/* Thanks to Alex Russell for example code */
/* Thanks to Gary Neal for example code */
-#include "dos_kb.h"
+/* working out the licencing~ */
+#include "src/lib/dos_kb.h"
// keyboard buffer
static byte key[NUM_SCANCODES]; // pressed
* Comment out the following #define if you don't want the testing main()
* to be included.
*/
-#define TESTING
+//#define TESTING
#define TESTING2
/*****************NEW KEYBOARD 09h ISR***********************/
-#ifndef _DOSLIB_KB_H_\r
-#define _DOSLIB_KB_H_\r
-#include "lib\lib_com.h"\r
-\r
-/* Maximum number of scan codes on keyboard controllers */\r
-#define NUM_SCANCODES 128\r
-\r
-#ifdef __cplusplus /* Functions must be declared C style */\r
-extern "C" {\r
-#endif\r
-void interrupt far newkb(void);\r
-//extern void interrupt (far *oldkb)(void);\r
-void setkb(int vq);\r
-int keyp(byte c);\r
-\r
-/* Define macro */\r
-//#define kepn(c) key[c & 0x7F]\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif/*_DOSLIB_KB_H_*/\r
+#ifndef _DOSLIB_KB_H_
+#define _DOSLIB_KB_H_
+#include "src/lib/16_head.h"
+
+/* Maximum number of scan codes on keyboard controllers */
+#define NUM_SCANCODES 128
+
+#ifdef __cplusplus /* Functions must be declared C style */
+extern "C" {
+#endif
+void interrupt far newkb(void);
+//extern void interrupt (far *oldkb)(void);
+void setkb(int vq);
+int keyp(byte c);
+
+/* Define macro */
+//#define kepn(c) key[c & 0x7F]
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/*_DOSLIB_KB_H_*/
--- /dev/null
+#!/usr/bin/perl
+my $top=`pwd`; chomp $top;
+
+sub vfat_rename($$) {
+ my $from,$to;
+ ($from,$to) = @_;
+
+ # uppercase DOS names with the vfat driver need some forceful convincing
+ # to actually make them lowercase
+ rename($from,"$to.xxx.xx");
+ rename("$to.xxx.xx",$to);
+}
+
+sub scan($) {
+ my $old = `pwd`; chomp $old;
+ my $cur = shift @_;
+ my @x;
+
+ print "scanning $cur\n";
+ chdir($cur) || die;
+
+ opendir(X,".") || return;
+ while (my $name = readdir(X)) {
+ next unless -f $name;
+ my $n = lc($name);
+ next if $n eq $name;
+ print "$name\n";
+ rename($name,$n) || die;
+ vfat_rename($name,$n);
+ }
+ closedir(X);
+
+ opendir(X,".") || return;
+ while (my $name = readdir(X)) {
+ next if $name =~ m/^\.+$/;
+ next if $name eq ".git";
+ next if $name eq ".GIT";
+ next unless -d $name;
+ my $n = lc($name);
+ next if $n eq $name;
+ print "$name\n";
+ rename($name,$n) || die;
+ vfat_rename($name,$n);
+ }
+ closedir(X);
+
+ opendir(X,".") || return;
+ while (my $name = readdir(X)) {
+ next if $name =~ m/^\.+$/;
+ next if $name eq ".git";
+ next if $name eq ".GIT";
+ next unless -d $name;
+ push(@x,$name);
+ }
+ closedir(X);
+ foreach my $name (@x) {
+ scan("$cur/$name");
+ }
+
+ chdir($old) || die;
+}
+
+scan($top);
#-zk0 = kanji support~
#-zkl = current codepage
-#MFLAGS=-mc# -zm
+DFLAGS=-DTARGET_MSDOS=16 -DMSDOS=1# -zm
CFLAGS=-zk0 -wo -x -mc# -zdp# -zp16 -zq
OFLAGS=-ot -ox -ob -oh -or# -om -ol -ol+
-FLAGS=-0 -d2 -lr $(OFLAGS) $(CFLAGS)
+FLAGS=-0 -d2 -lr $(OFLAGS) $(CFLAGS) $(DFLAGS)
SRC=src$(DIRSEP)
SRCLIB=$(SRC)lib$(DIRSEP)
JSMNLIB=$(SRCLIB)jsmn$(DIRSEP)
DOSLIB=$(SRCLIB)doslib$(DIRSEP)
WCPULIB=$(SRCLIB)wcpu$(DIRSEP)
-DOSLIBOBJ = adlib.$(OBJ) midi.$(OBJ) 8254.$(OBJ) 8259.$(OBJ) cpu.$(OBJ)
-16LIBOBJS = 16_in.$(OBJ) 16_mm.$(OBJ) wcpu.$(OBJ) 16_head.$(OBJ) scroll16.$(OBJ) 16_ca.$(OBJ) $(DOSLIBOBJ)
+DOSLIBEXMMOBJ = himemsys.$(OBJ) emm.$(OBJ)
+DOSLIBOBJ = adlib.$(OBJ) midi.$(OBJ) 8254.$(OBJ) 8259.$(OBJ) dos.$(OBJ) cpu.$(OBJ)
+16LIBOBJS = 16_in.$(OBJ) 16_mm.$(OBJ) wcpu.$(OBJ) 16_head.$(OBJ) scroll16.$(OBJ) 16_ca.$(OBJ)
GFXLIBOBJS = modex16.$(OBJ) bitmap.$(OBJ) planar.$(OBJ) 16text.$(OBJ)
-all: 16.exe test.exe pcxtest.exe test2.exe palettec.exe maptest.exe fmemtest.exe fonttest.exe exmmtest.exe fonttes0.exe fontgfx.exe sountest.exe miditest.exe
-#inputest.exe
+all: 16.exe test.exe pcxtest.exe test2.exe palettec.exe maptest.exe fmemtest.exe fonttest.exe exmmtest.exe fonttes0.exe fontgfx.exe sountest.exe miditest.exe testemm.exe tsthimem.exe inputest.exe
#
#executables
wcl $(FLAGS) fontgfx.$(OBJ) 16.lib
inputest.exe: inputest.$(OBJ) 16.lib
- wcl $(FLAGS) inputest.$(OBJ) 16.lib
+ wcl $(FLAGS) -D__DEBUG_InputMgr__=1 inputest.$(OBJ) 16.lib
sountest.exe: sountest.$(OBJ) 16.lib
wcl $(FLAGS) sountest.$(OBJ) 16.lib
miditest.exe: miditest.$(OBJ) 16.lib
wcl $(FLAGS) miditest.$(OBJ) 16.lib
+tsthimem.exe: tsthimem.$(OBJ) 16.lib
+ wcl $(FLAGS) tsthimem.$(OBJ) 16.lib
+
+testemm.exe: testemm.$(OBJ) 16.lib
+ wcl $(FLAGS) testemm.$(OBJ) 16.lib
+
pcxtest.exe: pcxtest.$(OBJ) gfx.lib
wcl $(FLAGS) pcxtest.$(OBJ) gfx.lib
miditest.$(OBJ): $(SRC)miditest.c
wcl $(FLAGS) -c $(SRC)miditest.c
+testemm.$(OBJ): $(SRC)testemm.c
+ wcl $(FLAGS) -c $(SRC)testemm.c
+
+tsthimem.$(OBJ): $(SRC)tsthimem.c
+ wcl $(FLAGS) -c $(SRC)tsthimem.c
+
exmmtest.$(OBJ): $(SRC)exmmtest.c
wcl $(FLAGS) -c $(SRC)exmmtest.c
#
#non executable objects libraries
#
-16.lib: $(16LIBOBJS) gfx.lib
- wlib -b 16.lib $(16LIBOBJS) gfx.lib
+16.lib: $(16LIBOBJS) gfx.lib doslib.lib
+ wlib -b 16.lib $(16LIBOBJS) gfx.lib doslib.lib
gfx.lib: $(GFXLIBOBJS)
wlib -b gfx.lib $(GFXLIBOBJS)
+doslib.lib: $(DOSLIBOBJ) $(DOSLIBEXMMOBJ)# $(SRCLIB)cpu.lib
+ wlib -b doslib.lib $(DOSLIBOBJ) $(DOSLIBEXMMOBJ)# $(SRCLIB)cpu.lib
+
modex16.$(OBJ): $(SRCLIB)modex16.h $(SRCLIB)modex16.c
wcl $(FLAGS) -c $(SRCLIB)modex16.c
midi.$(OBJ): $(SRCLIB)midi.h $(SRCLIB)midi.c
wcl $(FLAGS) -c $(SRCLIB)midi.c
+#
+# doslib stuff
+#
adlib.$(OBJ): $(DOSLIB)adlib.h $(DOSLIB)adlib.c
wcl $(FLAGS) -c $(DOSLIB)adlib.c
8259.$(OBJ): $(DOSLIB)8259.h $(DOSLIB)8259.c
wcl $(FLAGS) -c $(DOSLIB)8259.c
+dos.$(OBJ): $(DOSLIB)dos.h $(DOSLIB)dos.c
+ wcl $(FLAGS) -c $(DOSLIB)dos.c
+
cpu.$(OBJ): $(DOSLIB)cpu.h $(DOSLIB)cpu.c
wcl $(FLAGS) -c $(DOSLIB)cpu.c
-#dos.$(OBJ): $(DOSLIB)dos.h $(DOSLIB)dos.c
-# wcl $(FLAGS) -c $(DOSLIB)dos.c
+himemsys.$(OBJ): $(DOSLIB)himemsys.h $(DOSLIB)himemsys.c
+ wcl $(FLAGS) -c $(DOSLIB)himemsys.c
+
+emm.$(OBJ): $(DOSLIB)emm.h $(DOSLIB)emm.c
+ wcl $(FLAGS) -c $(DOSLIB)emm.c
+
+# end
16_head.$(OBJ): $(SRCLIB)16_head.h $(SRCLIB)16_head.c
wcl $(FLAGS) -c $(SRCLIB)16_head.c
\r
#ifdef __DEBUG_InputMgr__\r
#define TESTKEYIN\r
-#define TESTCONTROLNOISY\r
+//#define TESTCONTROLNOISY\r
#endif\r
\r
#define KeyInt 9 // The keyboard ISR number\r
+++ /dev/null
-/* Thanks to Alex Russell for example code */
-/* Thanks to Gary Neal for example code */
-/* working out the licencing~ */
-#include "src/lib/dos_kb.h"
-
-// keyboard buffer
-static byte key[NUM_SCANCODES]; // pressed
-static byte kea[NUM_SCANCODES]; // released
-
-#ifdef __cplusplus /* Function must be declared C style */
-extern "C" {
-#endif
-static void interrupt (far *oldkb)(void) = NULL; /* BIOS keyboard handler */
-#ifdef __cplusplus
-}
-#endif
-
-/*
- * Comment out the following #define if you don't want the testing main()
- * to be included.
- */
-//#define TESTING
-#define TESTING2
-
-/*****************NEW KEYBOARD 09h ISR***********************/
-void interrupt newkb(void){
- byte kee;
- register char qx;
-
- kee = inp(0x60); /* Read the keyboard scan code */
-
- /* Clear keyboard controller on XT machines */
- qx = inp(0x61); /* Get keyboard control register */
- qx |= 0x82;
- outp(0x61, qx); /* Toggle acknowledge bit high */
- qx &= 0x7F;
- outp(0x61, qx); /* Toggle acknowledge bit low */
-
- /* Interpret the scan code and set our flags */
- #ifdef TESTING2
- //printf("%d[%d]\n",kee,key[kee]);
- printf("\0"); // bug
- #endif
- if(kee & 0x80)
- key[kee & 0x7F] = 0; // a key is released
- else
- key[kee] = kea[kee] = 1; // a key is pressed
-
- /* Acknowledge the interrupt to the programmable interrupt controller */
- outp(0x20, 0x20); /* Signal non specific end of interrupt */
-}
-
-/* ---------------------- init_keyboard() ---------------- April 17,1993 */
-/* restore the bios keyboard handler */
-/* ---------------------- deinit_keyboard() -------------- April 17,1993 */
-void setkb(int vq){
- int i; /* Index variable */
- if(!vq){ // deinitiation
- /* Abort if our function pointer has no valid address */
- if(oldkb == NULL) return;
- /* Set address in our function pointer in interrupt vector table */
- _dos_setvect(9, oldkb);
- /* Reset our function pointer to contain no valid address */
- oldkb = NULL;
- #ifdef TESTING
- /* Print the key heap */
- printf("\n");
- for(i=0; i<NUM_SCANCODES; i++){
- if(i==NUM_SCANCODES/2) printf("================================\n");
- printf("%03d[%d][%d]",i+1,key[i],kea[i]);
- if(key[i]==1)printf("====");
- printf(",\n");
- }
- #endif
- }else if(vq == 1){ // initiation
- byte far *lock_key;
-
- /* Abort if our function pointer has a valid address. */
- if(oldkb != NULL) return;
-
- /* Clear the keyboard buttons state arrays */
- for(i = 0; i < NUM_SCANCODES; i++)
- key[i] = kea[i] = 0;
-
- /* save old BIOS key board handler */
- oldkb = _dos_getvect(9);
-
- // turn off num-lock via BIOS
- lock_key = MK_FP(0x040, 0x017); // Pointing to the address of the bios shift state keys
- *lock_key&=(~(16 | 32 | 64)); // toggle off the locks by changing the values of the 4th, 5th, and 6th bits of the address byte of 0040:0017
- oldkb(); // call BIOS keyhandler to change keyboard lights
-
- /* setup our own handler */
- _dos_setvect(9, newkb);
- }
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
- * keyp *
- * *
- * Returns the status of the key requested. *
- * The status is 1 if the key is pressed or has been pressed since the *
- * last call to this function for that particular key. *
-\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-int keyp(byte c){
- register char retVal;
-
- /* Key value in range of keyboard keys available */
- c &= 0x7F;
-
- /* Get the status of the key requested */
- retVal = key[c] | kea[c];
-
- /* Reset the was pressed status for the requested key */
- kea[c] = 0;
-
- /* Return the requested key's state */
- return retVal;
-}
-
-
-/*
- * The library testing routines follows below.
- */
-
-#ifdef TESTING
-
-/*
- * Library test (program) entry point.
- */
-
-void main(void)
-{
- byte q;
- setkb(1);
- while(!keyp(1))
- {
- keyp(q);
- }
- setkb(0);
-}
-
-#endif
+++ /dev/null
-#ifndef _DOSLIB_KB_H_
-#define _DOSLIB_KB_H_
-#include "src/lib/16_head.h"
-
-/* Maximum number of scan codes on keyboard controllers */
-#define NUM_SCANCODES 128
-
-#ifdef __cplusplus /* Functions must be declared C style */
-extern "C" {
-#endif
-void interrupt far newkb(void);
-//extern void interrupt (far *oldkb)(void);
-void setkb(int vq);
-int keyp(byte c);
-
-/* Define macro */
-//#define kepn(c) key[c & 0x7F]
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif/*_DOSLIB_KB_H_*/
*
* Compiles for intended target environments:
* - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
+
#ifndef __HW_8254_8254_H
#define __HW_8254_8254_H
*
* Compiles for intended target environments:
* - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
+
#ifndef __HW_8259_8259_H
#define __HW_8259_8259_H
*
* Compiles for intended target environments:
* - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-#include "src/lib/doslib/cpu.h"
+
+//#include "src/lib/doslib/cpu.h"
#include "src/lib/doslib/8254.h" /* 8254 timer */
#include <stdint.h>
/* NTS: I have a Creative CT1350B card where we really do have to wait at least
* 33us per I/O access, because the OPL2 chip on it really is that slow.
- *
+ *
* Peior to this fix, the adlib code would often fail on a real CT1350B
* (unless run just after the Sound Blaster test program) and even if it
* did run, only about 1/3rd of the voices would work. Upping the delay
#include <dos.h>
#include "src/lib/doslib/cpu.h"
-//#include <hw/dos/dos.h>
/* DEBUG: Flush out calls that aren't there */
#ifdef TARGET_OS2
#endif
}
+int cpu_basic_probe()
+{
+ __asm
+ {
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+ push bp
+// BUGFIX: Calling near a function that returns far is like taking a long walk off a short pier
+// push cs
+
+// call cpu_basic_probe_f_
+
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ //retnative
+ }
+ return;
+}
#include <stdint.h>
#include <dos.h>
+#include "src/lib/16_head.h"
#if !defined(FAR)
# if defined(TARGET_WINDOWS)
void cpu_wrmsr(const uint32_t idx,const uint64_t val);
#endif
+int cpu_basic_probe();
+
#endif /* __HW_CPU_CPU_H */
*/
#ifdef TARGET_WINDOWS
-# include <windows.h>
+//# include <windows.h>
#endif
#include <stdio.h>
#define __HW_DOS_DOS_H
#include "src/lib/doslib/cpu.h"
+//#include "src/lib/16_head.h"
#include <stdint.h>
#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ lib REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-/* biosext.c
- *
- * DOS library for carrying out extended memory copy using BIOS INT 15h
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/biosext.h>
-
-#if TARGET_MSDOS == 16
-int bios_extcopy_sub(uint32_t dst,uint32_t src,unsigned long copy/* WARNING: must be multiple of 2, and <= 64KB */) {
- /* WARNING: There are better ways to access extended memory.
- * But we have this function for those cases where the better ways are
- * unavailable. Such as:
- *
- * a) we're running on a 286, where 32-bit 386 instructions
- * are unavailable to carry out flat real mode tricks
- *
- * b) we're running under Windows, whos DOS VM subsystem
- * is intolerant of flat real mode and generally demands that
- * we switch into DPMI protected mode to even access it
- *
- * c) we're running under some other virtual 8086 mode system
- * that forbids flat realmode like hacks (such as EMM386.EXE)
- *
- * There is also another possible danger: Some BIOS implementations emulate 286 behavior (even on
- * 386, 486, Pentium, and beyond) by masking off or ignoring the upper 8 bits of the base (24-31).
- * On these systems, accessing memory at or above the 16MB mark with the BIOS is impossible. But on
- * these same systems, you have 32-bit protected mode and the option to use flat real mode anyway,
- * so it doesn't really matter. On a 286 class system where you must use this function, the CPU is
- * physically incapable of signalling more than 16MB (24 bit addressing) so again, that doesn't
- * matter.
- *
- * TODO: I need to test this theory: If a BIOS ignores address bits 24-31, but we're running under
- * Windows (and therefore the Windows kernel's emulation of the BIOS call), does the address
- * masking limitation still apply? */
- /* The following comment is a list of all system & BIOS combinations this code has been tested under.
- *
- * BIOS/System/Environment Works? At or above 16MB boundary?
- * ---------------------------------------------------------------------
- * DOSBox 0.74 YES w/ BUGS YES
- * Microsoft Virtual PC 2007 YES YES
- * Oracle VirtualBox 4.0.4 YES YES
- * QEMU YES YES
- * DOSBox 0.74 +
- * Microsoft Windows 3.0
- * Real mode YES YES
- * Standard mode YES YES
- * 386 Enhanced mode YES NO
- * Microsoft Windows 3.1
- * Standard mode YES YES
- * 386 Enhanced mode YES YES
- * Microsoft Windows 3.11
- * Standard mode YES YES
- * 386 Enhanced mode YES YES
- * QEMU +
- * Microsoft Windows 95 (4.00.950)
- * Normal YES YES
- * Safe mode YES YES
- * Microsoft Windows 98 (4.10.1998)
- * Normal YES YES
- * Safe mode YES YES
- * Microsoft Windows ME (4.90.3000)
- * Normal YES YES
- * Safe mode YES YES
- * Microsoft Windows 2000 Professional (5.00.2195)
- * Normal YES NO
- * Microsoft Windows XP Professional (5.1.2600)
- * Normal YES NO
- * Microsoft Windows XP Professional SP2 (5.1.2600)
- * Normal YES NO
- * Microsoft Windows Vista Ultimate
- * Normal YES NO
- *
- * Bugs:
- * * DOSBox 0.74: DOSBox directly emulates the INT BIOS function. Unfortunately it does it wrong,
- * apparently getting bytes 7 and 8 of the descriptor backwards. If this code always
- * fills in the flags and limit(16:19) bits, then it causes DOSBox to access addresses
- * in the 0x8F000000....0x8FFFFFFF range (because the flags+limit byte is usually 0x8F
- * on 386 systems and DOSBox is mistreating it as bits 24-31 of the address).
- *
- * Unfortunately this bug means that any program relying on this function exclusively
- * will be unable to properly target memory above 16MB when running under DOSBox. However,
- * DOSBox also fails to enforce segment limits in real mode (emulating a CPU that is
- * perpetually in "flat real mode") which means that you are free to abuse 386+ style
- * 32-bit addressing, therefore, you should be using flat real mode instead of this function.
- *
- * It's possible the DOSBox developers missed the bug because they only tested it against
- * ancient DOS games written in the 286 era that habitually left bytes 7-8 zero anyway.
- * Who knows?
- */
- union REGS regs;
- struct SREGS sregs;
- uint8_t tmp[0x40]; /* the global descriptor table */
-
- memset(tmp,0,sizeof(tmp));
-
- *((uint16_t*)(tmp+0x10)) = 0xFFFF; /* limit (source) */
- *((uint32_t*)(tmp+0x12)) = 0x93000000UL + (src & 0xFFFFFFUL); /* base and access byte (source) */
- if (src >= 0x1000000UL/*>= 16MB*/) /* see DOSBox bug report listed above to understand why I am filling in bytes 7-8 this way */
- *((uint16_t*)(tmp+0x16)) = ((src >> 16) & 0xFF00UL) + 0x8FUL; /* (386) base bits 24-31, flags, limit bits 16-19 */
-
- *((uint16_t*)(tmp+0x18)) = 0xFFFF; /* limit (dest) */
- *((uint32_t*)(tmp+0x1A)) = 0x93000000UL + (dst & 0xFFFFFFUL); /* base and access byte (dest) */
- if (dst >= 0x1000000UL/*>= 16MB*/) /* see DOSBox bug report listed above to understand why I am filling in bytes 7-8 this way */
- *((uint16_t*)(tmp+0x1E)) = ((dst >> 16) & 0xFF00UL) + 0x8FUL; /* (386) base bits 24-31, flags, limit bits 16-19 */
-
- regs.h.ah = 0x87;
- regs.w.cx = (unsigned int)(copy >> 1UL); /* number of WORDS, not BYTES */
- regs.w.si = FP_OFF((unsigned char*)tmp);
- sregs.es = FP_SEG((unsigned char*)tmp);
- int86x(0x15,®s,®s,&sregs); /* now call the BIOS */
- return (regs.h.ah == 0) ? 0 : -1;
-}
-
-int bios_extcopy(uint32_t dst,uint32_t src,unsigned long copy) {
- if (copy == 0UL) return 0;
- /* if we're on anything less than a 286, then this function is meaningless--there is no extended memory */
- if (cpu_basic_level == (signed char)0xFF) cpu_probe();
- if (cpu_basic_level < 2) return -1;
- /* carry out the copy operation */
- while (copy >= 0x10000UL) {
- if (bios_extcopy_sub(dst,src,0x10000UL))
- return -1;
-
- copy -= 0x10000UL;
- dst += 0x10000UL;
- src += 0x10000UL;
- }
- if (copy >= 2UL) {
- if (bios_extcopy_sub(dst,src,copy & 0xFFFFFFFEUL))
- return -1;
-
- dst += copy & 0xFFFFFFFEUL;
- src += copy & 0xFFFFFFFEUL;
- copy &= 1UL;
- }
- if (copy != 0UL) {
- unsigned char tmp[2];
- if (bios_extcopy_sub(ptr2phys(tmp),src,2)) return -1;
- *((unsigned char far*)MK_FP(dst>>4,dst&0xF)) = tmp[0];
- }
-
- return 0;
-}
-#endif
-
+++ /dev/null
-/* biosext.h
- *
- * DOS library for carrying out extended memory copy using BIOS INT 15h
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdint.h>
-
-#if TARGET_MSDOS == 16
-int bios_extcopy(uint32_t dst,uint32_t src,unsigned long copy);
-#endif
-
+++ /dev/null
-/* biosmem.c
- *
- * Various BIOS INT 15h extended memory query functions.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/biosmem.h>
-
-#if TARGET_MSDOS == 16
-int biosmem_size_E820(unsigned long *index,struct bios_E820 *nfo) {
- if (cpu_basic_level < 3) /* requires a 386 or higher. If the programmer didn't call CPU detection that's OK he gets the crash he deserves */
- return 0;
-
- return _biosmem_size_E820_3(index,nfo);
-}
-
-int biosmem_size_88(unsigned int *sz) {
- union REGS regs={0};
-
- regs.x.ax = 0x8800;
- int86(0x15,®s,®s);
- if (regs.x.cflag & 1) /* CF=1 */
- return 0;
- if (regs.x.ax == 0)
- return 0;
- if (regs.h.ah == 0x86 || regs.h.ah == 0x80)
- return 0;
-
- *sz = regs.x.ax;
- return 1;
-}
-
-int biosmem_size_E801(unsigned int *low,unsigned int *high) {
- union REGS regs={0};
-
- regs.x.ax = 0xE801;
- int86(0x15,®s,®s);
- if (regs.x.cflag & 1) { /* CF=1 */
- return 0;
- }
-
- if (regs.x.ax == 0)
- regs.x.ax = regs.x.cx;
- else if (regs.x.cx == 0)
- regs.x.cx = regs.x.ax;
-
- if (regs.x.bx == 0)
- regs.x.bx = regs.x.dx;
- else if (regs.x.dx == 0)
- regs.x.dx = regs.x.bx;
-
- if (regs.x.ax != regs.x.cx || regs.x.bx != regs.x.dx)
- return 0;
-
- *low = regs.x.ax;
- *high = regs.x.bx;
- return 1;
-}
-#endif
-
+++ /dev/null
-/* biosmem.h
- *
- * Various BIOS INT 15h extended memory query functions.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#pragma pack(push,1)
-struct bios_E820 {
- uint64_t base,length;
- uint32_t type;
- uint32_t ext_attributes;
-};
-#pragma pack(pop)
-
-/* INT 15H AX=E820 types */
-enum {
- BIOS_E820_NONE=0,
- BIOS_E820_RAM,
- BIOS_E820_RESERVED,
- BIOS_E820_ACPI_RECLAIMABLE,
- BIOS_E820_ACPI_NVS,
- BIOS_E820_FAULTY
-};
-
-int _biosmem_size_E820_3(unsigned long *index,struct bios_E820 *nfo);
-int biosmem_size_E820(unsigned long *index,struct bios_E820 *nfo);
-int biosmem_size_E801(unsigned int *low,unsigned int *high);
-int biosmem_size_88(unsigned int *sz);
-
+++ /dev/null
-/* biosmem3.c
- *
- * Support functions for calling BIOS INT 15h E820 to query extended memory layout
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/biosmem.h>
-
-#if TARGET_MSDOS == 16
-int _biosmem_size_E820_3(unsigned long *index,struct bios_E820 *nfo) {
- unsigned long idx = *index;
- unsigned long retv = 0;
- unsigned int len = 0;
-
- memset(nfo,0,sizeof(*nfo));
-
- __asm {
- push es
- mov eax,0xE820
- mov ebx,idx
- mov ecx,24
- mov edx,0x534D4150
-#if defined(__LARGE__) || defined(__COMPACT__)
- mov di,word ptr [nfo+2] ; segment portion of far pointer
- mov es,di
-#endif
- mov di,word ptr [nfo] ; offset of pointer
- int 15h
- pop es
- jc noway
- mov retv,eax
- mov idx,ebx
- mov len,cx ; Watcom doesn't know what "CL" is? It's only the lower 8 bits of CX/ECX Duhhhh...
-noway:
- }
-
- if (retv == 0x534D4150UL) {
- *index = idx;
- return len & 0xFF;
- }
-
- return 0;
-}
-#endif
-
+++ /dev/null
-
-# TODO: OS/2 target: What can we #define to tell the header files which OS/2
-# environment we're doing? (Command prompt app. vs Presentation Manager app vs.
-# "fullscreen" app.)
-
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NOW_BUILDING = HW_DOS_LIB
-
-OBJS = $(SUBDIR)$(HPS)dos.obj $(SUBDIR)$(HPS)dosxio.obj $(SUBDIR)$(HPS)biosext.obj $(SUBDIR)$(HPS)himemsys.obj $(SUBDIR)$(HPS)emm.obj $(SUBDIR)$(HPS)dosbox.obj $(SUBDIR)$(HPS)biosmem.obj $(SUBDIR)$(HPS)biosmem3.obj $(SUBDIR)$(HPS)dosasm.obj $(SUBDIR)$(HPS)tgusmega.obj $(SUBDIR)$(HPS)tgussbos.obj $(SUBDIR)$(HPS)tgusumid.obj $(SUBDIR)$(HPS)dosntvdm.obj $(SUBDIR)$(HPS)doswin.obj $(SUBDIR)$(HPS)dos_lol.obj $(SUBDIR)$(HPS)dossmdrv.obj $(SUBDIR)$(HPS)dosvbox.obj $(SUBDIR)$(HPS)dosmapal.obj $(SUBDIR)$(HPS)dosflavr.obj $(SUBDIR)$(HPS)dos9xvm.obj $(SUBDIR)$(HPS)dos_nmi.obj $(SUBDIR)$(HPS)win32lrd.obj $(SUBDIR)$(HPS)win3216t.obj $(SUBDIR)$(HPS)win16vec.obj $(SUBDIR)$(HPS)dpmiexcp.obj $(SUBDIR)$(HPS)dosvcpi.obj $(SUBDIR)$(HPS)ddpmilin.obj $(SUBDIR)$(HPS)ddpmiphy.obj $(SUBDIR)$(HPS)ddpmidos.obj $(SUBDIR)$(HPS)ddpmidsc.obj $(SUBDIR)$(HPS)dpmirmcl.obj $(SUBDIR)$(HPS)dos_mcb.obj $(SUBDIR)$(HPS)dospsp.obj $(SUBDIR)$(HPS)dosdev.obj $(SUBDIR)$(HPS)dos_ltp.obj $(SUBDIR)$(HPS)dosdpmi.obj
-!ifdef TARGET_WINDOWS
-OBJS += $(SUBDIR)$(HPS)winfcon.obj
-!endif
-
-#HW_DOS_LIB = $(SUBDIR)$(HPS)dos.lib
-
-!ifndef TARGET_OS2
-NTVDMLIB_LIB = ..$(HPS)..$(HPS)windows$(HPS)ntvdm$(HPS)$(SUBDIR)$(HPS)ntvdmlib.lib
-NTVDMLIB_LIB_WLINK_LIBRARIES = library $(NTVDMLIB_LIB)
-NTVDMVDD_LIB = ..$(HPS)..$(HPS)windows$(HPS)ntvdm$(HPS)$(SUBDIR)$(HPS)ntvdmvdd.lib
-NTVDMVDD_LIB_WLINK_LIBRARIES = library $(NTVDMVDD_LIB)
-!endif
-
-!ifndef TARGET_WINDOWS
-! ifndef TARGET_OS2
-LOL_EXE = $(SUBDIR)$(HPS)lol.exe
-TESTSMRT_EXE =$(SUBDIR)$(HPS)testsmrt.exe
-NTASTRM_EXE = $(SUBDIR)$(HPS)ntastrm.exe
-! ifeq TARGET_MSDOS 16
-TESTDPMI_EXE =$(SUBDIR)$(HPS)testdpmi.exe
-! endif
-TSTHIMEM_EXE =$(SUBDIR)$(HPS)tsthimem.exe
-TESTBEXT_EXE =$(SUBDIR)$(HPS)testbext.exe
-TESTEMM_EXE = $(SUBDIR)$(HPS)testemm.exe
-TSTBIOM_EXE = $(SUBDIR)$(HPS)tstbiom.exe
-TSTLP_EXE = $(SUBDIR)$(HPS)tstlp.exe
-! endif
-!endif
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-CR3_EXE = $(SUBDIR)$(HPS)cr3.exe
-
-!ifndef TARGET_OS2
-# if targeting Win32, then build the DOS NT assistant DLL that DOS versions
-# can use to better interact with Windows NT/2000/XP. Else, copy the winnt
-# DLL into the DOS build dir. The DLL is given the .VDD extension to clarify
-# that it is intented for use as a VDD for NTVDM.EXE (or as a Win32 extension
-# to the Win16 builds).
-DOSNTAST_VDD = $(SUBDIR)$(HPS)dosntast.vdd
-!endif
-
-!ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 32
-! ifeq TARGET_WINDOWS 40
-DOSNTAST_VDD_BUILD=1
-! endif
-! endif
-!endif
-
-$(HW_DOS_LIB): $(OBJS)
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos.obj -+$(SUBDIR)$(HPS)biosext.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)himemsys.obj -+$(SUBDIR)$(HPS)emm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dosbox.obj -+$(SUBDIR)$(HPS)biosmem.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)biosmem3.obj -+$(SUBDIR)$(HPS)dosasm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)tgusmega.obj -+$(SUBDIR)$(HPS)tgussbos.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)tgusumid.obj -+$(SUBDIR)$(HPS)dosntvdm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)doswin.obj -+$(SUBDIR)$(HPS)dosxio.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos_lol.obj -+$(SUBDIR)$(HPS)dossmdrv.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dosvbox.obj -+$(SUBDIR)$(HPS)dosmapal.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dosflavr.obj -+$(SUBDIR)$(HPS)dos9xvm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos_nmi.obj -+$(SUBDIR)$(HPS)win32lrd.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)win3216t.obj -+$(SUBDIR)$(HPS)win16vec.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dpmiexcp.obj -+$(SUBDIR)$(HPS)dosvcpi.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)ddpmilin.obj -+$(SUBDIR)$(HPS)ddpmiphy.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)ddpmidos.obj -+$(SUBDIR)$(HPS)ddpmidsc.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dpmirmcl.obj -+$(SUBDIR)$(HPS)dos_mcb.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dospsp.obj -+$(SUBDIR)$(HPS)dosdev.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos_ltp.obj -+$(SUBDIR)$(HPS)dosdpmi.obj
-!ifdef TARGET_WINDOWS
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)winfcon.obj
-!endif
-
-# some components need a 386 in real mode
-$(SUBDIR)$(HPS)biosmem3.obj: biosmem3.c
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS386) $[@
- @$(CC) @tmp.cmd
-
-$(SUBDIR)$(HPS)dosntast.obj: dosntast.c
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS_CON) $[@
- @$(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-exe: $(TESTSMRT_EXE) $(NTASTRM_EXE) $(TEST_EXE) $(CR3_EXE) $(TESTBEXT_EXE) $(TSTHIMEM_EXE) $(TESTEMM_EXE) $(TSTBIOM_EXE) $(LOL_EXE) $(TSTLP_EXE) $(TESTDPMI_EXE) .symbolic
-
-lib: $(DOSNTAST_VDD) $(HW_DOS_LIB) .symbolic
-
-!ifdef TESTSMRT_EXE
-$(TESTSMRT_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testsmrt.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)testsmrt.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTSMRT_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef NTASTRM_EXE
-$(NTASTRM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)ntastrm.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)ntastrm.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(NTASTRM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef DOSNTAST_VDD_BUILD
-$(DOSNTAST_VDD): $(HW_DOS_LIB) $(HW_CPU_LIB) $(NTVDMLIB_LIB) $(NTVDMVDD_LIB) $(SUBDIR)$(HPS)dosntast.obj
- %write tmp.cmd option quiet system $(WLINK_DLL_SYSTEM) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(NTVDMVDD_LIB_WLINK_LIBRARIES) $(NTVDMLIB_LIB_WLINK_LIBRARIES) library winmm.lib file $(SUBDIR)$(HPS)dosntast.obj
- %write tmp.cmd option modname='DOSNTAST'
-! ifeq TARGET_MSDOS 32
- %write tmp.cmd option nostdcall
-! endif
-# explanation: if we use the IMPLIB option, Watcom will go off and make an import library that
-# cases all references to refer to HELLDLD1.DLL within the NE image, which Windows does NOT like.
-# we need to ensure the DLL name is encoded by itself without a .DLL extension which is more
-# compatible with Windows and it's internal functions.
-#
-# Frankly I'm surprised that Watcom has this bug considering how long it's been around... Kind of disappointed really
-# %write tmp.cmd option impfile=$(SUBDIR)$(HPS)DOSNTAST.LCF
- %write tmp.cmd name $(DOSNTAST_VDD)
- @wlink @tmp.cmd
-!else
-# copy from Win32 dir. Build if necessary
-winnt$(HPS)dosntast.vdd: dosntast.c
- @$(MAKECMD) build lib winnt
-
-! ifdef DOSNTAST_VDD
-$(DOSNTAST_VDD): winnt$(HPS)dosntast.vdd
- @$(COPY) winnt$(HPS)dosntast.vdd $(DOSNTAST_VDD)
-! endif
-!endif
-
-!ifdef LOL_EXE
-$(LOL_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)lol.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)lol.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(LOL_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TESTDPMI_EXE
-$(TESTDPMI_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testdpmi.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)testdpmi.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTDPMI_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TEST_EXE
-$(TEST_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)test.obj $(HW_DOS_LIB_WLINK_LIBRARIES)
- %write tmp.cmd option map=$(SUBDIR)$(HPS)test.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(TEST_EXE)
- @wbind $(TEST_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(TEST_EXE)
-! endif
-!endif
-
-!ifdef CR3_EXE
-$(CR3_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)cr3.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)cr3.obj $(HW_DOS_LIB_WLINK_LIBRARIES)
- %write tmp.cmd option map=$(SUBDIR)$(HPS)cr3.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(CR3_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(CR3_EXE)
- @wbind $(CR3_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(CR3_EXE)
-! endif
-!endif
-
-!ifdef TSTLP_EXE
-$(TSTLP_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tstlp.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)tstlp.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TSTLP_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TESTBEXT_EXE
-$(TESTBEXT_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testbext.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)testbext.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTBEXT_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TSTHIMEM_EXE
-$(TSTHIMEM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tsthimem.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)tsthimem.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TSTHIMEM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TESTEMM_EXE
-$(TESTEMM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testemm.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)testemm.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTEMM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TSTBIOM_EXE
-$(TSTBIOM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tstbiom.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)tstbiom.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TSTBIOM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_DOS_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* cr3.c
- *
- * Test program: Attempt to read the CR3 register, see what happens
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- uint32_t v_cr3=0;
-
- probe_dos();
-
- __asm {
- .386p
- int 3
- xor eax,eax
- mov eax,cr3
- mov v_cr3,eax
- }
-
- printf("CR3=0x%08lX\n",(unsigned long)v_cr3);
- return 0;
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32
-void *dpmi_alloc_dos(unsigned long len,uint16_t *selector) {
- unsigned short rm=0,pm=0,fail=0;
-
- /* convert len to paragraphs */
- len = (len + 15) >> 4UL;
- if (len >= 0xFF00UL) return NULL;
-
- __asm {
- mov bx,WORD PTR len
- mov ax,0x100
- int 0x31
-
- mov rm,ax
- mov pm,dx
- sbb ax,ax
- mov fail,ax
- }
-
- if (fail) return NULL;
-
- *selector = pm;
- return (void*)((unsigned long)rm << 4UL);
-}
-
-void dpmi_free_dos(uint16_t selector) {
- __asm {
- mov ax,0x101
- mov dx,selector
- int 0x31
- }
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* TODO: Windows 3.1/95/98/ME have a DPMI server underneath.
- * It would be neato at some point if these functions were
- * available for use from Windows 3.1 Win16/Win32, and
- * Windows 95/98/ME Win32 */
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void dpmi_free_descriptor(uint16_t d) {
- union REGS regs = {0};
- regs.w.ax = 0x0001; /* DPMI free descriptor */
- regs.w.bx = d;
- int386(0x31,®s,®s);
-}
-
-uint16_t dpmi_alloc_descriptors(uint16_t c) {
- union REGS regs = {0};
- regs.w.ax = 0x0000; /* allocate descriptor */
- regs.w.cx = 1; /* just one */
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return regs.w.ax;
-}
-
-unsigned int dpmi_set_segment_base(uint16_t sel,uint32_t base) {
- union REGS regs = {0};
- regs.w.ax = 0x0007; /* set segment base */
- regs.w.bx = sel;
- regs.w.cx = base >> 16UL;
- regs.w.dx = base;
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return 1;
-}
-
-unsigned int dpmi_set_segment_limit(uint16_t sel,uint32_t limit) {
- union REGS regs = {0};
- regs.w.ax = 0x0008; /* set segment limit */
- regs.w.bx = sel;
- regs.w.cx = limit >> 16UL;
- regs.w.dx = limit;
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return 1;
-}
-
-unsigned int dpmi_set_segment_access(uint16_t sel,uint16_t access) {
- union REGS regs = {0};
- unsigned char c=0;
-
- /* the DPL/CPL value we give to the DPMI function below must match our privilege level, so
- * get that value from our own selector */
- __asm {
- push eax
- movzx eax,sel
- and al,3
- mov c,al
- pop eax
- }
-
- regs.w.ax = 0x0009; /* set segment access rights */
- regs.w.bx = sel;
- regs.w.cx = (access & 0xFF9F) | (c << 5); /* readable, code, CPL=same, present=1, 16-bit byte granular */
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return 1;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32
-int dpmi_linear_lock(uint32_t lin,uint32_t size) {
- int retv = 0;
-
- __asm {
- mov ax,0x0600
- mov cx,word ptr lin
- mov bx,word ptr lin+2
- mov di,word ptr size
- mov si,word ptr size+2
- int 0x31
- jc endf
- mov retv,1
-endf:
- }
-
- return retv;
-}
-
-int dpmi_linear_unlock(uint32_t lin,uint32_t size) {
- int retv = 0;
-
- __asm {
- mov ax,0x0601
- mov cx,word ptr lin
- mov bx,word ptr lin+2
- mov di,word ptr size
- mov si,word ptr size+2
- int 0x31
- jc endf
- mov retv,1
-endf:
- }
-
- return retv;
-}
-
-void *dpmi_linear_alloc(uint32_t try_lin,uint32_t size,uint32_t flags,uint32_t *handle) {
- void *retv = 0;
- uint32_t han = 0;
-
- __asm {
- mov ax,0x0504
- mov ebx,try_lin
- mov ecx,size
- mov edx,flags
- int 0x31
- jc endf
- mov retv,ebx
- mov han,esi
-endf:
- }
-
- if (retv != NULL && handle != NULL)
- *handle = han;
-
- return retv;
-}
-
-int dpmi_linear_free(uint32_t handle) {
- int retv = 0;
-
- __asm {
- mov ax,0x0502
- mov di,word ptr handle
- mov si,word ptr handle+2
- int 0x31
- jc endf
- mov retv,1
-endf:
- }
-
- return retv;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32
-void *dpmi_phys_addr_map(uint32_t phys,uint32_t size) {
- uint32_t retv = 0;
-
- __asm {
- mov ax,0x0800
- mov cx,word ptr phys
- mov bx,word ptr phys+2
- mov di,word ptr size
- mov si,word ptr size+2
- int 0x31
- jc endf
- mov word ptr retv,cx
- mov word ptr retv+2,bx
-endf:
- }
-
- return (void*)retv;
-}
-
-void dpmi_phys_addr_free(void *base) {
- __asm {
- mov ax,0x0801
- mov cx,word ptr base
- mov bx,word ptr base+2
- int 0x31
- }
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define int386 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-struct lib_dos_options lib_dos_option={0};
-
-/* DOS version info */
-uint8_t dos_flavor = 0;
-uint16_t dos_version = 0;
-uint32_t freedos_kernel_version = 0;
-const char *dos_version_method = NULL;
-
-#if TARGET_MSDOS == 32
-char *freedos_kernel_version_str = NULL;
-#else
-char far *freedos_kernel_version_str = NULL;
-#endif
-
-void probe_dos() {
-#if TARGET_MSDOS == 32 && 0
- assert(sizeof(struct dpmi_realmode_call) == 0x32);
- assert(offsetof(struct dpmi_realmode_call,ss) == 0x30);
- assert(offsetof(struct dpmi_realmode_call,cs) == 0x2C);
-#endif
-
- if (dos_version == 0) {
-#ifdef TARGET_WINDOWS
-# if TARGET_MSDOS == 32
-# ifdef WIN386
-/* =================== Windows 3.0/3.1 Win386 ================= */
- DWORD raw = GetVersion(); /* NTS: The Win16 version does not tell us if we're running under Windows NT */
-
- dos_version_method = "GetVersion";
- dos_version = (((raw >> 24UL) & 0xFFUL) << 8UL) | (((raw >> 16UL) & 0xFFUL) << 0UL);
-
- /* Windows NT/2000/XP NTVDM.EXE lies to us, reporting Windows 95 numbers and MS-DOS 5.0 */
- if (dos_version == 0x500) {
- uint16_t x = 0;
-
- /* Sorry Microsoft, but you make it hard for us to detect and we have to break your OS to find the info we need */
- __asm {
- mov ax,0x3306
- mov bx,0
- int 21h
- jc err1
- mov x,bx
-err1:
- }
-
- if (x != 0 && x != 0x005) { /* Once pushed to reveal the true DOS version, NTVDM.EXE responds with v5.50 */
- dos_version = (x >> 8) | (x << 8);
- dos_version_method = "INT 21h AX=3306h/NTVDM.EXE";
- }
- }
-# else
-/* =================== Windows 32-bit ================== */
- DWORD raw;
- /* GetVersion() 32-bit doesn't return the DOS version at all. The upper WORD has build number instead. */
- /* Instead, use GetVersionEx() to detect system. If system is Windows 3.1 or 9x/ME we might be able
- * to get away with abusing the DPMI server deep within Windows to get what we want. Else, if it's
- * Windows NT, we simply assume v5.50 */
-
- /* assume v5.0 */
- dos_version = 0x500;
- dos_version_method = "Guessing";
-
- /* use the Win32 version of GetVersion() to determine what OS we're under */
- raw = GetVersion();
- if (raw & 0x80000000UL) { /* Windows 9x/ME */
- /* Start by guessing the version number based on which version of Windows we're under */
- unsigned char major = raw & 0xFF,minor = (raw >> 8) & 0xFF,ok=0;
-
- dos_version_method = "Guessing by Windows version";
- if (major < 4) { /* Windows 3.1 Win32s */
- dos_version = 0x616; /* Assume MS-DOS 6.22, though it could be 6.20 or even 6.00 */
- }
- else if (major == 4) { /* Windows 95/98/ME */
- if (minor >= 90)
- dos_version = 0x800; /* Windows ME (8.00) */
- else if (minor >= 10)
- dos_version = 0x70A; /* Windows 98 (7.10) */
- else
- dos_version = 0x700; /* Windows 95 */
- }
-
- /* Try: Windows 9x/ME QT_Thunk hack to call down into the Win16 layer's version of GetVersion() */
- if (!ok && major == 4 && Win9xQT_ThunkInit()) {
- DWORD fptr,raw=0;
-
- fptr = GetProcAddress16(win9x_kernel_win16,"GETVERSION");
- if (fptr != 0) {
- dos_version_method = "Read from Win16 GetVersion() [32->16 QT_Thunk]";
-
- {
- __asm {
- mov edx,fptr
- mov eax,dword ptr [QT_Thunk]
-
- ; QT_Thunk needs 0x40 byte of data storage at [EBP]
- ; give it some, right here on the stack
- push ebp
- mov ebp,esp
- sub esp,0x40
-
- call eax ; <- QT_Thunk
-
- ; release stack storage
- mov esp,ebp
- pop ebp
-
- ; take Win16 response in DX:AX translate to EAX
- shl edx,16
- and eax,0xFFFF
- or eax,edx
- mov raw,eax
- }
- }
-
- if (raw != 0) {
- dos_version = (((raw >> 24UL) & 0xFFUL) << 8UL) | (((raw >> 16UL) & 0xFFUL) << 0UL);
- ok = 1;
- }
- }
- }
- /* Tried: Windows 3.1 with Win32s. Microsoft Win32 documentation gleefully calls Dos3Call "obsolete",
- * yet inspection of the Win32s DLLs shows that W32SKRNL.DLL has a _Dos3Call@0 symbol in it
- * that acts just like the Win16 version, calling down into DOS, and most of the Win32s DLLs
- * rely on it quite heavily to implement Win32 functions (the GetSystemTime function for example
- * using it to call INT 21h AH=2Ah).
- *
- * Some old MSDN documentation I have has a list of INT 21h calls and corresponding Win32
- * functions to use. Again of course, they skip right over "Get MS-DOS version", no help there.
- *
- * Anyway, calling this function with AX=0x3306 or AH=0x30 yields no results. Apparently, Microsoft
- * implemented passing through file I/O, date/time, and code page conversions, yet never considered
- * people might use it for something like... asking DOS it's version number. Attempting to make
- * these calls yields zero in AX and BX, or for AX=3306, a false return number that would imply
- * MS-DOS v1.0 (EAX=1). So, _Dos3Call@0 is not an option.
- *
- * But then that means we have absolutely no way to determine the DOS kernel version (short of
- * poking our nose into segments and memory locations we have no business being in!). We can't
- * use _Dos3Call@0, we can't use GetVersion() because the Win32 GetVersion() doesn't return
- * the DOS version, and we can't use Win95 style thunks because Win32s doesn't have a publicly
- * available and documented way to thunk down into Win16. We have absolutely jack shit to go by.
- *
- * Hey, Microsoft... When you released Win32s in 1993, did you ever stop to consider someone
- * might want to do something as simple as query the DOS version? Why couldn't you guys have
- * done something straightforward like a "GetDOSVersion()" API function that works under
- * Windows 9x/ME and returns an error under NT? I know it's silly of me to ask this in 2012
- * when Windows 8 is around the corner and Win32s are long dead, but often it seems like you
- * guys really don't stop to think about things like that and you make really stupid mistakes
- * with your APIs. */
- }
- else {
- dos_version = 0x532; /* Windows NT v5.50 */
- }
-# endif
-# elif TARGET_MSDOS == 16
-/* =================== Windows 16-bit ================== */
- DWORD raw = GetVersion(); /* NTS: The Win16 version does not tell us if we're running under Windows NT */
-
- dos_version_method = "GetVersion";
- dos_version = (((raw >> 24UL) & 0xFFUL) << 8UL) | (((raw >> 16UL) & 0xFFUL) << 0UL);
-
- /* Windows NT/2000/XP NTVDM.EXE lies to us, reporting Windows 95 numbers and MS-DOS 5.0 */
- if (dos_version == 0x500) {
- uint16_t x = 0;
-
- /* Sorry Microsoft, but you make it hard for us to detect and we have to break your OS to find the info we need */
- __asm {
- mov ax,0x3306
- mov bx,0
- int 21h
- jc err1
- mov x,bx
-err1:
- }
-
- if (x != 0 && x != 0x005) { /* Once pushed to reveal the true DOS version, NTVDM.EXE responds with v5.50 */
- dos_version = (x >> 8) | (x << 8);
- dos_version_method = "INT 21h AX=3306h/NTVDM.EXE";
- }
- }
-
- /* TODO: DOS "flavor" detection */
- /* TODO: If FreeDOS, get the kernel version and allocate a selector to point at FreeDOS's revision string */
-# else
-# error dunno
-# endif
-#elif defined(TARGET_OS2)
-/* =================== OS/2 ==================== */
- dos_version = (10 << 8) | 0;
- dos_version_method = "Blunt guess";
-
-# if TARGET_MSDOS == 32
- {
- ULONG major=0,minor=0,rev=0;
- DosQuerySysInfo(QSV_VERSION_MAJOR,QSV_VERSION_MAJOR,&major,sizeof(major));
- DosQuerySysInfo(QSV_VERSION_MINOR,QSV_VERSION_MINOR,&minor,sizeof(minor));
- DosQuerySysInfo(QSV_VERSION_REVISION,QSV_VERSION_REVISION,&rev,sizeof(rev));
- if (major != 0) {
- dos_version_method = "DosQuerySysInfo (OS/2)";
- dos_version = (major << 8) | minor;
- /* TODO: store the revision value too somewhere! */
- }
- }
-# elif TARGET_MSDOS == 16
- {
- USHORT x=0;
- DosGetVersion(&x);
- if (x != 0) {
- dos_version_method = "DosGetVersion (OS/2)";
- dos_version = x;
- }
- }
-# else
-# error dunno
-# endif
-#else
-/* =================== MS-DOS ================== */
- union REGS regs;
-
- regs.w.ax = 0x3000;
-# if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-# else
- int86(0x21,®s,®s);
-# endif
- dos_version = (regs.h.al << 8) | regs.h.ah;
- dos_version_method = "INT 21h AH=30h";
-
- if (dos_version >= 0x500 && regs.h.bh == 0xFD) {
- dos_flavor = DOS_FLAVOR_FREEDOS;
- freedos_kernel_version = (((uint32_t)regs.h.ch) << 16UL) |
- (((uint32_t)regs.h.cl) << 8UL) |
- ((uint32_t)regs.h.bl);
-
- /* now retrieve the FreeDOS kernel string */
- /* FIXME: Does this syscall have a way to return an error or indicate that it didn't return a string? */
- regs.w.ax = 0x33FF;
-# if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-# else
- int86(0x21,®s,®s);
-# endif
-
-# if TARGET_MSDOS == 32
- freedos_kernel_version_str = (unsigned char*)(((uint32_t)regs.w.dx << 4UL) + (uint32_t)regs.w.ax);
-# else
- freedos_kernel_version_str = MK_FP(regs.w.dx,regs.w.ax);
-# endif
- }
- else if (dos_version >= 0x200 && regs.h.bh == 0xFF)
- dos_flavor = DOS_FLAVOR_MSDOS;
-
- /* but, SETVER can arrange for DOS to lie to us. so get the real version via
- * undocumented subfunctions (DOS 5.0+ or later, apparently) */
- regs.w.ax = 0x3306; /* AH=0x33 AL=0x06 */
- regs.w.bx = 0; /* in case early DOS versions fail to set CF set BX to zero */
-# if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-# else
- int86(0x21,®s,®s);
-# endif
- if ((regs.w.cflag & 1) == 0 && regs.h.bl >= 5 && regs.h.bl <= 8) {
- dos_version = (regs.h.bl << 8) | regs.h.bh;
- dos_version_method = "INT 21h AX=3306h";
- }
-#endif
- }
-}
-
+++ /dev/null
-/* dos.h
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifndef __HW_DOS_DOS_H
-#define __HW_DOS_DOS_H
-
-#include "src/lib/doslib/cpu.h"
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NTVDM.EXE DOSNTAST.VDD call support */
-#include <windows/ntvdm/ntvdmlib.h>
-#endif
-
-#if defined(TARGET_OS2)
-# define INCL_DOSMISC
-# ifdef FAR /* <- conflict between OS/2 headers and cpu.h definition of "FAR" */
-# undef FAR
-# endif
-# include <os2.h>
-#endif
-
-extern unsigned char FAR *dos_LOL;
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-extern int8_t dpmi_no_0301h; /* -1 = not tested 0 = avail 1 = N/A */
-#else
-# define dpmi_no_0301h 0 /* FIXME: Is it possible for DOS extenders to run non-4GW non-LE executables? */
-#endif
-
-#define DPMI_ENTER_AUTO 0xFF
-
-/* DOS "Flavor" we are running under.
- * I originally didn't care too much until one day some really strange
- * fatal bugs popped up when running this code under FreeDOS 1.0, almost
- * as if the FreeDOS kernel does something to fuck with the DOS extender's
- * mind if our code attempts certain things like reading the ROM area... */
-enum {
- DOS_FLAVOR_NONE=0, /* generic DOS */
- DOS_FLAVOR_MSDOS, /* Microsoft MS-DOS */
- DOS_FLAVOR_FREEDOS, /* FreeDOS */
-};
-
-extern uint8_t dos_flavor;
-extern uint16_t dos_version;
-extern const char *dos_version_method;
-extern uint32_t freedos_kernel_version;
-#if TARGET_MSDOS == 32
-extern char *freedos_kernel_version_str;
-#else
-extern char far *freedos_kernel_version_str;
-#endif
-extern unsigned char vcpi_present;
-extern unsigned char vcpi_major_version,vcpi_minor_version;
-
-struct dos_mcb_enum {
- uint16_t segment;
- uint16_t counter;
- /* acquired data */
- unsigned char FAR *ptr; /* pointer to actual memory content */
- uint16_t size,psp,cur_segment;
- uint8_t type;
- char name[9];
-};
-
-#pragma pack(push,1)
-struct dpmi_realmode_call {
- uint32_t edi,esi,ebp,reserved;
- uint32_t ebx,edx,ecx,eax;
- uint16_t flags,es,ds,fs,gs,ip,cs,sp,ss;
-};
-#pragma pack(pop)
-
-#ifndef TARGET_OS2
-# if TARGET_MSDOS == 32
-/* WARNING: This is only 100% reliable if the memory in question is below the 1MB mark!
- * This may happen to work for pointers above the 1MB mark because DOS4GW and DOS32a tend to
- * allocate that way, but that 1:1 correspondence is not guaranteed */
-static inline uint32_t ptr2phys_low1mb(unsigned char *x) {
- return (uint32_t)x;
-}
-# else
-static inline uint32_t ptr2phys_low1mb(unsigned char far *x) {
- uint32_t r = (uint32_t)FP_SEG(x) << 4UL;
- return r + (uint32_t)FP_OFF(x);
-}
-# endif
-#endif
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
-static inline void far *normalize_realmode_far_ptr(void far *p) {
- return MK_FP(
- FP_SEG(p) + (FP_OFF(p) >> 4),
- FP_OFF(p) & 0xF);
-}
-#endif
-
-#ifndef TARGET_OS2
-# if TARGET_MSDOS == 32
-int _dos_xread(int fd,void *buffer,int bsz);
-# else
-int _dos_xread(int fd,void far *buffer,int bsz);
-# endif
-
-# if TARGET_MSDOS == 32
-int _dos_xwrite(int fd,void *buffer,int bsz);
-# else
-int _dos_xwrite(int fd,void far *buffer,int bsz);
-# endif
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-# define dpmi_alloc_descriptor() dpmi_alloc_descriptors(1)
-
-void *dpmi_alloc_dos(unsigned long len,uint16_t *selector);
-void dpmi_free_dos(uint16_t selector);
-
-void dpmi_free_descriptor(uint16_t d);
-uint16_t dpmi_alloc_descriptors(uint16_t c);
-unsigned int dpmi_set_segment_base(uint16_t sel,uint32_t base);
-unsigned int dpmi_set_segment_limit(uint16_t sel,uint32_t limit);
-unsigned int dpmi_set_segment_access(uint16_t sel,uint16_t access);
-void *dpmi_phys_addr_map(uint32_t phys,uint32_t size);
-void dpmi_phys_addr_free(void *base);
-#endif
-
-#if TARGET_MSDOS == 32
-unsigned char *dos_list_of_lists();
-#else
-unsigned char far *dos_list_of_lists();
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-int dpmi_alternate_rm_call(struct dpmi_realmode_call *rc);
-int dpmi_alternate_rm_call_stacko(struct dpmi_realmode_call *rc);
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-# if defined(TARGET_WINDOWS)
-/* as a 32-bit Windows program: even if DPMI is present, it's useless to us because we can't call into that part of Windows */
-# define dpmi_present 0
-# endif
-#endif
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
-/* as a 16-bit program (DOS or Windows), DPMI might be present. Note that DPMI can be present even under NTVDM.EXE under Windows NT,
- * because NTVDM.EXE will emulate some DPMI functions. */
-extern unsigned char dpmi_present;
-extern uint16_t dpmi_flags;
-extern unsigned char dpmi_init;
-extern uint32_t dpmi_entry_point; /* NTS: This is the real-mode address, even for 32-bit builds */
-extern unsigned char dpmi_processor_type;
-extern uint16_t dpmi_version;
-extern uint16_t dpmi_private_data_length_paragraphs;
-extern uint16_t dpmi_private_data_segment;
-extern unsigned char dpmi_entered; /* 0=not yet entered, 16=entered as 16bit, 32=entered as 32bit */
-extern uint64_t dpmi_rm_entry;
-extern uint32_t dpmi_pm_entry;
-extern uint16_t dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss;
-
-void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
-#endif
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-int dpmi_private_alloc();
-int dpmi_enter(unsigned char mode);
-#endif
-
-void probe_dos();
-void probe_dpmi();
-int probe_vcpi();
-
-uint16_t dos_mcb_first_segment();
-int mcb_name_is_junk(char *s/*8 char*/);
-int dos_mcb_next(struct dos_mcb_enum *e);
-int dos_mcb_first(struct dos_mcb_enum *e);
-void mcb_filter_name(struct dos_mcb_enum *e);
-unsigned char FAR *dos_mcb_get_psp(struct dos_mcb_enum *e);
-
-struct dos_psp_cooked {
- unsigned char FAR *raw;
- uint16_t memsize,callpsp,env;
- char cmd[130];
-};
-
-int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e);
-
-struct dos_device_enum {
- unsigned char FAR *raw,FAR *next;
- uint16_t ns,no,attr,entry,intent,count;
- char name[9];
-};
-
-int dos_device_first(struct dos_device_enum *e);
-int dos_device_next(struct dos_device_enum *e);
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
-uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
-#endif
-
-#if TARGET_MSDOS == 32
-extern struct dos_linear_to_phys_info dos_ltp_info;
-extern unsigned char dos_ltp_info_init;
-
-int dos_ltp_probe();
-
-/* NTS: The return value is 64-bit so that in scenarios where we hack DPMI to support PSE and PAE modes,
- * the function will still return the physical address associated with the page even when it's above
- * the 4GB boundary. But as a 32-bit DOS program, the linear addresses will never exceed 32-bit. */
-uint64_t dos_linear_to_phys(uint32_t linear);
-
-int dpmi_linear_lock(uint32_t lin,uint32_t size);
-int dpmi_linear_unlock(uint32_t lin,uint32_t size);
-void *dpmi_linear_alloc(uint32_t try_lin,uint32_t size,uint32_t flags,uint32_t *handle);
-int dpmi_linear_free(uint32_t handle);
-
-#define DOS_LTP_FAILED 0xFFFFFFFFFFFFFFFFULL
-
-struct dos_linear_to_phys_info {
- unsigned char paging:1; /* paging is enabled, therefore mapping will occur. if not set, then linear == physical memory addresses */
- unsigned char dos_remap:1; /* if set, the lower 1MB region (DOS conventional memory) is remapped. if clear, we can assume 1:1 mapping below 1MB */
- unsigned char should_lock_pages:1; /* if set, the program should call DPMI functions to lock pages before attempting to get physical memory address */
- unsigned char cant_xlate:1; /* if set, resources to determine physical memory addresses are not available (such as: running in a Windows DOS Box). however dos_remap=0 means we can assume 1:1 mapping below 1MB */
- unsigned char using_pae:1; /* if set, the DOS extender or DPMI host has PAE/PSE extensions enabled. This changes how page tables are parsed, and can prevent us from mapping */
- unsigned char dma_dos_xlate:1; /* usually set if dos_remap=1 to say the DOS extender or environment translates DMA addresses (i.e. Windows DOS Box), but we can't actually know the physical memory address. We can do DMA from DOS memory */
- unsigned char vcpi_xlate:1; /* use VCPI to translate linear -> phys */
- unsigned char reserved:1;
- uint32_t cr0;
- uint32_t cr3; /* last known copy of the CR3 (page table base) register */
- uint32_t cr4; /* last known copy of the CR4 register */
-};
-#endif
-
-#define BIOS_KS_ALT 0x08
-#define BIOS_KT_CTRL 0x04
-
-static inline unsigned char read_bios_keystate() { /* from 0x40:0x17 */
-#if TARGET_MSDOS == 32
- return *((unsigned char*)(0x400 + 0x17));
-#else
- return *((unsigned char far*)MK_FP(0x40,0x17));
-#endif
-}
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-void far *win16_getexhandler(unsigned char n);
-int win16_setexhandler(unsigned char n,void far *x);
-void far *win16_getvect(unsigned char n);
-int win16_setvect(unsigned char n,void far *x);
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-typedef struct Win32OrdinalLookupInfo {
- DWORD entries,base,base_addr;
- DWORD* table;
-} Win32OrdinalLookupInfo;
-
-DWORD *Win32GetExportOrdinalTable(HMODULE mod,DWORD *entries,DWORD *base,DWORD *base_addr);
-void *Win32GetOrdinalAddress(Win32OrdinalLookupInfo *nfo,unsigned int ord);
-int Win32GetOrdinalLookupInfo(HMODULE mod,Win32OrdinalLookupInfo *info);
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-extern DWORD genthunk32w_ntdll;
-extern DWORD genthunk32w_kernel32;
-extern DWORD genthunk32w_kernel32_GetVersion;
-extern DWORD genthunk32w_kernel32_GetVersionEx;
-extern DWORD genthunk32w_kernel32_GetLastError;
-extern BOOL __GenThunksExist;
-extern BOOL __GenThunksChecked;
-extern DWORD (PASCAL FAR *__LoadLibraryEx32W)(LPCSTR lpName,DWORD a,DWORD b);
-extern BOOL (PASCAL FAR *__FreeLibrary32W)(DWORD hinst);
-extern DWORD (PASCAL FAR *__GetProcAddress32W)(DWORD hinst,LPCSTR name);
-extern DWORD (PASCAL FAR *__GetVDMPointer32W)(LPVOID ptr,UINT mask);
-extern DWORD (_cdecl _far *__CallProcEx32W)(DWORD params,DWORD convertMask,DWORD procaddr32,...);
-
-/* NOTE: You call it as if it were declared CallProc32W(..., DWORD hinst,DWORD convertMask,DWORD procaddr32); Ick */
-extern DWORD (PASCAL FAR *__CallProc32W)(DWORD hinst,DWORD convertMask,DWORD procaddr32,...);
-
-/* it would be nice if Open Watcom defined these constants for Win16 */
-#define CPEX_DEST_STDCALL 0x00000000UL
-#define CPEX_DEST_CDECL 0x80000000UL
-
-int genthunk32_init();
-void genthunk32_free();
-#endif
-
-#if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
-#pragma pack(push,4)
-/* OpenWatcom does not define the OSVERSIONINFO struct for Win16 */
-typedef struct OSVERSIONINFO {
- uint32_t dwOSVersionInfoSize;
- uint32_t dwMajorVersion;
- uint32_t dwMinorVersion;
- uint32_t dwBuildNumber;
- uint32_t dwPlatformId;
- char szCSDVersion[128];
-} OSVERSIONINFO;
-
-#define MAXPNAMELEN 32
-
-#define WAVECAPS_PITCH 0x0001
-#define WAVECAPS_PLAYBACKRATE 0x0002
-#define WAVECAPS_VOLUME 0x0004
-#define WAVECAPS_LRVOLUME 0x0008
-#define WAVECAPS_SYNC 0x0010
-#define WAVECAPS_SAMPLEACCURATE 0x0020
-
-typedef struct WAVEOUTCAPS {
- uint16_t wMid;
- uint16_t wPid;
- uint32_t vDriverVersion;
- char szPname[MAXPNAMELEN];
- uint32_t dwFormats;
- uint16_t wChannels;
- uint16_t wReserved1;
- uint32_t dwSupport;
-} WAVEOUTCAPS;
-#pragma pack(pop)
-#endif
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void far *dpmi_getexhandler(unsigned char n);
-int dpmi_setexhandler(unsigned char n,void far *x);
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* TODO: This should be moved into the hw/DOS library */
-extern unsigned char nmi_32_hooked;
-extern int nmi_32_refcount;
-extern void (interrupt *nmi_32_old_vec)();
-
-void do_nmi_32_unhook();
-void do_nmi_32_hook();
-#endif
-
-#if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-enum {
- DOS_CLOSE_AWARENESS_NOT_ACK=0,
- DOS_CLOSE_AWARENESS_ACKED=1
-};
-
-void dos_vm_yield();
-void dos_close_awareness_ack();
-int dos_close_awareness_query();
-void dos_close_awareness_cancel();
-int dos_close_awareness_available();
-int dos_close_awareness_enable(unsigned char en);
-#endif
-
-/* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
-extern char virtualbox_version_str[64];
-
-int detect_virtualbox_emu();
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-int __cdecl dpmi_lin2fmemcpy_32(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-int __cdecl dpmi_lin2fmemcpy_16(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-int dpmi_lin2fmemcpy(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-int dpmi_lin2fmemcpy_init();
-#endif
-
-struct lib_dos_options {
- uint8_t dont_load_dosntast:1; /* do not automatically load DOSNTAST, but use it if loaded. */
- /* if not loaded and the program wants it later on, it should
- * call ntvdm_dosntast_load_vdd(); */
- uint8_t dont_use_dosntast:1; /* do not use DOSNTAST, even if loaded */
- uint8_t __reserved__:6;
-};
-
-extern struct lib_dos_options lib_dos_option;
-
-# define DOSNTAST_HANDLE_UNASSIGNED 0xFFFFU
-
-# define DOSNTAST_INIT_REPORT_HANDLE 0xD0500000
-# define DOSNTAST_INIT_REPORT_HANDLE_C 0xD0500000ULL
-/* in: EBX = DOSNTAST_INIT_REPORT_HANDLE
- * ECX = NTVDM handle
- * out: EBX = 0x55AA55AA
- * ECX = flat memory address where signature is stored (must be in BIOS data area) */
-
-# define DOSNTAST_GETVERSIONEX 0xD0500001
-# define DOSNTAST_GETVERSIONEX_C 0xD0500001ULL
-/* in: EBX = <command>
- * ECX = protected mode call (1) or real-mode call (0)
- * DS:ESI = OSVERSIONINFO struct
- * out: EBX = result
- * DS:ESI = filled in with OS struct */
-
-# define DOSNTAST_GET_TICK_COUNT 0xD0500002
-# define DOSNTAST_GET_TICK_COUNT_C 0xD0500002ULL
-/* in: EBX = <command>
- * out: EBX = tick count */
-
-# define DOSNTAST_GET_IO_PORT 0xD0500003
-# define DOSNTAST_GET_IO_PORT_C 0xD0500003ULL
-/* in: EBX = <command>
- * out: EBX = 0x55AA55AA
- * EDX = I/O port base */
-
-# define DOSNTAST_NOTIFY_UNLOAD 0xD050FFFF
-# define DOSNTAST_NOTIFY_UNLOAD_C 0xD050FFFFULL
-/* in: EBX = <command>
- * out: EBX = none */
-
-# define DOSNTAST_FUNCTION_GENERAL 0x1000
-# define DOSNTAST_FUN_GEN_SUB_MESSAGEBOX 0x0000
-
-# define DOSNTAST_FUNCTION_WINMM 0x1001
-# define DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs 0x0000
-# define DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps 0x0001
-# define DOSNTAST_FUN_WINMM_SUB_waveOutOpen 0x0002
-
-const char *dos_flavor_str(uint8_t f);
-
-/* Windows NT-friendly version of Win386 MapAliasToFlat.
- * The library version is naive and assumes Windows 3.x/9x/ME behavior.
- * If you need to convert pointers NOT given by Win386's AllocAlias() functions
- * (such as 16:16 pointers given by Window messages) and need the code to gracefully
- * handle itself under Windows NT, use this function not MapAliasToFlat() */
-#if TARGET_MSDOS == 32 && defined(WIN386)
-void far *win386_alt_winnt_MapAliasToFlat(DWORD farptr);
-void far *win386_help_MapAliasToFlat(DWORD farptr);
-#endif
-
-#if (TARGET_MSDOS == 16 || TARGET_MSDOS == 32) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-extern unsigned short smartdrv_version;
-extern int smartdrv_fd;
-
-int smartdrv_close();
-int smartdrv_flush();
-int smartdrv_detect();
-#endif
-
-uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
-
-#endif /* __HW_DOS_DOS_H */
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* Windows 9x/NT Close-awareness */
-void dos_close_awareness_cancel() {
- __asm {
- .386p
- mov ax,0x168F
- mov dx,0x0300
- int 0x2F
- }
-}
-
-void dos_close_awareness_ack() {
- __asm {
- .386p
- mov ax,0x168F
- mov dx,0x0200
- int 0x2F
- }
-}
-
-int dos_close_awareness_enable(unsigned char en) {
- uint16_t r=0;
-
- en = (en != 0) ? 1 : 0;
-
- __asm {
- .386p
- mov ax,0x168F
- xor dx,dx
- mov dl,en
- int 0x2F
- mov r,ax
- }
-
- return (int)r;
-}
-
-int dos_close_awareness_query() {
- uint16_t r=0;
-
- __asm {
- .386p
- mov ax,0x168F
- mov dx,0x0100
- int 0x2F
- mov r,ax
- }
-
- if (r == 0x168F)
- return -1;
-
- return (int)r;
-}
-
-int dos_close_awareness_available() {
- /* "close-awareness" is provided by Windows */
- return (windows_mode == WINDOWS_ENHANCED || windows_mode == WINDOWS_NT);
-}
-
-void dos_vm_yield() {
- __asm {
- mov ax,0x1680 /* RELEASE VM TIME SLICE */
- xor bx,bx /* THIS VM */
- int 0x2F
- }
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DOS "list of lists" pointer */
-unsigned char FAR *dos_LOL=NULL;
-
-/* MS-DOS "list of lists" secret call */
-#if TARGET_MSDOS == 32
-# ifdef WIN386
-unsigned char *dos_list_of_lists() {
- return NULL;/*not implemented*/
-}
-# else
-static void dos_realmode_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x0021
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-
-unsigned char *dos_list_of_lists() {
- struct dpmi_realmode_call rc={0};
-
- rc.eax = 0x5200;
- dos_realmode_call(&rc);
- if (rc.flags & 1) return NULL; /* CF */
- return (dos_LOL = ((unsigned char*)((rc.es << 4) + (rc.ebx & 0xFFFFUL))));
-}
-# endif
-#else
-unsigned char far *dos_list_of_lists() {
- unsigned int s=0,o=0;
-
- __asm {
- mov ah,0x52
- int 21h
- jc notwork
- mov s,es
- mov o,bx
-notwork:
- }
-
- return (dos_LOL = ((unsigned char far*)MK_FP(s,o)));
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* TODO: Since VCPI/EMM386.EXE can affect 16-bit real mode, why not enable this API for 16-bit real mode too? */
-/* TODO: Also why not enable this function for 16-bit protected mode under Windows 3.1? */
-#if TARGET_MSDOS == 32
-struct dos_linear_to_phys_info dos_ltp_info;
-unsigned char dos_ltp_info_init=0;
-
-/* WARNING: Caller must have called probe_dos() and detect_windows() */
-int dos_ltp_probe() {
- if (!dos_ltp_info_init) {
- memset(&dos_ltp_info,0,sizeof(dos_ltp_info));
-
- /* part of our hackery needs to know what CPU we're running under */
- if (cpu_basic_level < 0)
- cpu_probe();
-
- probe_dos();
-
-#if defined(TARGET_WINDOWS)
- /* TODO: Careful analsys of what version and mode Windows we're running under */
- /* start with the assumption that we don't know where we are and we can't translate to physical. */
- dos_ltp_info.vcpi_xlate = 0; /* TODO: It is said Windows 3.0 has VCPI at the core. Can we detect that? Use it? */
- dos_ltp_info.paging = (windows_mode <= WINDOWS_STANDARD ? 0 : 1); /* paging is not used in REAL or STANDARD modes */
- dos_ltp_info.dos_remap = dos_ltp_info.paging;
- dos_ltp_info.should_lock_pages = 1;
- dos_ltp_info.cant_xlate = 1;
- dos_ltp_info.using_pae = 0; /* TODO: Windows XP SP2 and later can and do use PAE. How to detect that? */
- dos_ltp_info.dma_dos_xlate = 0;
-
-# if TARGET_MSDOS == 32
-# else
- /* TODO: Use GetWinFlags() and version info */
-# endif
-#else
-/* ================ MS-DOS specific =============== */
- /* we need to know if VCPI is present */
- probe_vcpi();
-
- /* NTS: Microsoft Windows 3.0/3.1 Enhanced mode and Windows 95/98/ME all trap access to the control registers.
- * But then they emulate the instruction in such a way that we get weird nonsense values.
- *
- * Windows 95/98/ME: We get CR0 = 2. Why??
- * Windows 3.0/3.1: We get CR0 = 0.
- *
- * So basically what Windows is telling us... is that we're 32-bit protected mode code NOT running in
- * protected mode? What? */
- if (windows_mode == WINDOWS_ENHANCED) {
- /* it's pointless, the VM will trap and return nonsense for control register contents */
- dos_ltp_info.cr0 = 0x80000001UL;
- dos_ltp_info.cr3 = 0x00000000UL;
- dos_ltp_info.cr4 = 0x00000000UL;
- }
- else if (windows_mode == WINDOWS_NT) {
- /* Windows NTVDM will let us read CR0, but CR3 and CR4 come up blank. So what's the point then? */
- uint32_t r0=0;
-
- __asm {
- xor eax,eax
- dec eax
-
- mov eax,cr0
- mov r0,eax
- }
- dos_ltp_info.cr0 = r0 | 0x80000001UL; /* paging and protected mode are ALWAYS enabled, even if NTVDM should lie to us */
- dos_ltp_info.cr3 = 0x00000000UL;
- dos_ltp_info.cr4 = 0x00000000UL;
- }
- else {
- uint32_t r0=0,r3=0,r4=0;
- __asm {
- xor eax,eax
- dec eax
-
- mov eax,cr0
- mov r0,eax
-
- mov eax,cr3
- mov r3,eax
-
- mov eax,cr4
- mov r4,eax
- }
- dos_ltp_info.cr0 = r0;
- dos_ltp_info.cr3 = r3;
- dos_ltp_info.cr4 = r4;
- }
-
- dos_ltp_info.vcpi_xlate = vcpi_present?1:0; /* if no other methods available, try asking the VCPI server */
- dos_ltp_info.paging = (dos_ltp_info.cr0 >> 31)?1:0; /* if bit 31 of CR0 is set, the extender has paging enabled */
- dos_ltp_info.dos_remap = vcpi_present?1:0; /* most DOS extenders map 1:1 the lower 1MB, but VCPI can violate that */
- dos_ltp_info.should_lock_pages = dos_ltp_info.paging; /* it's a good assumption if paging is enabled the extender probably pages to disk and may move things around */
- dos_ltp_info.cant_xlate = dos_ltp_info.paging; /* assume we can't translate addresses yet if paging is enabled */
- dos_ltp_info.using_pae = (dos_ltp_info.cr4 & 0x20)?1:0; /* take note if PAE is enabled */
- dos_ltp_info.dma_dos_xlate = dos_ltp_info.paging; /* assume the extender translates DMA if paging is enabled */
-
- if (windows_mode == WINDOWS_ENHANCED || windows_mode == WINDOWS_NT) {
- dos_ltp_info.should_lock_pages = 1; /* Windows is known to page to disk (the swapfile) */
- dos_ltp_info.dma_dos_xlate = 1; /* Windows virtualizes the DMA controller */
- dos_ltp_info.cant_xlate = 1; /* Windows provides us no way to determine the physical memory address from linear */
- dos_ltp_info.dos_remap = 1; /* Windows remaps the DOS memory area. This is how it makes multiple DOS VMs possible */
- dos_ltp_info.vcpi_xlate = 0; /* Windows does not like VCPI */
- dos_ltp_info.paging = 1; /* Windows uses paging. Always */
- }
-
- /* this code is ill prepared for PAE modes for the time being, since PAE makes page table entries 64-bit
- * wide instead of 32-bit wide. Then again, 99% of DOS out there probably couldn't handle PAE well either. */
- if (dos_ltp_info.using_pae)
- dos_ltp_info.cant_xlate = 1;
-
- /* if NOT running under Windows, and the CR3 register shows something, then we can translate by directly peeking at the page tables */
- if (windows_mode == WINDOWS_NONE && dos_ltp_info.cr3 >= 0x1000)
- dos_ltp_info.cant_xlate = 0;
-#endif
-
- dos_ltp_info_init = 1;
- }
-
- return 1;
-}
-#endif
-
-#if TARGET_MSDOS == 32
-/* WARNINGS: Worst case scanario this function cannot translate anything at all.
- * It will return 0xFFFFFFFFUL if it cannot determine the address.
- * If paging is disabled, the linear address will be returned.
- * If the environment requires you to lock pages, then you must do so
- * before calling this function. Failure to do so will mean erratic
- * behavior when the page you were working on moves out from under you! */
-
-/* "There is no way in a DPMI environment to determine the physical address corresponding to a given linear address. This is part of the design of DPMI. You must design your application accordingly."
- *
- * Fuck you.
- * I need the damn physical address and you're not gonna stop me! */
-
-/* NOTES:
- *
- * QEMU + Windows 95 + EMM386.EXE:
- *
- * I don't know if the DOS extender is doing this, or EMM386.EXE is enforcing it, but
- * a dump of the first 4MB in the test program reveals our linear address space is
- * randomly constructed from 16KB pages taken from all over extended memory. Some of
- * them, the pages are arranged BACKWARDS. Yeah, backwards.
- *
- * Anyone behind DOS4/GW and DOS32a care to explain that weirdness?
- *
- * Also revealed, DOS4/GW follows the DPMI spec and refuses to map pages from conventional
- * memory. So if DOS memory is not mapped 1:1 and the page tables are held down there we
- * literally cannot read them! */
-/* NOTE: The return value is 64-bit so that in the future, if we ever run under DOS with PAE or
- * PSE-36 trickery, we can still report the correct address even if above 4GB. The parameter
- * supplied however remains 32-bit, because as a 32-bit DOS program there's no way any
- * linear address will ever exceed 4GB. */
-uint64_t dos_linear_to_phys(uint32_t linear) {
- uint32_t off,ent;
- uint64_t ret = DOS_LTP_FAILED;
- unsigned char lock1=0,lock2=0;
- uint32_t *l1=NULL,*l2=NULL;
-
- if (!dos_ltp_info.paging)
- return linear;
- if (linear < 0x100000UL && !dos_ltp_info.dos_remap) /* if below 1MB boundary and DOS is not remapped, then no translation */
- return linear;
-
- /* if VCPI translation is to be used, and lower DOS memory is remapped OR the page requested is >= 1MB (or in adapter ROM/RAM), then call the VCPI server and ask */
- if (dos_ltp_info.vcpi_xlate && (dos_ltp_info.dos_remap || linear >= 0xC0000UL)) {
- ent = dos_linear_to_phys_vcpi(linear>>12);
- if (ent != 0xFFFFFFFFUL) return ent;
- /* Most likely requests for memory >= 1MB will fail, because VCPI is only required to
- * provide the system call for lower 1MB DOS conventional memory */
- }
-
-/* if we can't use VCPI and cannot translate, then give up. */
-/* also, this code does not yet support PAE */
- if (dos_ltp_info.using_pae || dos_ltp_info.cant_xlate)
- return ret;
-
-/* re-read control reg because EMM386, etc. is free to change it at any time */
- {
- uint32_t r3=0,r4=0;
- __asm {
- xor eax,eax
- dec eax
-
- mov eax,cr3
- mov r3,eax
-
- mov eax,cr4
- mov r4,eax
- }
- dos_ltp_info.cr3 = r3;
- dos_ltp_info.cr4 = r4;
- }
-
- /* OK then, we have to translate */
- off = linear & 0xFFFUL;
- linear >>= 12UL;
- if (dos_ltp_info.cr3 < 0x1000) /* if the contents of CR3 are not available, then we cannot translate */
- return ret;
-
- /* VCPI possibility: the page table might reside below 1MB in DOS memory, and remain unmapped. */
- if (dos_ltp_info.dos_remap && dos_ltp_info.vcpi_xlate && dos_ltp_info.cr3 < 0x100000UL) {
- lock1 = 0;
- if (dos_linear_to_phys_vcpi(dos_ltp_info.cr3>>12) == (dos_ltp_info.cr3&0xFFFFF000UL)) /* if VCPI says it's a 1:1 mapping down there, then it's OK */
- l1 = (uint32_t*)(dos_ltp_info.cr3 & 0xFFFFF000UL);
- }
- /* DOS4/GW and DOS32A Goodie: the first level of the page table is in conventional memory... and the extender maps DOS 1:1 :) */
- else if (!dos_ltp_info.dos_remap && dos_ltp_info.cr3 < 0x100000UL) {
- lock1 = 0;
- l1 = (uint32_t*)(dos_ltp_info.cr3 & 0xFFFFF000UL);
- }
- else {
- /* well, then we gotta map it */
- l1 = (uint32_t*)dpmi_phys_addr_map(dos_ltp_info.cr3 & 0xFFFFF000UL,4096);
- if (l1 != NULL) lock1 = 1;
- }
-
- if (l1 != NULL) {
- /* level 1 lookup */
- ent = l1[linear >> 10UL];
- if (ent & 1) { /* if the page is actually present... */
- /* if the CPU supports PSE (Page Size Extensions) and has them enabled (via CR4) and the page is marked PS=1 */
- if ((cpu_cpuid_features.a.raw[2/*EDX*/] & (1 << 3)) && (dos_ltp_info.cr4 & 0x10) && (ent & 0x80)) {
- /* it's a 4MB page, and we stop searching the page hierarchy here */
- ret = ent & 0xFFC00000UL; /* bits 31-22 are the actual page address */
-
- /* but wait: if the CPU supports PSE-36, then we need to readback address bits 35...32,
- * or if an AMD64 processor, address bits 39...32 */
- /* FIXME: So, we can assume if the CPU supports 64-bit long mode, that we can use bits 39...32?
- * Perhaps this is a more in-depth check that we should be doing in the ltp_probe function? */
- if (cpu_cpuid_features.a.raw[2/*E2X*/] & (1 << 17)) { /* If PSE support exists */
- if (cpu_cpuid_features.a.raw[3/*ECX*/] & (1 << 29)) { /* If CPU supports 64-bit long mode */
- /* AMD64 compatible, up to 40 bits */
- ret |= ((uint64_t)((ent >> 13UL) & 0xFFUL)) << 32ULL;
- }
- else { /* else, assume Pentium III compatible, up to 36 bits */
- ret |= ((uint64_t)((ent >> 13UL) & 0xFUL)) << 32ULL;
- }
- }
- }
- else {
- /* VCPI possibility: the page table might reside below 1MB in DOS memory, and remain unmapped. */
- if (dos_ltp_info.dos_remap && dos_ltp_info.vcpi_xlate && ent < 0x100000UL) {
- lock2 = 0;
- if (dos_linear_to_phys_vcpi(ent>>12) == (ent&0xFFFFF000UL)) /* if VCPI says it's a 1:1 mapping down there, then it's OK */
- l2 = (uint32_t*)(ent & 0xFFFFF000UL);
- }
- /* again the second level is usually in DOS memory where we can assume 1:1 mapping */
- else if (!dos_ltp_info.dos_remap && !dos_ltp_info.dos_remap && ent < 0x100000UL) {
- lock2 = 0;
- l2 = (uint32_t*)(ent & 0xFFFFF000UL);
- }
- else {
- /* well, then we gotta map it */
- l2 = (uint32_t*)dpmi_phys_addr_map(ent & 0xFFFFF000UL,4096);
- if (l2 != NULL) lock2 = 1;
- }
- }
- }
- }
-
- if (l2 != NULL) {
- /* level 2 lookup */
- ent = l2[linear & 0x3FF];
- if (ent & 1) { /* if the page is actually present... */
- ret = ent & 0xFFFFF000UL;
- }
- }
-
- if (lock2) dpmi_phys_addr_free((void*)l2);
- if (lock1) dpmi_phys_addr_free((void*)l1);
- return ret;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-unsigned char FAR *dos_mcb_get_psp(struct dos_mcb_enum *e) {
- if (e->psp < 0x80 || e->psp == 0xFFFFU)
- return NULL;
-
-#if TARGET_MSDOS == 32
- return (unsigned char*)((uint32_t)e->psp << 4UL);
-#else
- return (unsigned char FAR*)MK_FP(e->psp,0);
-#endif
-}
-
-int mcb_name_is_junk(char *s/*8 char*/) {
- int junk=0,i;
- unsigned char c;
-
- for (i=0;i < 8;i++) {
- c = (unsigned char)s[i];
- if (c == 0)
- break;
- else if (c < 32 || c >= 127)
- junk = 1;
- }
-
- return junk;
-}
-
-uint16_t dos_mcb_first_segment() {
- if (dos_LOL == NULL)
- return 0;
-
- return *((uint16_t FAR*)(dos_LOL-2)); /* NTS: This is not a mistake. You take the pointer given by DOS and refer to the WORD starting 2 bytes PRIOR. I don't know why they did that... */
-}
-
-void mcb_filter_name(struct dos_mcb_enum *e) {
- if (e->psp > 0 && e->psp < 0x80) { /* likely special DOS segment */
- if (!memcmp(e->name,"SC",2) || !memcmp(e->name,"SD",2))
- memset(e->name+2,0,6);
- else
- memset(e->name,0,8);
- }
- else if (mcb_name_is_junk(e->name)) {
- memset(e->name,0,8);
- }
-}
-
-int dos_mcb_next(struct dos_mcb_enum *e) {
- unsigned char FAR *mcb;
- unsigned int i;
- uint16_t nxt;
-
- if (e->type == 0x5A || e->segment == 0x0000U || e->segment == 0xFFFFU)
- return 0;
- if (e->counter >= 16384)
- return 0;
-
-#if TARGET_MSDOS == 32
- mcb = (unsigned char*)((uint32_t)(e->segment) << 4UL);
- e->ptr = mcb + 16;
-#else
- mcb = (unsigned char far*)(MK_FP(e->segment,0));
- e->ptr = (unsigned char far*)(MK_FP(e->segment+1U,0));
-#endif
-
- e->cur_segment = e->segment;
- e->type = *((uint8_t FAR*)(mcb+0));
- e->psp = *((uint16_t FAR*)(mcb+1));
- e->size = *((uint16_t FAR*)(mcb+3));
- for (i=0;i < 8;i++) e->name[i] = mcb[i+8]; e->name[8] = 0;
- if (e->type != 0x5A && e->type != 0x4D) return 0;
- nxt = e->segment + e->size + 1;
- if (nxt <= e->segment) return 0;
- e->segment = nxt;
- return 1;
-}
-
-int dos_mcb_first(struct dos_mcb_enum *e) {
- if (dos_LOL == NULL)
- return 0;
-
- e->counter = 0;
- e->segment = dos_mcb_first_segment();
- if (e->segment == 0x0000U || e->segment == 0xFFFFU)
- return 0;
-
- return dos_mcb_next(e);
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* TODO: This should be moved into the hw/DOS library */
-unsigned char nmi_32_hooked = 0;
-int nmi_32_refcount = 0;
-void (interrupt *nmi_32_old_vec)() = NULL;
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NMI reflection (32-bit -> 16-bit)
- This code is VITAL if we want to work with SBOS and MEGA-EM
- from protected mode. */
-static struct dpmi_realmode_call nmi_32_nr={0};
-static void interrupt far nmi_32() {
- /* trigger a real-mode INT 02h */
- __asm {
- mov ax,0x0300
- mov bx,0x02
- xor cx,cx
- mov edi,offset nmi_32_nr ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-
-void do_nmi_32_unhook() {
- if (nmi_32_refcount > 0)
- nmi_32_refcount--;
-
- if (nmi_32_refcount == 0) {
- if (nmi_32_hooked) {
- nmi_32_hooked = 0;
- _dos_setvect(0x02,nmi_32_old_vec);
- nmi_32_old_vec = NULL;
- }
- }
-}
-
-void do_nmi_32_hook() {
- if (nmi_32_refcount == 0) {
- if (!nmi_32_hooked) {
- nmi_32_hooked = 1;
- nmi_32_old_vec = _dos_getvect(0x02);
- _dos_setvect(0x02,nmi_32);
- }
- }
- nmi_32_refcount++;
-}
-#endif
-
+++ /dev/null
-; dosasm.asm
-;
-; Assembly language support routines for dos.c
-; (C) 2011-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-
-extern _dpmi_entered ; BYTE
-extern _dpmi_entry_point ; DWORD
-extern _dpmi_private_data_segment ; word
-extern _dpmi_rm_entry ; qword
-extern _dpmi_pm_entry ; dword
-extern _dpmi_pm_cs,_dpmi_pm_ds,_dpmi_pm_es,_dpmi_pm_ss
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%ifndef TARGET_WINDOWS
- %if TARGET_MSDOS == 16
-; cheap coding: put some variables here in the code segment. as real-mode
-; code there's nothing to stop us from leaving DS == CS on entry and letting
-; DPMI build an alias to our own code segment
-l_dpmi_mode db 0
-l_dpmi_rm_entry dd 0 ; also re-used to call entry!
- dw 0
-l_dpmi_pm_entry dd 0
-; we also need to record the segments given to us by the DPMI server so
-; that we can re-enter protected mode
-l_dpmi_segs dw 0,0,0,0
-this_process_psp dw 0
-
-; void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
-global _dpmi_enter_core
-_dpmi_enter_core:
- ; 16-bit or 32-bit?
- pushf
- pusha
- push ds
- push es
- push cs
- push ss
- cli
- mov ax,seg _dpmi_entered
- mov ds,ax
- xor ax,ax
- mov bl,byte [_dpmi_entered]
- mov byte [cs:l_dpmi_mode],bl ; the protected mode side of the function needs this
- cmp bl,32
- jnz .not32_ax
- or al,1 ; indicate 32-bit DPMI connection
-.not32_ax:
- ; so: AX=0 if 16-bit setup, AX=1 if 32-bit setup. Now for simplicity set DS==CS
- mov bx,seg _dpmi_private_data_segment ; NTS may be zero if DPMI doesn't need it
- mov es,bx
- mov es,[es:_dpmi_private_data_segment] ; NTS: ES = DPMI private data. Do not modify between here and call to DPMI entry
-
- mov bx,seg _dpmi_entry_point
- mov ds,bx
- mov bx,word [_dpmi_entry_point+0]
- mov word [cs:l_dpmi_rm_entry+0],bx
- mov bx,word [_dpmi_entry_point+2]
- mov word [cs:l_dpmi_rm_entry+2],bx
-
- mov bx,cs
- mov ds,bx
- call far word [cs:l_dpmi_rm_entry]
- jnc .entry_ok
- ; ENTRY FAILED. Set entered flag to zero and return
- mov ax,seg _dpmi_entered
- mov ds,ax
- mov byte [_dpmi_entered],0
- add sp,4 ; discard saved CS+SS
- pop es
- pop ds
- popa
- popf
- retnative
-; HERE: Entry succeeded. Get DPMI PM/RM entry points and then switch back to real mode.
-; note that because we entered with DS == CS the DPMI server should have CS != DS but both
-; refer to the same segment, as aliases. That makes our job simpler as we can use local storage
-; privately in the code segment.
-.entry_ok:
- mov ax,0x0306
- int 31h
-
- ; BX:CX real to protected mode entry point
- mov word [l_dpmi_pm_entry+0],cx
- mov word [l_dpmi_pm_entry+2],bx
-
- ; save the selectors preallocated by DPMI
- mov word [l_dpmi_segs+0],cs
- mov word [l_dpmi_segs+2],ds
- mov word [l_dpmi_segs+4],es
- mov word [l_dpmi_segs+6],ss
-
- ; SI:DI (16-bit) or SI:EDI (32-bit) protected mode to real mode entry point
- cmp byte [l_dpmi_mode],32
- jnz .store_16
- ; 32-bit storage, and return
- mov dword [l_dpmi_rm_entry+0],edi
- mov word [l_dpmi_rm_entry+4],si
- pop dx ; restore SS into DX. DX will become SS
- pop ax ; restore CS into AX. AX will become DS
- mov cx,ax ; CX will become ES
- mov si,ax ; SI will become CS
- mov bx,sp ; BX will become SP
- mov di,.exit_ok ; DI will become IP, so direct it at the exit point below
- jmp far dword [l_dpmi_rm_entry]
-.store_16:
- ; 16-bit storage, and return
- mov word [l_dpmi_rm_entry+0],di
- mov word [l_dpmi_rm_entry+2],si
- pop dx ; restore SS into DX. DX will become SS
- pop ax ; restore CS into AX. AX will become DS
- mov cx,ax ; CX will become ES
- mov si,ax ; SI will become CS
- mov bx,sp ; BX will become SP
- mov di,.exit_ok ; DI will become IP, so direct it at the exit point below
- jmp far word [l_dpmi_rm_entry]
-; jump back to realmode here
-.exit_ok:
-
-; copy results to host variables
- mov ax,word [cs:l_dpmi_pm_entry]
- mov bx,word [cs:l_dpmi_pm_entry+2]
- mov cx,seg _dpmi_pm_entry
- mov ds,cx
- mov word [_dpmi_pm_entry+0],ax
- mov word [_dpmi_pm_entry+2],bx
-
- mov ax,word [cs:l_dpmi_rm_entry]
- mov bx,word [cs:l_dpmi_rm_entry+2]
- mov cx,word [cs:l_dpmi_rm_entry+4]
- mov dx,seg _dpmi_rm_entry
- mov ds,dx
- mov word [_dpmi_rm_entry+0],ax
- mov word [_dpmi_rm_entry+2],bx
- mov word [_dpmi_rm_entry+4],cx
-
- mov ax,word [cs:l_dpmi_segs+0]
- mov dx,seg _dpmi_pm_cs
- mov ds,dx
- mov word [_dpmi_pm_cs],ax
-
- mov ax,word [cs:l_dpmi_segs+2]
- mov dx,seg _dpmi_pm_ds
- mov ds,dx
- mov word [_dpmi_pm_ds],ax
-
- mov ax,word [cs:l_dpmi_segs+4]
- mov dx,seg _dpmi_pm_es
- mov ds,dx
- mov word [_dpmi_pm_es],ax
-
- mov ax,word [cs:l_dpmi_segs+6]
- mov dx,seg _dpmi_pm_ss
- mov ds,dx
- mov word [_dpmi_pm_ss],ax
-
- ; now that DPMI is active, we have to hook real-mode INT 21h
- ; to catch program termination, so we can forward that to the DPMI
- ; server for proper DPMI cleanup
- call dpmi_hook_int21
-
- pop es
- pop ds
- popa
- popf
- retnative
- %endif
-%endif
-
-; INT 21h hook:
-; We use DPMI entry and thunking back to real mode to let the host
-; program remain 16-bit. BUT: there's a problem. if the host program
-; exits normally with INT 21h via real mode, the DPMI server never gets
-; the message and it remains stuck running in the background. To make
-; DPMI exit normally, we have to hook INT 21h and reflect AH=0x4C to
-; protected mode.
-%ifndef TARGET_WINDOWS
- %if TARGET_MSDOS == 16
-old_int21h dd 0
-dpmi_hook_int21:
- push es
- push ax
- push bx
- push cx
- xor ax,ax
- mov es,ax
- mov ax,cs
- mov bx,word [es:(0x21*4)]
- mov cx,word [es:(0x21*4)+2]
- mov word [es:(0x21*4)],dpmi_int21_hook_exit
- mov word [es:(0x21*4)+2],ax
- mov word [cs:old_int21h+0],bx
- mov word [cs:old_int21h+2],cx
-
- ; also keep track of this process's PSP segment, so we can readily
- ; identify WHO is calling INT 21h AH=0x4C and forward to DPMI only
- ; for our process, not any other process.
- mov ah,0x62
- int 21h
- mov word [cs:this_process_psp],bx
-
- pop cx
- pop bx
- pop ax
- pop es
- ret
-
-; Our INT 21h hook. We're looking for any INT 21h AH=0x4C call coming from
-; this process. If the call comes from any other program in memory, the call
-; is forwarded without modification, so that DPMI does not prematurely exit
-; when subprocesses started by this program terminate.
-;
-; This hack seems silly but apparently most DPMI servers do not monitor real-mode
-; INT 21h for the AH=0x4C call. If they never see the termination call from
-; protected mode, then they never clean up for this process and in most cases
-; (especially Windows) end up leaking selectors and other resources. So to avoid
-; memory leaks, we must forward INT 21h AH=0x4C to the protected mode side of
-; the DPMI server.
-;
-; TODO: This hook should also catch INT 21h AH=31 Terminate and Stay Resident,
-; DPMI needs to keep those too!
-;
-; FIXME: How will this code catch cases where the calling program calls INT 21h
-; from protected mode to terminate? Worst case scenario: DPMI cleans up
-; and we never get a chance to remove our INT 21h hook.
-dpmi_int21_hook_exit:
- cmp ah,0x4C
- jz .catch_exit
- jmp far word [cs:old_int21h]
-.catch_exit:
- ; this is our process terminating, not some subprocess, right?
- ; we want to forward termination only for this process, not anyone else.
- push ax
- push bx
- mov ah,0x62 ; get PSP segment
- int 21h
- cmp bx,word [cs:this_process_psp]
- jz .catch_exit_psp
- pop bx
- pop ax
- jmp far word [cs:old_int21h]
-.catch_exit_psp:
- pop bx
- pop ax
- ; restore the old vector
- push es
- push ax
- push bx
- push cx
- xor ax,ax
- mov es,ax
- mov ax,cs
- mov bx,word [cs:old_int21h+0]
- mov cx,word [cs:old_int21h+2]
- mov word [es:(0x21*4)],bx
- mov word [es:(0x21*4)+2],cx
- pop cx
- pop bx
- pop ax
- pop es
- ; OK. Switch into protected mode.
- ; use the segment values given to us by the DPMI server.
- cli
- mov bp,ax ; save AX
- mov ax,word [cs:l_dpmi_segs+2] ; AX becomes DS (so load DS from DPMI env)
- mov cx,ax ; CX becomes ES
- mov dx,ax ; DX becomes SS (doesn't matter)
- mov bx,sp ; BX becomes SP (doesn't matter)
- mov si,word [cs:l_dpmi_segs+0] ; SI becomes CS (so load CS from DPMI env)
- mov di,.catch_exit_pmode ; DI becomes IP
- jmp far word [cs:l_dpmi_pm_entry]
-.catch_exit_pmode:
- mov ax,bp
- mov ah,0x4C
- int 21h ; now issue INT 21h AH=0x4C where the DPMI server can see it
- hlt
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef TARGET_WINDOWS
-
-; WARNING: The caller must have ensured we are running on a 386 or higher, and that
-; the DPMI entry points were obtained
-
-; __cdecl: right-to-left argument passing (meaning: caller does "push sz", "push lsrc", "push dst"...)
-l_lin2fm_params:
-l_lin2fm_param_dst: dd 0 ; unsigned char far *dst
-l_lin2fm_param_lsrc: dd 0 ; uint32_t lsrc
-l_lin2fm_param_sz: dd 0 ; uint32_t sz
- ; = 12 bytes
-
-l_rm_ret dw 0
-l_rm_reentry dd 0
- dw 0
-
-; TODO: Export these so they are visible as C variables
-; we need these selectors for copy operation
-l_lin2fm_src_sel dw 0
-l_lin2fm_dst_sel dw 0
-
-; dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss
-; int __cdecl dpmi_lin2fmemcpy_32(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-global _dpmi_lin2fmemcpy_32
-_dpmi_lin2fmemcpy_32:
- push bp
- mov bp,sp
-
- ; copy params, we need them in protected mode
- mov eax,dword [bp+cdecl_param_offset+0]
- mov dword [cs:l_lin2fm_params+0],eax
- mov eax,dword [bp+cdecl_param_offset+4]
- mov dword [cs:l_lin2fm_params+4],eax
- mov eax,dword [bp+cdecl_param_offset+8]
- mov dword [cs:l_lin2fm_params+8],eax
-
- pusha ; save all regs
-
- push ds
- push es
-
- push cs ; realmode re-entry needs this
- push ss ; realmode re-entry needs this
- push ds ; realmode re-entry needs this
-
- mov ax,seg _dpmi_pm_entry
- mov ds,ax
-
- xor ax,ax
- mov word [cs:l_rm_ret],ax
-
- mov eax,dword [_dpmi_rm_entry+0]
- mov dword [cs:l_rm_reentry+0],eax
-
- mov ax,word [_dpmi_rm_entry+4]
- mov word [cs:l_rm_reentry+4],ax
-
- mov ax,word [_dpmi_pm_ds]
- mov cx,ax
- mov dx,word [_dpmi_pm_ss]
- mov bx,sp
- mov si,word [_dpmi_pm_cs]
- mov di,.entry_pm
- call far word [_dpmi_pm_entry]
- ; didn't make it. error return
- add sp,6 ; do not restore SS+CS+DS, just discard
- pop es
- pop ds
- popa
- pop bp
- xor ax,ax ; return 0 == no copy made
- retnative
-.entry_pm:
-
- ; we need to allocate two selectors to do the copy operation with
- cmp word [l_lin2fm_src_sel],0
- jnz .sel_avail ; if != 0, then skip code
- ; allocate two descriptors
- xor ax,ax
- mov cx,2
- int 31h
- jnc .sel_alloced ; if carry clear, continue
- jmp .go_to_exit_pm ; else return to RM with retval == 0
-.sel_alloced:
- ; we got two descriptors, store them
- mov word [l_lin2fm_src_sel],ax
- add ax,8 ; obviously...
- mov word [l_lin2fm_dst_sel],ax
- ; we need to make them data selectors
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_src_sel]
- mov cl,0xF0 ; P=1 DPL=3 data expand-up r/o. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_src_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
- ; and the other one
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_dst_sel]
- mov cl,0xF2 ; P=1 DPL=3 data expand-up r/w. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_dst_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
-.sel_avail:
- ; OK, pull in source address (flat) from param and set the selector base
- mov ax,0x0007
- mov bx,word [l_lin2fm_src_sel]
- mov dx,word [l_lin2fm_param_lsrc+0] ; CX:DX = base
- mov cx,word [l_lin2fm_param_lsrc+2]
- int 31h
- ; and the dest address (realmode seg:off) too
- movzx eax,word [l_lin2fm_param_dst+2]
- shl eax,4
- movzx ebx,word [l_lin2fm_param_dst+0]
- add eax,ebx
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,word [l_lin2fm_dst_sel]
- mov ax,0x0007
- int 31h
- ; alright then, do the memcpy
- mov cx,word [l_lin2fm_param_sz]
- mov word [l_rm_ret],cx ; set return value too
- push ds
- push es
- cld
- mov ax,word [l_lin2fm_src_sel]
- mov bx,word [l_lin2fm_dst_sel]
- mov ds,ax
- mov es,bx
- xor si,si
- mov di,si
- rep movsb ; ES:DI <- DS:SI
- pop es
- pop ds
-.go_to_exit_pm:
- ; NTS: when dpmi_enter_core() did it's job it made sure DS == CS
- ; so the DPMI server would make DS an alias of CS in protected mode
- pop ax ; AX = realmode DS
- mov cx,ax
- pop dx ; DX = realmode SS
- pop si ; SI = realmode CS
- mov bx,sp
- mov di,.exit_pm
- call far dword [l_rm_reentry] ; NTS: We're using the 32-bit DPMI server, the RM entry point is 16:32 format
-.exit_pm: ; NTS: Don't forget CS+DS+SS was pushed but the PM part popped them as part of returning
- pop es
- pop ds
- popa
-
- pop bp
- mov ax,word [cs:l_rm_ret]
- retnative
-
-; NOTE: This version of the code is written to work with 16-bit DPMI servers,
-; and to work within the constraint that we could be run on a 286 where
-; 32-bit registers are not available.
-; dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss
-; int __cdecl dpmi_lin2fmemcpy_16(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-global _dpmi_lin2fmemcpy_16
-_dpmi_lin2fmemcpy_16:
- push bp
- mov bp,sp
-
- ; copy params, we need them in protected mode
- mov ax,word [bp+cdecl_param_offset+0]
- mov word [cs:l_lin2fm_params+0],ax
- mov ax,word [bp+cdecl_param_offset+2]
- mov word [cs:l_lin2fm_params+2],ax
- mov ax,word [bp+cdecl_param_offset+4]
- mov word [cs:l_lin2fm_params+4],ax
- mov ax,word [bp+cdecl_param_offset+6]
- mov word [cs:l_lin2fm_params+6],ax
- mov ax,word [bp+cdecl_param_offset+8]
- mov word [cs:l_lin2fm_params+8],ax
- mov ax,word [bp+cdecl_param_offset+10]
- mov word [cs:l_lin2fm_params+10],ax
-
- pusha ; save all regs
-
- push ds
- push es
-
- push cs ; realmode re-entry needs this
- push ss ; realmode re-entry needs this
- push ds ; realmode re-entry needs this
-
- mov ax,seg _dpmi_pm_entry
- mov ds,ax
-
- xor ax,ax
- mov word [cs:l_rm_ret],ax
-
- mov eax,dword [_dpmi_rm_entry+0]
- mov dword [cs:l_rm_reentry+0],eax
-
- mov ax,word [_dpmi_rm_entry+4]
- mov word [cs:l_rm_reentry+4],ax
-
- mov ax,word [_dpmi_pm_ds]
- mov cx,ax
- mov dx,word [_dpmi_pm_ss]
- mov bx,sp
- mov si,word [_dpmi_pm_cs]
- mov di,.entry_pm
- call far word [_dpmi_pm_entry]
- ; didn't make it. error return
- add sp,6 ; do not restore SS+CS+DS, just discard
- pop es
- pop ds
- popa
- pop bp
- xor ax,ax ; return 0 == no copy made
- retnative
-.entry_pm:
-
- ; we need to allocate two selectors to do the copy operation with
- cmp word [l_lin2fm_src_sel],0
- jnz .sel_avail ; if != 0, then skip code
- ; allocate two descriptors
- xor ax,ax
- mov cx,2
- int 31h
- jnc .sel_alloced ; if carry clear, continue
- jmp .go_to_exit_pm ; else return to RM with retval == 0
-.sel_alloced:
- ; we got two descriptors, store them
- mov word [l_lin2fm_src_sel],ax
- add ax,8 ; obviously...
- mov word [l_lin2fm_dst_sel],ax
- ; we need to make them data selectors
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_src_sel]
- mov cl,0xF0 ; P=1 DPL=3 data expand-up r/o. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_src_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
- ; and the other one
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_dst_sel]
- mov cl,0xF2 ; P=1 DPL=3 data expand-up r/w. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_dst_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
-.sel_avail:
- ; OK, pull in source address (flat) from param and set the selector base
- mov ax,0x0007
- mov bx,word [l_lin2fm_src_sel]
- mov dx,word [l_lin2fm_param_lsrc+0] ; CX:DX = base
- mov cx,word [l_lin2fm_param_lsrc+2]
- int 31h
- ; and the dest address (realmode seg:off) too
- mov dx,word [l_lin2fm_param_dst+2] ; DX = (seg << 4) + offset, CX = (seg >> 12) + (carry flag result of computing DX)
- mov cx,dx
- shr cx,12
- shl dx,4
- add dx,word [l_lin2fm_param_dst+0]
- adc cx,0 ; CX:DX = 32-bit linear address
- mov bx,word [l_lin2fm_dst_sel]
- mov ax,0x0007
- int 31h
- ; alright then, do the memcpy
- mov cx,word [l_lin2fm_param_sz]
- mov word [l_rm_ret],cx ; set return value too
- push ds
- push es
- cld
- mov ax,word [l_lin2fm_src_sel]
- mov bx,word [l_lin2fm_dst_sel]
- mov ds,ax
- mov es,bx
- xor si,si
- mov di,si
- rep movsb ; ES:DI <- DS:SI
- pop es
- pop ds
-.go_to_exit_pm:
- ; NTS: when dpmi_enter_core() did it's job it made sure DS == CS
- ; so the DPMI server would make DS an alias of CS in protected mode
- pop ax ; AX = realmode DS
- mov cx,ax
- pop dx ; DX = realmode SS
- pop si ; SI = realmode CS
- mov bx,sp
- mov di,.exit_pm
- call far word [l_rm_reentry] ; NTS: We're using the 16-bit DPMI server, the RM entry point is 16:16 format
-.exit_pm: ; NTS: Don't forget CS+DS+SS was pushed but the PM part popped them as part of returning
- pop es
- pop ds
- popa
-
- pop bp
- mov ax,word [cs:l_rm_ret]
- retnative
-
- %endif
-%endif
+++ /dev/null
-/* dosbox.c
- *
- * Detect whether or not we're running under the DOSBox emulator
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-static const char *dosbox_fakebios = "DOSBox FakeBIOS v1.0";
-#endif
-
-/* the ROM area doesn't change. so remember our last result */
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-static signed char dosbox_detect_cache = -1;
-#endif
-
-int detect_dosbox_emu() {
-#if defined(TARGET_OS2)
- /* TODO: So... how does one read the ROM BIOS area from OS/2? */
- return 0;
-#elif defined(TARGET_WINDOWS)
- /* TODO: I know that from within Windows there are various ways to scan the ROM BIOS area.
- * Windows 1.x and 2.x (if real mode) we can just use MK_FP as we do under DOS, but
- * we have to use alternate means if Windows is in protected mode. Windows 2.x/3.x protected
- * mode (and because of compatibility, Windows 95/98/ME), there are two methods open to us:
- * One is to use selector constants that are hidden away in KRNL386.EXE with names like _A0000,
- * _B0000, etc. They are data selectors that when loaded into the segment registers point to
- * their respective parts of DOS adapter ROM and BIOS ROM. Another way is to use the Win16
- * API to create a data selector that points to the BIOS. Windows 386 Enhanced mode may map
- * additional things over the unused parts of adapter ROM, but experience shows that it never
- * relocates or messes with the VGA BIOS or with the ROM BIOS,
- *
- * My memory is foggy at this point, but I remember that under Windows XP SP2, one of the
- * above Win16 methods still worked even from under the NT kernel.
- *
- * For Win32 applications, if the host OS is Windows 3.1 Win32s or Windows 95/98/ME, we can
- * take advantage of a strange quirk in the way the kernel maps the lower 1MB. For whatever
- * reason, the VGA RAM, adapter ROM, and ROM BIOS areas are left open even for Win32 applications
- * with no protection. Thus, a Win32 programmer can just make a pointer like
- * char *a = (char*)0xA0000 and scribble on legacy VGA RAM to his heart's content (though on
- * modern PCI SVGA hardware the driver probably instructs the card to disable VGA compatible
- * mapping). In fact, this ability to scribble on RAM directly is at the heart of one of Microsoft's
- * earliest and hackiest "Direct Draw" interfaces known as "DISPDIB.DLL", a not-to-well documented
- * library responsible for those Windows 3.1 multimedia apps and games that were somehow able to
- * run full-screen 320x200x256 color VGA despite being Windows GDI-based apps. Ever wonder how the
- * MCI AVI player was able to go full-screen when DirectX and WinG were not invented yet? Now you
- * know :)
- *
- * There are some VFW codecs out there as well, that also like to abuse DISPDIB.DLL for "fullscreen"
- * modes. One good example is the old "Motion Pixels" codec, that when asked to go fullscreen,
- * uses DISPDIB.DLL and direct VGA I/O port trickery to effectively set up a 320x480 256-color mode,
- * which it then draws on "fake hicolor" style to display the video (though a bit dim since you're
- * sort of watching a video through a dithered mesh, but...)
- *
- * In case you were probably wondering, no, Windows NT doesn't allow Win32 applications the same
- * privilege. Win32 apps writing to 0xA0000 would page fault and crash. Curiously enough though,
- * NTVDM.EXE does seem to open up the 0xA0000-0xFFFFF memory area to Win16 applications if they
- * use the right selectors and API calls. */
- return 0;
-#else
- int i;
-# if TARGET_MSDOS == 32
- const char *scan;
-# else
- const char far *scan;
-# endif
-
- probe_dos();
- if (dosbox_detect_cache >= 0)
- return (int)dosbox_detect_cache;
-
-# if TARGET_MSDOS == 32
- if (dos_flavor == DOS_FLAVOR_FREEDOS) {
- /* FIXME: I have no idea why but FreeDOS 1.0 has a strange conflict with DOS32a where if this code
- * tries to read the ROM BIOS it causes a GPF and crashes (or sometimes runs off into the
- * weeds leaving a little garbage on the screen). DOS32a's register dump seems to imply that
- * at one point our segment limits were suddenly limited to 1MB (0xFFFFF). I have no clue
- * what the hell is triggering it, but I know from testing we can avoid that crash by not
- * scanning. */
- if (freedos_kernel_version == 0x000024UL) /* 0.0.36 */
- return (dosbox_detect_cache=0);
- }
-# endif
-
-/* signs that we're running under DOSBOX:
- * - the majority of the adapter ROM area is 0x00 (not 0xFF or any other value). Here we check 0xE000:0xFF00 and 0xF000:0x000.
- * - an ASCII string is visible at 0xF000:0xE061: "DOSBox FakeBIOS v1.0" */
-
-# if TARGET_MSDOS == 32
- scan = (const char*)0xEFF00UL;
-# else
- scan = (const char far*)MK_FP(0xE000,0xFF00);
-# endif
-
- for (i=0;i < 256;i++) {
- if (scan[i] != 0)
- return (dosbox_detect_cache=0);
- }
-
-# if TARGET_MSDOS == 32
- scan = (const char*)0xF0000UL;
-# else
- scan = (const char far*)MK_FP(0xF000,0x0000);
-# endif
- for (i=0;i < 256;i++) {
- if (scan[i] != 0)
- return (dosbox_detect_cache=0);
- }
-
-# if TARGET_MSDOS == 32
- scan = (const char*)0xFE061UL;
-# else
- scan = (const char far*)MK_FP(0xF000,0xE061);
-# endif
- i = 0;
- do {
- if (dosbox_fakebios[i] != scan[i])
- return (dosbox_detect_cache=0);
- } while (dosbox_fakebios[i++] != 0);
-
- return (dosbox_detect_cache=1);
-#endif
-}
-
+++ /dev/null
-/* dosbox.h
- *
- * Detect whether or not we're running under the DOSBox emulator
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdint.h>
-
-int detect_dosbox_emu();
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-int dos_device_next(struct dos_device_enum *e) {
- e->raw = e->next;
- if (e->raw == NULL || e->count >= 512 || e->no == 0xFFFFU)
- return 0;
-
- e->no = *((uint16_t FAR*)(e->raw + 0x0));
- e->ns = *((uint16_t FAR*)(e->raw + 0x2));
- e->attr = *((uint16_t FAR*)(e->raw + 0x04));
- e->entry = *((uint16_t FAR*)(e->raw + 0x06));
- e->intent = *((uint16_t FAR*)(e->raw + 0x08));
- if (!(e->attr & 0x8000)) {
- /* block device */
- _fmemcpy(e->name,e->raw+0x0B,8); e->name[7] = 0;
- if (e->name[0] < 33 || e->name[0] >= 127) e->name[0] = 0;
- }
- else {
- /* char device */
- _fmemcpy(e->name,e->raw+0x0A,8); e->name[8] = 0;
- }
- e->count++;
-
-#if TARGET_MSDOS == 32
- e->next = (unsigned char*)((((uint32_t)(e->ns)) << 4UL) + e->no);
-#else
- e->next = (unsigned char FAR*)MK_FP(e->ns,e->no);
-#endif
-
- return 1;
-}
-
-int dos_device_first(struct dos_device_enum *e) {
- unsigned int offset = 0x22; /* most common, DOS 3.1 and later */
-
- if (dos_LOL == NULL)
- return 0;
-
- if (dos_version < 0x200) /* We don't know where the first device is in DOS 1.x */
- return 0;
- else if (dos_version < 0x300)
- offset = 0x17;
- else if (dos_version == 0x300)
- offset = 0x28;
-
- e->no = 0;
- e->ns = 0;
- e->count = 0;
- e->raw = e->next = dos_LOL + offset;
- if (_fmemcmp(e->raw+0xA,"NUL ",8) != 0) /* should be the NUL device driver */
- return 0;
-
- return dos_device_next(e);
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-int8_t dpmi_no_0301h = -1; /* whether or not the DOS extender provides function 0301h */
-#endif
-
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
-uint16_t dpmi_flags=0;
-uint16_t dpmi_version=0;
-unsigned char dpmi_init=0;
-uint32_t dpmi_entry_point=0;
-unsigned char dpmi_present=0;
-unsigned char dpmi_processor_type=0;
-uint16_t dpmi_private_data_length_paragraphs=0;
-uint16_t dpmi_private_data_segment=0xFFFF; /* when we DO enter DPMI, we store the private data segment here. 0 = no private data. 0xFFFF = not yet entered */
-unsigned char dpmi_entered = 0; /* 0=not yet entered, 16=entered as 16bit, 32=entered as 32bit */
-uint64_t dpmi_rm_entry = 0;
-uint32_t dpmi_pm_entry = 0;
-
-/* once having entered DPMI, keep track of the selectors registers given to us in p-mode */
-uint16_t dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss;
-
-void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
-#endif
-
-/* 16-bit real mode DOS or 16-bit protected mode Windows */
-void probe_dpmi() {
-#if defined(TARGET_OS2)
- /* OS/2 apps do not run under DPMI */
-#elif TARGET_MSDOS == 32 && defined(TARGET_WINDOWS)
- /* Win32 apps do not bother with DPMI */
-#else
- if (!dpmi_init) {
- /* BUGFIX: WINE (Wine Is Not an Emulator) can run Win16 applications
- * but does not emulate the various low level interrupts one
- * can call. To avoid crashing under WINE we must not use
- * direct interrupts. */
- if (windows_emulation == WINEMU_WINE) {
- dpmi_present = 0;
- dpmi_init = 1;
- return;
- }
-
- {
- unsigned char present=0,proc=0;
- uint16_t version=0,privv=0,flags=0;
- uint32_t entry=0;
-
- __asm {
- push es
- mov ax,0x1687
- int 2Fh
- or ax,ax
- jnz err1
- mov present,1
- mov flags,bx
- mov proc,cl
- mov version,dx
- mov privv,si
- mov word ptr [entry+0],di
- mov word ptr [entry+2],es
- pop es
-err1:
- }
-
- dpmi_flags = flags;
- dpmi_present = present;
- dpmi_version = version;
- dpmi_entry_point = entry;
- dpmi_processor_type = proc;
- dpmi_private_data_segment = 0xFFFF;
- dpmi_private_data_length_paragraphs = privv;
- }
-
-#if TARGET_MSDOS == 32 || defined(TARGET_WINDOWS)
- /* when we ask for the "entry point" we mean we want the real-mode entrypoint.
- * apparently some DPMI servers like Windows XP+NTVDM.EXE translate ES:DI coming
- * back to a protected mode entry point, which is not what we're looking for.
- *
- * Interesting fact: When compiled as a Win16 app, the DPMI call actually works,
- * but returns an entry point appropriate for Win16 apps. So.... apparently we
- * can enter DPMI protected mode from within Win16? Hmm.... that might be something
- * fun to experiment with :) */
- if (dpmi_present) {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x1687;
- mux_realmode_2F_call(&rc);
- if ((rc.eax&0xFFFF) == 0) {
- dpmi_flags = rc.ebx&0xFFFF;
- dpmi_present = 1;
- dpmi_version = rc.edx&0xFFFF;
- dpmi_entry_point = (((uint32_t)rc.es << 16UL) & 0xFFFF0000UL) + (uint32_t)(rc.edi&0xFFFFUL);
- dpmi_processor_type = rc.ecx&0xFF;
- dpmi_private_data_segment = 0xFFFF;
- dpmi_private_data_length_paragraphs = rc.esi&0xFFFF;
- }
- else {
- dpmi_present = 0;
- }
- }
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
- dpmi_no_0301h = 0;
-#endif
- dpmi_init = 1;
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
- if (dpmi_present) {
- /* Thanks to bullshit like DOS4/GW we have to test the extender to know
- whether or not core routines we need are actually there or not. If they
- are not, then alternative workarounds are required. The primary reason
- for this test is to avoid HIMEM.SYS API code returning nonsensical values
- caused by DOS4/GW not supporting such vital functions as DPMI 0301H:
- Call far real-mode procedure. Knowing this should also fix the VESA BIOS
- test bug where the protected-mode version is unable to use the BIOS's
- direct-call window bank-switching function.
-
- At least, this code so far can rely on DPMI function 0300H: call real-mode
- interrupt.*/
-
- /* test #1: allocate a 16-bit region, put a RETF instruction there,
- and ask the DPMI server to call it (0301H test).
-
- Success:
- Registers unchanged
- CF=0
-
- Failure (DOS4/GW):
- CF=1
- AX=0301H (wait wha?) */
- {
- uint16_t sel = 0;
- struct dpmi_realmode_call rc={0};
- unsigned char *proc = dpmi_alloc_dos(16,&sel);
- if (proc != NULL) {
- *proc = 0xCB; /* <- RETF */
-
- rc.cs = ((size_t)proc) >> 4UL;
- rc.ip = ((size_t)proc) & 0xFUL;
- if (dpmi_test_rm_entry_call(&rc) != 0)
- dpmi_no_0301h = 1;
-
- dpmi_free_dos(sel);
- }
- }
- }
-#endif
- }
-#endif
-}
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS)
-int dpmi_private_alloc() {
- unsigned short sss=0;
-
- if (!dpmi_present || dpmi_private_data_segment != 0xFFFFU)
- return 1; /* OK, nothing to do */
-
- if (dpmi_private_data_length_paragraphs == 0) {
- dpmi_private_data_segment = 0;
- return 0;
- }
-
- __asm {
- push ds
- mov ah,0x48
- mov bx,seg dpmi_private_data_length_paragraphs
- mov ds,bx
- mov bx,dpmi_private_data_length_paragraphs
- int 21h
- pop ds
- jc fail1
- mov sss,ax
-fail1:
- }
-
- if (sss == 0)
- return 0;
-
- dpmi_private_data_segment = sss;
- return 1;
-}
-
-/* NTS: This enters DPMI. There is no exit from DPMI. And if you re-enter DPMI by switching back to protected mode,
- * you only serve to confuse the server somewhat.
- *
- * Re-entry results:
- * - Windows XP: Allows it, even going 16 to 32 bit mode, but the console window gets confused and drops our
- * output when changing bit size.
- * - Windows 9x: Allows it, doesn't allow changing bit mode, so once in 16-bit mode you cannot enter 32-bit mode.
- * The mode persists until the DOS Box exits.
- *
- * This also means that once you init in one mode, you cannot re-enter another mode. If you init in 16-bit DPMI,
- * you cannot init into 32-bit DPMI.
- *
- * If all you want is the best mode, call with mode == 0xFF instead to automatically select. */
-int dpmi_enter(unsigned char mode) {
-/* TODO: Cache results, only need to scan once */
- if (mode == 0xFF) {
- if ((cpu_basic_level == -1 || cpu_basic_level >= 3) && (dpmi_flags&1) == 1)
- mode = 32; /* if 32-bit capable DPMI server and 386 or higher, choose 32-bit */
- else
- mode = 16; /* for all else, choose 16-bit */
- }
-
- if (dpmi_entered != 0) {
- if (dpmi_entered != mode) return 0;
- return 1;
- }
-
- if (mode != 16 && mode != 32)
- return 0;
- if (mode == 32 && !(dpmi_flags & 1))
- return 0;
- if (dpmi_entry_point == 0)
- return 0;
- if (!dpmi_private_alloc())
- return 0;
- if (dpmi_private_data_length_paragraphs != 0 && dpmi_private_data_segment == 0)
- return 0;
- if (dpmi_private_data_segment == 0xFFFFU)
- return 0;
-
- dpmi_entered = mode;
- dpmi_enter_core();
- return (dpmi_entered != 0); /* NTS: dpmi_enter_core() will set dpmi_entered back to zero on failure */
-}
-#endif
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* TODO: Switch into DPMI protected mode, allocate and setup selectors, do memcpy to
- * DOS realmode segment, then return to real mode. When the code is stable,
- * move it into hw/dos/dos.c. The purpose of this code is to allow 16-bit realmode
- * DOS programs to reach into DPMI linear address space, such as the Win 9x
- * kernel area when run under the Win 9x DPMI server. */
-int dpmi_lin2fmemcpy(unsigned char far *dst,uint32_t lsrc,uint32_t sz) {
- if (dpmi_entered == 32)
- return dpmi_lin2fmemcpy_32(dst,lsrc,sz);
- else if (dpmi_entered == 16) {
- _fmemset(dst,0,sz);
- return dpmi_lin2fmemcpy_16(dst,lsrc,sz);
- }
-
- return 0;
-}
-
-int dpmi_lin2fmemcpy_init() {
- probe_dpmi();
- if (!dpmi_present)
- return 0;
- if (!dpmi_enter(DPMI_ENTER_AUTO))
- return 0;
-
- return 1;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-const char *windows_emulation_str(uint8_t e) {
- switch (e) {
- case WINEMU_NONE: return "None";
- case WINEMU_WINE: return "WINE (Wine Is Not an Emulator)";
- default: break;
- }
-
- return "?";
-}
-
-const char *dos_flavor_str(uint8_t f) {
- switch (f) {
- case DOS_FLAVOR_NONE: return "None";
- case DOS_FLAVOR_MSDOS: return "MS-DOS";
- case DOS_FLAVOR_FREEDOS: return "FreeDOS";
- }
-
- return "?";
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && defined(WIN386) /* Watcom Win386 does NOT translate LPARAM for us */
-void far *win386_alt_winnt_MapAliasToFlat(DWORD farptr) {
- /* FIXME: This only works by converting a 16:16 pointer directly to 16:32.
- * It works perfectly fine in QEMU and DOSBox, but I seem to remember something
- * about the x86 architecture and possible ways you can screw up using 16-bit
- * data segments with 32-bit code. Are those rumors true? Am I going to someday
- * load up Windows 3.1/95 on an ancient PC and find out this code crashes
- * horribly or has random problems?
- *
- * We need this alternate path for Windows NT/2000/XP/Vista/7 because NTVDM.EXE
- * grants Watcom386 a limited ~2GB limit for the flat data segment (usually
- * 0x7B000000 or something like that) instead of the full 4GB limit the 3.x/9x/ME
- * kernels usually grant. This matters because without the full 4GB limit we can't
- * count on overflow/rollover to reach below our data segment base. Watcom386's
- * MapAliasToFlat() unfortunately assumes just that. If we were to blindly rely
- * on it, then we would work just fine under 3.x/9x/ME but crash under
- * NT/2000/XP/Vista/7 the minute we need to access below our data segment (such as,
- * when handling the WM_GETMINMAXINFO message the LPARAM far pointer usually
- * points somewhere into NTVDM.EXE's DOS memory area when we're usually located
- * at the 2MB mark or so) */
- return MK_FP(farptr>>16,farptr&0xFFFF);
-}
-
-void far *win386_help_MapAliasToFlat(DWORD farptr) {
- if (windows_mode == WINDOWS_NT)
- return win386_alt_winnt_MapAliasToFlat(farptr);
-
- return (void far*)MapAliasToFlat(farptr); /* MapAliasToFlat() returns near pointer, convert to far! */
-}
-#endif
-
+++ /dev/null
-/* dosntast.c
- *
- * Windows NT VDD driver, dynamically loaded by code that needs it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * This driver when loaded allows the DOS program to call Windows NT APIs
- * such as version information or to use the WINMM WAVE API instead of
- * NTVDM.EXE's shitty Sound Blaster emulation.
- */
-
-/* This is a Windows NT VDD driver */
-#define NTVDM_VDD_DRIVER
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-#include <i86.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <windows/ntvdm/ntvdmlib.h>
-#include <windows/ntvdm/ntvdmvdd.h>
-
-#define DEBUG
-
-/* this is a DLL for Win32 */
-#if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
-# error this is a DLL for Win32 only
-#endif
-
-static HMODULE this_vdd = 0;
-
-/* If the DOS portion of this code calls NTVDM.EXE to load the same DLL again, NTVDM.EXE
- * will do it, and allocate another handle. We'd rather not waste handles, so we leave
- * a "mark" in the BIOS data area for the DOS program to find and know whether we're
- * already loaded, and what handle to use. */
-static unsigned int vm_marked = 0;
-
-/* since 32-bit DOS builds must thunk to 16-bit mode to make calls, we use "fake" I/O
- * ports to control other aspects such as sound output to make it easier for the DOS
- * portion's interrupt controller to do it's job. But we never assume a fixed I/O port
- * base because, who knows, the user's NTVDM environment may have special VDD drivers
- * loaded. */
-static uint16_t vm_io_base = 0;
-#define VM_IO_PORTS 0x20
-
-/* +0x00 (WORD) W/O Function select. */
-/* +0x01 (WORD) W/O Sub-function select. */
-
-/* Interrupt handlers may use these, to save the current state and use the interface themselves
- * before restoring the interface for the code they interrupted.
- *
- * The idea being the DOS program should not have to CLI/STI all the time to avoid conflicts with their
- * own interrupt handlers. */
-
-/* +0x00 (INSB) R/O Read current function/subfunction selection [24 bytes] */
-/* +0x00 (OUTSB) W/O Write current function/subfunction selection [24 bytes] */
-
-#pragma pack(push,1)
-typedef struct {
- uint16_t function; /* +0x00 */
- uint16_t subfunction; /* +0x02 */
- uint16_t __reserved__1; /* +0x04 */
- uint16_t __reserved__2; /* +0x06 */
- uint16_t __reserved__3; /* +0x08 */
- uint16_t __reserved__4; /* +0x0A */
- uint16_t __reserved__5; /* +0x0C */
- uint16_t __reserved__6; /* +0x0E */
- uint16_t __reserved__7; /* +0x10 */
- uint16_t __reserved__8; /* +0x12 */
- uint16_t __reserved__9; /* +0x14 */
- uint16_t __reserved__A; /* +0x16 */
-} IOIF_STATE;
-
-typedef struct {
- WORD (*iop)(WORD param0);
- void (*insb)(BYTE *data,WORD count);
- void (*insw)(WORD *data,WORD count);
- void (*outsb)(BYTE *data,WORD count);
- void (*outsw)(WORD *data,WORD count);
-} IOIF_COMMAND;
-#pragma pack(pop)
-
-/* IO interface state */
-IOIF_STATE io_if={0};
-IOIF_COMMAND* io_if_command=NULL; /* what to do on command */
-
-/* What the fucking hell Watcom?
- * This function obviously never gets called, yet if I don't have it here
- * your linker suddenly decides the standard C libray doesn't exist? What the fuck? */
-BOOL WINAPI DllMain(HINSTANCE hInstance,DWORD fdwReason,LPVOID lpvReserved) {
- /* FIXME: If Watcom demands this function, then why the fuck isn't it getting called on DLL load?
- * What the fuck Open Watcom?!? */
- if (fdwReason == DLL_PROCESS_ATTACH) {
- this_vdd = hInstance;
- }
-
- return TRUE;
-}
-
-/* DOSNTAST_FUNCTION_GENERAL------------------------------------------------------------ */
-static void ioif_function_general_messagebox_outsb(BYTE *data,WORD count) {
- if (io_if.subfunction == DOSNTAST_FUN_GEN_SUB_MESSAGEBOX) {
- /* whatever ASCIIZ string DS:SI points to is passed by NTVDM.EXE to us */
- MessageBoxA(NULL,data,"DOSNTAST.VDD",MB_OK);
- }
-}
-
-static IOIF_COMMAND ioif_command_general_messagebox = {
- /* If only Watcom C/C++ supported GCC's .name = value structure definition style,
- * like what they do in the Linux kernel, we could make this a lot more obvious */
- NULL, /* iop */
- NULL, /* insb */
- NULL, /* insw */
- ioif_function_general_messagebox_outsb, /* outsb */
- NULL /* outsw */
-};
-
-/* this is called when Function == general and selection changes */
-static void ioif_function_general__SELECT() {
- switch (io_if.subfunction) {
- case DOSNTAST_FUN_GEN_SUB_MESSAGEBOX:
- io_if_command = &ioif_command_general_messagebox;
- break;
- default:
- io_if_command = NULL;
- break;
- }
-}
-/* DOSNTAST_FUNCTION_WINMM-------------------------------------------------------------- */
-static WORD ioif_function_winmm_waveOutGetNumDevs_iop(WORD param0) {
- return (WORD)waveOutGetNumDevs();
-}
-
-static IOIF_COMMAND ioif_command_winmm_waveOutGetNumDevs = {
- /* If only Watcom C/C++ supported GCC's .name = value structure definition style,
- * like what they do in the Linux kernel, we could make this a lot more obvious */
- ioif_function_winmm_waveOutGetNumDevs_iop,/* iop */
- NULL, /* insb */
- NULL, /* insw */
- NULL, /* outsb */
- NULL /* outsw */
-};
-
-static void ioif_function_winmm_waveOutOpen_outsb(BYTE *p,WORD count) {
- /* in: EAX = uDeviceID
- * EBX = dwCallbackInstance
- * DS:ESI = pwfx (WAVEFORMATEX*)
- * out: EAX = handle (or 0xFFFFFFFF if error)
- * EBX = error */
- /* TODO */
- setEAX(0xFFFFFFFF);
- setEBX(0xFFFFFFFF);
-}
-
-static IOIF_COMMAND ioif_command_winmm_waveOutOpen = {
- NULL, /* iop */
- NULL, /* insb */
- NULL, /* insw */
- ioif_function_winmm_waveOutOpen_outsb, /* outsb */
- NULL /* outsw */
-};
-
-static void ioif_function_winmm_waveOutGetDevCaps_insb(BYTE *p,WORD count) {
- /* EAX = uDeviceID
- * EBX = cbwoc (sizeof of WAVEOUTCAPS) */
- setEAX(waveOutGetDevCaps(getEAX(),(WAVEOUTCAPS*)p,getEBX()));
-}
-
-static IOIF_COMMAND ioif_command_winmm_waveOutGetDevCaps = {
- NULL, /* iop */
- ioif_function_winmm_waveOutGetDevCaps_insb,/* insb */
- NULL, /* insw */
- NULL, /* outsb */
- NULL /* outsw */
-};
-
-/* this is called when Function == general and selection changes */
-static void ioif_function_winmm__SELECT() {
- switch (io_if.subfunction) {
- case DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs:
- io_if_command = &ioif_command_winmm_waveOutGetNumDevs;
- break;
- case DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps:
- io_if_command = &ioif_command_winmm_waveOutGetDevCaps;
- break;
- case DOSNTAST_FUN_WINMM_SUB_waveOutOpen:
- io_if_command = &ioif_command_winmm_waveOutOpen;
- break;
- default:
- io_if_command = NULL;
- break;
- }
-}
-/* ------------------------------------------------------------------------------------- */
-void ioif_function__SELECT() {
- switch (io_if.function) {
- case DOSNTAST_FUNCTION_GENERAL:
- ioif_function_general__SELECT();
- break;
- case DOSNTAST_FUNCTION_WINMM:
- ioif_function_winmm__SELECT();
- break;
- default:
- io_if_command = NULL;
- }
-}
-
-WORD ioif_command(WORD param0) {
- if (io_if_command != NULL && io_if_command->iop != NULL)
- return io_if_command->iop(param0);
-
- return 0xFFFFU;
-}
-
-void ioif_command_insb(BYTE *data,WORD count) {
- if (io_if_command != NULL && io_if_command->insb != NULL)
- io_if_command->insb(data,count);
-}
-
-void ioif_command_insw(WORD *data,WORD count) {
- if (io_if_command != NULL && io_if_command->insw != NULL)
- io_if_command->insw(data,count);
-}
-
-void ioif_command_outsb(BYTE *data,WORD count) {
- if (io_if_command != NULL && io_if_command->outsb != NULL)
- io_if_command->outsb(data,count);
-}
-
-void ioif_command_outsw(WORD *data,WORD count) {
- if (io_if_command != NULL && io_if_command->outsw != NULL)
- io_if_command->outsw(data,count);
-}
-
-void save_ioif_state(IOIF_STATE *data,WORD count) {
- if (count < sizeof(IOIF_STATE)) return;
- *data = io_if;
-}
-
-void restore_ioif_state(IOIF_STATE *data,WORD count) {
- if (count < sizeof(IOIF_STATE)) return;
- io_if = *data;
- ioif_function__SELECT();
-}
-
-void ioif_function_select(WORD f) {
- /* setting the function resets subfunction to zero */
- io_if.function = f;
- io_if.subfunction = 0;
- ioif_function__SELECT();
-}
-
-void ioif_subfunction_select(WORD f) {
- io_if.subfunction = f;
- ioif_function__SELECT();
-}
-
-/* when a DOS program does REP OUTSW, NTVDM.EXE provides the translated DS:SI for us.
- * Nice. Except... when done from a 32-bit DOS program, it only translates DS:SI for us.
- * Not very good when our DOS code uses *DS:ESI* as a flat 32-bit program!
- *
- * Speaking of which Microsoft why the hell isn't there a function to tell if the DS
- * segment is 16-bit or 32-bit?!?
- *
- * NTS: This code assumes x86 32-bit NTVDM.EXE behavior where DOS memory is mapped to
- * the 0x00000-0xFFFFF area within the NTVDM process. */
-BYTE *NTVDM_DS_ESI_correct(BYTE *p) {
- /* if protected mode, replace the pointer given with a proper pointer to DS:ESI */
- if (getMSW() & 1) {
- /* NTS: x86 behavior: VdmMapFlat() just returns a pointer. There's an
- * "unmap" function but it's a stub. We take advantage of that.
- * No punishment for "mapping" without "unmapping" */
- return (BYTE*)VdmMapFlat(getDS(),getESI(),VDM_PM);
- }
-
- return (BYTE*)p;
-}
-
-BYTE *NTVDM_ES_EDI_correct(BYTE *p) {
- /* if protected mode, replace the pointer given with a proper pointer to DS:ESI */
- if (getMSW() & 1) {
- /* NTS: x86 behavior: VdmMapFlat() just returns a pointer. There's an
- * "unmap" function but it's a stub. We take advantage of that.
- * No punishment for "mapping" without "unmapping" */
- return (BYTE*)VdmMapFlat(getES(),getEDI(),VDM_PM);
- }
-
- return (BYTE*)p;
-}
-
-/* IO handler */
-VOID WINAPI io_inw(WORD iport,WORD *data) {
- if (iport == (vm_io_base+0x00)) /* function select */
- *data = io_if.function;
- else if (iport == (vm_io_base+0x01)) /* subfunction select */
- *data = io_if.subfunction;
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- *data = ioif_command(0xFFFFU);
- else
- *data = 0xFFFF; /* default */
-}
-
-VOID WINAPI io_inb(WORD iport,BYTE *data) {
- {
- WORD w;
- io_inw(iport,&w);
- *data = (BYTE)w; /* default: do whatever our word-size version would and return lower bits */
- }
-}
-
-VOID WINAPI io_insw(WORD iport,WORD *data,WORD count) {
- data = (WORD*)NTVDM_ES_EDI_correct((BYTE*)data);
-
- if (iport == (vm_io_base+0x00))
- save_ioif_state((IOIF_STATE*)data,count*2U); /* FIXME: Microsoft isn't clear: is "count" the count of WORDs? or BYTEs? */
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_insw(data,count);
-}
-
-VOID WINAPI io_insb(WORD iport,BYTE *data,WORD count) {
- data = NTVDM_ES_EDI_correct(data);
-
- if (iport == (vm_io_base+0x00))
- save_ioif_state((IOIF_STATE*)data,count);
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_insb(data,count);
-}
-
-VOID WINAPI io_outw(WORD iport,WORD data) {
- if (iport == (vm_io_base+0x00)) /* function select */
- ioif_function_select(data);
- else if (iport == (vm_io_base+0x01)) /* subfunction select */
- ioif_subfunction_select(data);
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command(data);
-}
-
-VOID WINAPI io_outb(WORD iport,BYTE data) {
- io_outw(iport,data); /* default: pass the byte value up to the word-size callback */
-}
-
-VOID WINAPI io_outsw(WORD iport,WORD *data,WORD count) {
- data = (WORD*)NTVDM_DS_ESI_correct((BYTE*)data);
-
- if (iport == (vm_io_base+0x00))
- restore_ioif_state((IOIF_STATE*)data,count*2U); /* FIXME: Microsoft isn't clear: is "count" the count of WORDs? or BYTEs? */
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_outsw(data,count);
-}
-
-VOID WINAPI io_outsb(WORD iport,BYTE *data,WORD count) {
- data = NTVDM_DS_ESI_correct(data);
-
- if (iport == (vm_io_base+0x00))
- restore_ioif_state((IOIF_STATE*)data,count);
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_outsb(data,count);
-}
-
-static void mark_vm() {
- unsigned char *ptr;
- unsigned int i=0xF0/*start at 0x40:0xF0*/,max=0x200;
-
- if (vm_marked) return;
-
- ptr = VdmMapFlat(0x40,0x00,VDM_V86);
- if (ptr == NULL) return;
-
- /* find an empty spot to place our signature. the client is expected
- * to write the handle value next to it */
- while (i < max) {
- if (!memcmp(ptr+i,"\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0",20))
- break;
-
- i++;
- }
-
- if (i < max)
- memcpy(ptr+i,"DOSNTAST.VDD\xFF\xFF\xFF\xFF",16);
-
- VdmUnmapFlat(0x40,0x00,(DWORD)ptr,VDM_V86);
- vm_marked = i+0x400;
-}
-
-static void remove_vm_mark() {
- unsigned char *ptr;
-
- if (vm_marked >= 0x400 && vm_marked <= 0x600) {
- ptr = VdmMapFlat(0x40,0x00,VDM_V86);
- if (ptr == NULL) return;
-
- memset(ptr+vm_marked-0x400,0,16);
-
- VdmUnmapFlat(0x40,0x00,(DWORD)ptr,VDM_V86);
- vm_marked = 0;
- }
-}
-
-static void choose_io_port() {
- VDD_IO_HANDLERS h;
- VDD_IO_PORTRANGE pr;
-
- if (vm_io_base != 0) return;
-
- /* FIXME: Remove this when Watcom C/C++ actually calls up to DllMain on entry point */
- if (this_vdd == NULL)
- this_vdd = GetModuleHandle("DOSNTAST.VDD");
- if (this_vdd == NULL) {
- MessageBox(NULL,"NO!","",MB_OK);
- return;
- }
-
- h.inb_handler = io_inb;
- h.inw_handler = io_inw;
- h.insb_handler = io_insb;
- h.insw_handler = io_insw;
- h.outb_handler = io_outb;
- h.outw_handler = io_outw;
- h.outsb_handler = io_outsb;
- h.outsw_handler = io_outsw;
-
- /* choose an I/O port */
- for (vm_io_base=0x1000;vm_io_base <= 0xF000;vm_io_base += 0x80) {
- pr.First = vm_io_base;
- pr.Last = vm_io_base + VM_IO_PORTS - 1;
-
- if (VDDInstallIOHook(this_vdd,1/*cPortRange*/,&pr,&h)) {
- /* got it */
- break;
- }
- }
-
- if (vm_io_base > 0xF000) {
- /* didn't find any */
- MessageBox(NULL,"Failed","",MB_OK);
- vm_io_base = 0;
- }
-}
-
-static void remove_io_port() {
- VDD_IO_PORTRANGE r;
-
- if (vm_io_base == 0) return;
- r.First = vm_io_base;
- r.Last = vm_io_base + VM_IO_PORTS - 1;
- VDDDeInstallIOHook(this_vdd,1,&r);
- vm_io_base = 0;
-}
-
-/* Microsoft documentation on this "init" routine is lacking */
-__declspec(dllexport) void WINAPI Init() {
- if (!vm_marked) mark_vm();
- if (vm_io_base == 0) choose_io_port();
-}
-
-__declspec(dllexport) void WINAPI Dispatch() {
- uint32_t command;
- char tmp[64];
-
- command = getEBX();
- if (command == DOSNTAST_INIT_REPORT_HANDLE) {
- setEBX(0x55AA55AA);
- setECX(vm_marked);
- }
- else if (command == DOSNTAST_GETVERSIONEX) {
- unsigned char *ptr = NULL;
- uint16_t seg;
- uint32_t ofs;
- uint8_t mode;
-
- seg = getDS();
- ofs = getESI();
- mode = (getCX() == 1) ? VDM_PM : VDM_V86;
-
- ptr = VdmMapFlat(seg,ofs,mode);
- if (ptr != NULL) {
- setEBX(GetVersionEx((OSVERSIONINFO*)ptr));
- VdmUnmapFlat(seg,ofs,(DWORD)ptr,mode);
- }
- }
- else if (command == DOSNTAST_GET_TICK_COUNT) {
- setEBX(GetTickCount());
- }
- /* the DOS program sends this when it's about to unload us.
- * I originally wanted DllMain to do this on PROCESS_DETACH but,
- * for some reason, that function isn't getting called. */
- else if (command == DOSNTAST_GET_IO_PORT) {
- setEBX(0x55AA55AA);
- setEDX(vm_io_base);
- }
- else if (command == DOSNTAST_NOTIFY_UNLOAD) {
- if (vm_io_base) remove_io_port();
- if (vm_marked) remove_vm_mark();
- setEBX(0x55AA55AA);
- }
- else {
- sprintf(tmp,"0x%08lX\n",(unsigned long)command);
- MessageBox(NULL,tmp,"Unknown command",MB_OK);
- }
-}
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define int386 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
-uint8_t ntvdm_dosntast_tried = 0;
-uint16_t ntvdm_dosntast_handle = (~0U);
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-uint16_t ntvdm_dosntast_io_base = 0;
-
-uint16_t ntvdm_dosntast_detect() {
- const char *str = "DOSNTAST.VDD";
- uint16_t str_len = 12;
- uint16_t handle = (~0U);
- unsigned int i,max=0x200;
-#if TARGET_MSDOS == 32
- unsigned char *p = (unsigned char*)0x400;
-#else
- unsigned char FAR *p = (unsigned char FAR*)MK_FP(0x40,0x00);
-#endif
-
- for (i=0;i <= (max-str_len);i++) {
-#if TARGET_MSDOS == 32
- if (memcmp(str,p+i,str_len) == 0)
- handle = *((uint16_t*)(p+i+str_len));
-#else
- if (_fmemcmp(str,p+i,str_len) == 0)
- handle = *((uint16_t FAR*)(p+i+str_len));
-#endif
-
- if (ntvdm_RM_ERR(handle))
- handle = DOSNTAST_HANDLE_UNASSIGNED;
- else
- break;
- }
-
- return handle;
-}
-
-int ntvdm_dosntast_load_vdd() {
- uint32_t t1=0,t2=0;
-
- /* TODO: Right now this works for the current path, or if it's in the Windows system dir.
- * Adopt a strategy where the user can also set an environment variable to say where
- * the DLL is. */
- ntvdm_dosntast_handle = ntvdm_RegisterModule("DOSNTAST.VDD","Init","Dispatch");
- if (ntvdm_RM_ERR(ntvdm_dosntast_handle)) return 0;
-
- /* test out the dispatch call: give the DLL back his handle */
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = DOSNTAST_INIT_REPORT_HANDLE_C;
- rc.ecx = ntvdm_dosntast_handle;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- t1 = rc.ebx;
- t2 = rc.ecx;
- }
-#else
- t1 = ntvdm_dosntast_handle;
- __asm {
- .386p
- push ebx
- push ecx
- mov ebx,DOSNTAST_INIT_REPORT_HANDLE
- mov eax,t1
- mov ecx,eax
- ntvdm_Dispatch_ins_asm_db
- mov t1,ebx
- mov t2,ecx
- pop ecx
- pop ebx
- }
-#endif
-
- if (t1 != 0x55AA55AA || !(t2 >= 0x400 && t2 <= 0x600)) {
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- return 0;
- }
-#if TARGET_MSDOS == 32
- if (memcmp((void*)t2,"DOSNTAST.VDD\xFF\xFF",14)) {
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- return 0;
- }
- *((uint16_t*)(t2+12)) = ntvdm_dosntast_handle;
-#else
- if (_fmemcmp(MK_FP(t2>>4,t2&0xF),"DOSNTAST.VDD\xFF\xFF",14)) {
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- return 0;
- }
- *((uint16_t FAR*)MK_FP((t2+12)>>4,(t2+12)&0xF)) = ntvdm_dosntast_handle;
-#endif
-
- return (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED)?1:0;
-}
-
-unsigned int ntvdm_dosntast_waveOutGetNumDevs() {
- if (ntvdm_dosntast_io_base == 0)
- return 0;
-
- /* FUNCTION */
- outpw(ntvdm_dosntast_io_base+0,DOSNTAST_FUNCTION_WINMM);
- /* SUBFUNCTION */
- outpw(ntvdm_dosntast_io_base+1,DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs);
- /* COMMAND */
- return inpw(ntvdm_dosntast_io_base+2);
-}
-
-uint32_t ntvdm_dosntast_waveOutGetDevCaps(uint32_t uDeviceID,WAVEOUTCAPS *pwoc,uint16_t cbwoc) {
- uint32_t retv=0,port;
-
- if (ntvdm_dosntast_io_base == 0)
- return 0;
-
- /* FUNCTION */
- outpw(ntvdm_dosntast_io_base+0,DOSNTAST_FUNCTION_WINMM);
- /* SUBFUNCTION */
- outpw(ntvdm_dosntast_io_base+1,DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps);
- /* COMMAND */
- port = ntvdm_dosntast_io_base+2;
-
-#if TARGET_MSDOS == 32
- __asm {
- .386p
- pushad
- /* we trust Watcom left ES == DS */
- mov edx,port
- mov eax,uDeviceID
- movzx ebx,cbwoc
- mov ecx,1
- mov edi,pwoc
- rep insb
- popad
- }
-#elif defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .386p
- push es
- pushad
- mov edx,port
- mov eax,uDeviceID
- movzx ebx,cbwoc
- mov ecx,1
- les di,pwoc
- rep insb
- popad
- pop es
- }
-#else
- __asm {
- .386p
- pushad
- push es
- mov ax,ds
- mov es,ax
- mov edx,port
- mov eax,uDeviceID
- movzx ebx,cbwoc
- mov ecx,1
- mov di,pwoc
- rep insb
- pop es
- popad
- }
-#endif
-
- return retv;
-}
-
-int ntvdm_dosntast_MessageBox(const char *text) {
- uint16_t port;
-
- if (ntvdm_dosntast_io_base == 0)
- return 0;
-
- /* FUNCTION */
- outpw(ntvdm_dosntast_io_base+0,DOSNTAST_FUNCTION_GENERAL);
- /* SUBFUNCTION */
- outpw(ntvdm_dosntast_io_base+1,DOSNTAST_FUN_GEN_SUB_MESSAGEBOX);
- /* COMMAND */
- port = ntvdm_dosntast_io_base+2;
-#if TARGET_MSDOS == 32
- __asm {
- .386p
- push esi
- push ecx
- push edx
- cld
- movzx edx,port
- mov esi,text
- mov ecx,1 /* NTS: duration dosn't matter, our DLL passes DS:SI directly to MessageBoxA */
- rep outsb
- pop edx
- pop ecx
- pop esi
- }
-#elif defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .386p
- push ds
- push si
- push cx
- push dx
- cld
- mov dx,port
- lds si,text
- mov cx,1
- rep outsb
- pop dx
- pop cx
- pop si
- pop ds
- }
-#else
- __asm {
- .386p
- push si
- push cx
- push dx
- cld
- mov dx,port
- mov si,text
- mov cx,1
- rep outsb
- pop dx
- pop cx
- pop si
- }
-#endif
-
- return 1;
-}
-
-/* initialize the library.
- * if dont_load_dosntast is set, then it will not load the VDD driver but will use the driver if already loaded */
-int ntvdm_dosntast_init() {
- uint32_t t1=0,t2=0;
-
- if (!ntvdm_dosntast_tried) {
- ntvdm_dosntast_tried = 1;
- ntvdm_dosntast_io_base = 0;
-
- if (lib_dos_option.dont_use_dosntast) {
- ntvdm_dosntast_handle = DOSNTAST_HANDLE_UNASSIGNED;
- return 0;
- }
-
- /* It turns out if you request the same DLL again and again, NTVDM.EXE will not return the
- * same handle, it will allocate another one. To avoid exhausting it handles, we first
- * detect whether the DLL is already loaded.
- *
- * We do this by scanning the 0x40-0x50 segments (the BIOS data area) for a signature value
- * placed by the DLL. Following the signature is the handle value. */
- ntvdm_dosntast_handle = ntvdm_dosntast_detect();
- if (ntvdm_dosntast_handle == DOSNTAST_HANDLE_UNASSIGNED && !lib_dos_option.dont_load_dosntast)
- ntvdm_dosntast_load_vdd();
-
- /* we need to know the IO port base */
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
- if (!ntvdm_rm_code_alloc())
- return ntvdm_RM_ERR_NOT_AVAILABLE;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = (uint32_t)(DOSNTAST_GET_IO_PORT_C); /* <= FIXME: "constant out of range" what the fuck are you talking about Watcom? */
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- t1 = rc.ebx;
- t2 = rc.edx;
- }
-#else
- t1 = ntvdm_dosntast_handle;
- __asm {
- .386p
- push ebx
- push edx
- mov ebx,DOSNTAST_GET_IO_PORT
- mov eax,t1
- ntvdm_Dispatch_ins_asm_db
- mov t1,ebx
- mov t2,edx
- pop edx
- pop ebx
- }
-#endif
-
- if (t1 == 0x55AA55AAUL)
- ntvdm_dosntast_io_base = (uint16_t)t2;
- }
- }
-
- return (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED)?1:0;
-}
-
-void ntvdm_dosntast_unload() {
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = DOSNTAST_NOTIFY_UNLOAD_C;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- }
-#else
- {
- const uint16_t h = ntvdm_dosntast_handle;
-
- __asm {
- .386p
- mov ebx,DOSNTAST_NOTIFY_UNLOAD
- mov ax,h
- ntvdm_Dispatch_ins_asm_db
- }
- }
-#endif
-
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- ntvdm_dosntast_handle = DOSNTAST_HANDLE_UNASSIGNED;
- }
-}
-
-uint32_t ntvdm_dosntast_GetTickCount() {
- uint32_t retv = 0xFFFFFFFFUL;
-
- if (ntvdm_dosntast_handle == DOSNTAST_HANDLE_UNASSIGNED)
- return 0; /* failed */
- if (!ntvdm_rm_code_alloc())
- return 0;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = DOSNTAST_GET_TICK_COUNT_C;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- retv = rc.ebx;
- }
-#else
- {
- const uint16_t h = ntvdm_dosntast_handle;
-
- __asm {
- .386p
- push ebx
- mov ebx,DOSNTAST_GET_TICK_COUNT
- mov ax,h
- ntvdm_Dispatch_ins_asm_db
- mov retv,ebx
- pop ebx
- }
- }
-#endif
-
- return retv;
-}
-
-unsigned int ntvdm_dosntast_getversionex(OSVERSIONINFO *ovi) {
- unsigned int retv=0;
-
- if (ntvdm_dosntast_handle == DOSNTAST_HANDLE_UNASSIGNED)
- return 0; /* failed */
- if (!ntvdm_rm_code_alloc())
- return 0;
-
-#if TARGET_MSDOS == 32
- {
- uint16_t myds=0;
- struct dpmi_realmode_call rc={0};
- __asm mov myds,ds
- rc.ebx = DOSNTAST_GETVERSIONEX_C;
- rc.esi = (uint32_t)ovi;
- rc.ecx = 1;
- rc.ds = myds;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- retv = rc.ebx;
- }
-#else
- {
- const uint16_t s = FP_SEG(ovi),o = FP_OFF(ovi),h = ntvdm_dosntast_handle;
-
- __asm {
- .386p
- push ds
- push esi
- push ecx
- mov ebx,DOSNTAST_GETVERSIONEX
- xor esi,esi
- mov ax,h
- mov si,s
- mov ds,si
- mov si,o
- xor cx,cx
- ntvdm_Dispatch_ins_asm_db
- mov retv,bx
- pop esi
- pop ebx
- pop ds
- }
- }
-#endif
-
- return retv;
-}
-
-#endif
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NTVDM.EXE DOSNTAST.VDD call support */
-#include <windows/ntvdm/ntvdmlib.h>
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-extern uint8_t ntvdm_dosntast_tried;
-extern uint16_t ntvdm_dosntast_handle;
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-extern uint16_t ntvdm_dosntast_io_base;
-
-int ntvdm_dosntast_init();
-void ntvdm_dosntast_unload();
-uint32_t ntvdm_dosntast_GetTickCount();
-int ntvdm_dosntast_MessageBox(const char *text);
-unsigned int ntvdm_dosntast_waveOutGetNumDevs();
-unsigned int ntvdm_dosntast_getversionex(OSVERSIONINFO *ovi);
-uint32_t ntvdm_dosntast_waveOutGetDevCaps(uint32_t uDeviceID,WAVEOUTCAPS *pwoc,uint16_t cbwoc);
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e) {
- unsigned int i,o=0;
-
-#if TARGET_MSDOS == 32
- e->raw = (unsigned char*)((uint32_t)seg << 4UL);
-#else
- e->raw = (unsigned char FAR*)MK_FP(seg,0);
-#endif
- e->memsize = *((uint16_t FAR*)(e->raw + 0x02));
- e->callpsp = *((uint16_t FAR*)(e->raw + 0x16));
- e->env = *((uint16_t FAR*)(e->raw + 0x2C));
- for (i=0;i < (unsigned char)e->raw[0x80] && e->raw[0x81+i] == ' ';) i++; /* why is there all this whitespace at the start? */
- for (;i < (unsigned char)e->raw[0x80];i++) e->cmd[o++] = e->raw[0x81+i];
- e->cmd[o] = 0;
- return 1;
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2))
-unsigned short smartdrv_version = 0xFFFF;
-int smartdrv_fd = -1;
-#endif
-
-#if (TARGET_MSDOS == 16 || TARGET_MSDOS == 32) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-int smartdrv_close() {
- if (smartdrv_fd >= 0) {
- close(smartdrv_fd);
- smartdrv_fd = -1;
- }
-
- return 0;
-}
-
-int smartdrv_flush() {
- if (smartdrv_version == 0xFFFF || smartdrv_version == 0)
- return 0;
-
- if (smartdrv_version >= 0x400) { /* SMARTDRV 4.xx and later */
-#if TARGET_MSDOS == 32
- __asm {
- push eax
- push ebx
- mov eax,0x4A10 ; SMARTDRV
- mov ebx,0x0001 ; FLUSH BUFFERS (COMMIT CACHE)
- int 0x2F
- pop ebx
- pop eax
- }
-#else
- __asm {
- push ax
- push bx
- mov ax,0x4A10 ; SMARTDRV
- mov bx,0x0001 ; FLUSH BUFFERS (COMMIT CACHE)
- int 0x2F
- pop bx
- pop ax
- }
-#endif
- }
- else if (smartdrv_version >= 0x300 && smartdrv_version <= 0x3FF) { /* SMARTDRV 3.xx */
- char buffer[0x1];
-#if TARGET_MSDOS == 32
-#else
- char far *bptr = (char far*)buffer;
-#endif
- int rd=0;
-
- if (smartdrv_fd < 0)
- return 0;
-
- buffer[0] = 0; /* flush cache */
-#if TARGET_MSDOS == 32
- /* FIXME: We do not yet have a 32-bit protected mode version.
- * DOS extenders do not appear to translate AX=0x4403 properly */
-#else
- __asm {
- push ax
- push bx
- push cx
- push dx
- push ds
- mov ax,0x4403 ; IOCTL SMARTAAR CACHE CONTROL
- mov bx,smartdrv_fd
- mov cx,0x1 ; 0x01 bytes
- lds dx,word ptr [bptr]
- int 0x21
- jc err1
- mov rd,ax ; CF=0, AX=bytes written
-err1: pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- }
-#endif
-
- if (rd == 0)
- return 0;
- }
-
- return 1;
-}
-
-int smartdrv_detect() {
- unsigned int rvax=0,rvbp=0;
-
- if (smartdrv_version == 0xFFFF) {
- /* Is Microsoft SMARTDRV 4.x or equivalent disk cache present? */
-
-#if TARGET_MSDOS == 32
- __asm {
- push eax
- push ebx
- push ecx
- push edx
- push esi
- push edi
- push ebp
- push ds
- mov eax,0x4A10 ; SMARTDRV 4.xx INSTALLATION CHECK AND HIT RATIOS
- mov ebx,0
- mov ecx,0xEBAB ; "BABE" backwards
- xor ebp,ebp
- int 0x2F ; multiplex (hope your DOS extender supports it properly!)
- pop ds
- mov ebx,ebp ; copy EBP to EBX. Watcom C uses EBP to refer to the stack!
- pop ebp
- mov rvax,eax ; we only care about EAX and EBP(now EBX)
- mov rvbp,ebx
- pop edi
- pop esi
- pop edx
- pop ecx
- pop ebx
- pop eax
- }
-#else
- __asm {
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- mov ax,0x4A10 ; SMARTDRV 4.xx INSTALLATION CHECK AND HIT RATIOS
- mov bx,0
- mov cx,0xEBAB ; "BABE" backwards
- xor bp,bp
- int 0x2F ; multiplex
- pop ds
- mov bx,bp ; copy BP to BX. Watcom C uses BP to refer to the stack!
- pop bp
- mov rvax,ax ; we only care about EAX and EBP(now EBX)
- mov rvbp,bx
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- }
-#endif
-
- if ((rvax&0xFFFF) == 0xBABE && (rvbp&0xFFFF) >= 0x400 && (rvbp&0xFFFF) <= 0x5FF) {
- /* yup. SMARTDRV 4.xx! */
- smartdrv_version = (rvbp&0xFF00) + (((rvbp>>4)&0xF) * 10) + (rvbp&0xF); /* convert BCD to decimal */
- }
-
- if (smartdrv_version == 0xFFFF) {
- char buffer[0x28];
-#if TARGET_MSDOS == 32
-#else
- char far *bptr = (char far*)buffer;
-#endif
- int rd=0;
-
- memset(buffer,0,sizeof(buffer));
-
- /* check for SMARTDRV 3.xx */
- smartdrv_fd = open("SMARTAAR",O_RDONLY);
- if (smartdrv_fd >= 0) {
- /* FIXME: The DOS library should provide a common function to do IOCTL read/write character "control channel" functions */
-#if TARGET_MSDOS == 32
- /* FIXME: We do not yet have a 32-bit protected mode version.
- * DOS extenders do not appear to translate AX=0x4402 properly */
-#else
- __asm {
- push ax
- push bx
- push cx
- push dx
- push ds
- mov ax,0x4402 ; IOCTL SMARTAAR GET CACHE STATUS
- mov bx,smartdrv_fd
- mov cx,0x28 ; 0x28 bytes
- lds dx,word ptr [bptr]
- int 0x21
- jc err1
- mov rd,ax ; CF=0, AX=bytes read
-err1: pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- }
-#endif
-
- /* NTS: Despite reading back 0x28 bytes of data, this IOCTL
- * returns AX=1 for some reason. */
- if (rd > 0 && rd <= 0x28) {
- if (buffer[0] == 1/*write through flag*/ && buffer[15] == 3/*major version number*/) { /* SMARTDRV 3.xx */
- smartdrv_version = ((unsigned short)buffer[15] << 8) + ((unsigned short)buffer[14]);
- }
- else {
- close(smartdrv_fd);
- }
- }
- }
- }
-
- /* didn't find anything. then no SMARTDRV */
- if (smartdrv_version == 0xFFFF)
- smartdrv_version = 0;
- }
-
- return (smartdrv_version != 0);
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-/* as seen in the ROM area: "BIOS: "+NUL+"VirtualBox 4.1.8_OSE" around 0xF000:0x0130 */
-static const char *virtualbox_bios_str = "BIOS: ";
-static const char *virtualbox_vb_str = "VirtualBox ";
-#endif
-
-/* the ROM area doesn't change. so remember our last result */
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-static signed char virtualbox_detect_cache = -1;
-#endif
-
-/* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
-char virtualbox_version_str[64]={0};
-
-int detect_virtualbox_emu() {
-#if defined(TARGET_OS2)
- /* TODO: So... how does one read the ROM BIOS area from OS/2? */
- return 0;
-#elif defined(TARGET_WINDOWS)
- /* TODO: I know that from within Windows there are various ways to scan the ROM BIOS area.
- * Windows 1.x and 2.x (if real mode) we can just use MK_FP as we do under DOS, but
- * we have to use alternate means if Windows is in protected mode. Windows 2.x/3.x protected
- * mode (and because of compatibility, Windows 95/98/ME), there are two methods open to us:
- * One is to use selector constants that are hidden away in KRNL386.EXE with names like _A0000,
- * _B0000, etc. They are data selectors that when loaded into the segment registers point to
- * their respective parts of DOS adapter ROM and BIOS ROM. Another way is to use the Win16
- * API to create a data selector that points to the BIOS. Windows 386 Enhanced mode may map
- * additional things over the unused parts of adapter ROM, but experience shows that it never
- * relocates or messes with the VGA BIOS or with the ROM BIOS,
- *
- * My memory is foggy at this point, but I remember that under Windows XP SP2, one of the
- * above Win16 methods still worked even from under the NT kernel.
- *
- * For Win32 applications, if the host OS is Windows 3.1 Win32s or Windows 95/98/ME, we can
- * take advantage of a strange quirk in the way the kernel maps the lower 1MB. For whatever
- * reason, the VGA RAM, adapter ROM, and ROM BIOS areas are left open even for Win32 applications
- * with no protection. Thus, a Win32 programmer can just make a pointer like
- * char *a = (char*)0xA0000 and scribble on legacy VGA RAM to his heart's content (though on
- * modern PCI SVGA hardware the driver probably instructs the card to disable VGA compatible
- * mapping). In fact, this ability to scribble on RAM directly is at the heart of one of Microsoft's
- * earliest and hackiest "Direct Draw" interfaces known as "DISPDIB.DLL", a not-to-well documented
- * library responsible for those Windows 3.1 multimedia apps and games that were somehow able to
- * run full-screen 320x200x256 color VGA despite being Windows GDI-based apps. Ever wonder how the
- * MCI AVI player was able to go full-screen when DirectX and WinG were not invented yet? Now you
- * know :)
- *
- * There are some VFW codecs out there as well, that also like to abuse DISPDIB.DLL for "fullscreen"
- * modes. One good example is the old "Motion Pixels" codec, that when asked to go fullscreen,
- * uses DISPDIB.DLL and direct VGA I/O port trickery to effectively set up a 320x480 256-color mode,
- * which it then draws on "fake hicolor" style to display the video (though a bit dim since you're
- * sort of watching a video through a dithered mesh, but...)
- *
- * In case you were probably wondering, no, Windows NT doesn't allow Win32 applications the same
- * privilege. Win32 apps writing to 0xA0000 would page fault and crash. Curiously enough though,
- * NTVDM.EXE does seem to open up the 0xA0000-0xFFFFF memory area to Win16 applications if they
- * use the right selectors and API calls. */
- return 0;
-#else
- int i,j;
-# if TARGET_MSDOS == 32
- const char *scan;
-# else
- const char far *scan;
-# endif
-
- probe_dos();
- if (virtualbox_detect_cache >= 0)
- return (int)virtualbox_detect_cache;
-
- virtualbox_detect_cache=0;
-
-# if TARGET_MSDOS == 32
- if (dos_flavor == DOS_FLAVOR_FREEDOS) {
- /* FIXME: I have no idea why but FreeDOS 1.0 has a strange conflict with DOS32a where if this code
- * tries to read the ROM BIOS it causes a GPF and crashes (or sometimes runs off into the
- * weeds leaving a little garbage on the screen). DOS32a's register dump seems to imply that
- * at one point our segment limits were suddenly limited to 1MB (0xFFFFF). I have no clue
- * what the hell is triggering it, but I know from testing we can avoid that crash by not
- * scanning. */
- if (freedos_kernel_version == 0x000024UL) /* 0.0.36 */
- return (virtualbox_detect_cache=0);
- }
-# endif
-
- /* test #1: the ROM BIOS region just prior to 0xF0000 is all zeros.
- * NTS: VirtualBox 4.1.8 also seems to have the ACPI tables at 0xE000:0x0000 */
-# if TARGET_MSDOS == 32
- scan = (const char*)0xEFF00;
-# else
- scan = (const char far*)MK_FP(0xE000,0xFF00);
-# endif
- for (i=0;i < 256;i++) {
- if (scan[i] != 0)
- return virtualbox_detect_cache;
- }
-
- /* test #2: somewhere within the first 4KB, are the strings "BIOS: " and
- * "VirtualBox " side by side separated by a NUL. The "VirtualBox" string is
- * followed by the version number, and "_OSE" if the open source version. */
-# if TARGET_MSDOS == 32
- scan = (const char*)0xF0000;
-# else
- scan = (const char far*)MK_FP(0xF000,0x0000);
-# endif
- for (i=0,j=0;i < 4096;i++) {
- if (scan[i] == virtualbox_bios_str[j]) {
- j++;
- if (virtualbox_bios_str[j] == 0 && scan[i+1] == 0) {
- /* good. found it. stop there. */
- i++;
- break;
- }
- }
- else {
- j=0;
- }
- }
- /* if we didn't find the first string, then give up */
- if (i >= 4096) return virtualbox_detect_cache;
-
- /* make sure the next string is "VirtualBox " */
- for (/*do not reset 'i'*/j=0;i < 4096;i++) {
- if (scan[i] == virtualbox_vb_str[j]) {
- j++;
- if (virtualbox_vb_str[j] == 0) {
- /* good. found it. stop there. */
- virtualbox_detect_cache = 1;
- break;
- }
- }
- else {
- j=0;
- }
- }
- if (i >= 4096) return virtualbox_detect_cache;
-
- /* 'i' now points at the version part of the string. copy it down */
- while (i < 4096 && scan[i] == ' ') i++;
- for (j=0;j < (sizeof(virtualbox_version_str)-1) && i < 4096;)
- virtualbox_version_str[j++] = scan[i++];
- virtualbox_version_str[j] = 0;
-
- return virtualbox_detect_cache;
-#endif
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-unsigned char vcpi_probed = 0;
-unsigned char vcpi_present = 0;
-unsigned char vcpi_major_version,vcpi_minor_version;
-
-/* NTS: According to the VCPI specification this call is only supposed to report
- * the physical memory address for anything below the 1MB boundary. And so
- * far EMM386.EXE strictly adheres to that rule by not reporting success for
- * addresses >= 1MB. The 32-bit limitation is a result of the VCPI system
- * call, since the physical address is returned in EDX. */
-uint32_t dos_linear_to_phys_vcpi(uint32_t pn) {
- uint32_t r=0xFFFFFFFFUL;
-
- __asm {
- .586p
- mov ax,0xDE06
- mov ecx,pn
- int 67h
- or ah,ah
- jnz err1 ; if AH == 0 then EDX = page phys addr
- mov r,edx
-err1:
- }
-
- return r;
-}
-
-#if !defined(TARGET_WINDOWS)
-static int int67_null() {
- uint32_t ptr;
-
-#if TARGET_MSDOS == 32
- ptr = ((uint32_t*)0)[0x67];
-#else
- ptr = *((uint32_t far*)MK_FP(0,0x67*4));;
-#endif
-
- return (ptr == 0);
-}
-#endif
-
-int probe_vcpi() {
-#if defined(TARGET_WINDOWS)
- if (!vcpi_probed) {
- /* NTS: Whoever said Windows 3.0 used VCPI at it's core, is a liar */
- vcpi_probed = 1;
- vcpi_present = 0;
- }
-#else
-/* =================== MSDOS ================== */
- unsigned char err=0xFF;
-
- if (!vcpi_probed) {
- vcpi_probed = 1;
-
- /* if virtual 8086 mode isn't active, then VCPI isn't there */
- /* FIXME: What about cases where VCPI might be there, but is inactive (such as: EMM386.EXE resident but disabled) */
- if (!cpu_v86_active)
- return 0;
-
- /* NOTE: VCPI can be present whether we're 16-bit real mode or
- * 32-bit protected mode. Unlike DPMI we cannot assume it's
- * present just because we're 32-bit. */
-
- /* Do not call INT 67h if the vector is uninitialized */
- if (int67_null())
- return 0;
-
- /* Do not attempt to probe for VCPI if Windows 3.1/95/98/ME
- * is running. Windows 9x blocks VCPI and if called, interrupts
- * our execution to inform the user that the program should be
- * run in DOS mode. */
- detect_windows();
- if (windows_mode != WINDOWS_NONE)
- return 0;
-
- /* NTS: we load DS for each var because Watcom might put it in
- * another data segment, especially in Large memory model.
- * failure to account for this was the cause of mysterious
- * hangs and crashes. */
- __asm {
- ; NTS: Save DS and ES because Microsoft EMM386.EXE
- ; appears to change their contents.
- push ds
- push es
- mov ax,0xDE00
- int 67h
- mov err,ah
-
- mov ax,seg vcpi_major_version
- mov ds,ax
- mov vcpi_major_version,bh
-
- mov ax,seg vcpi_minor_version
- mov ds,ax
- mov vcpi_minor_version,bl
-
- pop es
- pop ds
- }
-
- if (err != 0)
- return 0;
-
- vcpi_present = 1;
- }
-#endif
-
- return vcpi_present;
-}
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define int386 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-const char *windows_version_method = NULL;
-
-/* return value:
- * 0 = not running under Windows
- * 1 = running under Windows */
-const char *windows_emulation_comment_str = NULL;
-uint8_t windows_emulation = 0;
-uint16_t windows_version = 0; /* NOTE: 0 for Windows NT */
-uint8_t windows_mode = 0;
-uint8_t windows_init = 0;
-
-const char *windows_mode_strs[WINDOWS_MAX] = {
- "None",
- "Real",
- "Standard",
- "Enhanced",
- "NT",
- "OS/2"
-};
-
-/* TESTING (whether or not it correctly detects the presence of Windows):
- * Note that in some columns the API returns insufficient information and the
- * API has to use it's best guess on the correct value, which might be
- * inaccurate or wrong (marked: GUESSES).
- *
- * For Windows NT/2000/XP/Vista/7 tests, the code does not have any way of
- * knowing (yet) which version of the NT kernel is involved, so the best
- * it can offer is "I am running under NT" (marked as ONLY NT)
- *
- * OS, shell, configuration & mode Detects Correct mode Correct version
- * Microsoft Windows 3.0 (DOSBox 0.74)
- * 386 Enhanced Mode YES YES YES
- * 286 Standard Mode YES GUESSES YES
- * 8086 Real Mode YES GUESSES YES
- * Microsoft Windows 3.1 (DOSBox 0.74)
- * 386 Enhanced Mode YES YES YES
- * 286 Standard Mode YES YES YES
- * Microsoft Windows 3.11 (DOSBox 0.74)
- * 386 Enhanced Mode YES YES YES*
- * 286 Standard Mode YES YES YES*
- * * = Despite being v3.11 it still reports itself as v3.1
- * Microsoft Windows 95 (4.00.950) (DOS 7.00) (Qemu)
- * Normal YES YES* YES (4.0)
- * Safe mode YES YES* YES (4.0)
- * Prevent DOS apps detecting Windows NO - -
- * * = Reports self as "enhanced mode" which is really the only mode supported
- * Microsoft Windows 95 OSR2.5 (4.00.950 C) (DOS 7.10) (Qemu)
- * Normal YES YES YES (4.0)
- * Safe mode YES YES YES (4.0)
- * Microsoft Windows 95 SP1 (4.00.950a) (DOS 7.00) (Qemu)
- * Normal YES YES YES (4.0)
- * Safe mode YES YES YES (4.0)
- * Microsoft Windows 98 (4.10.1998) (DOS 7.10) (Qemu)
- * Normal YES YES YES (4.10)
- * Safe mode YES YES YES (4.10)
- * Microsoft Windows 98 SE (4.10.2222 A) (DOS 7.10) (Qemu)
- * Normal YES YES YES (4.10)
- * Safe mode YES YES YES (4.10)
- * Microsoft Windows ME (4.90.3000) (DOS 8.00) (Qemu)
- * Normal YES YES YES (4.90)
- * Safe mode YES YES YES (4.90)
- * Microsoft Windows 2000 Professional (5.00.2195) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional SP1 (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional SP2 (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional SP3 (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
-*/
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-/* it's nice to know if we're running under WINE (and therefore possibly Linux)
- * as opposed to real Windows, so that we can adjust our techniques accordingly.
- * I doubt for example that WINE would support Windows NT's NTVDM.EXE BOP codes,
- * or that our Win9x compatible VxD enumeration would know not to try enumerating
- * drivers. */
-void win32_probe_for_wine() { /* Probing for WINE from the Win32 layer */
- HMODULE ntdll;
-
- ntdll = LoadLibrary("NTDLL.DLL");
- if (ntdll) {
- const char *(__stdcall *p)() = (const char *(__stdcall *)())GetProcAddress(ntdll,"wine_get_version");
- if (p != NULL) {
- windows_emulation = WINEMU_WINE;
- windows_emulation_comment_str = p(); /* and the function apparently returns a string */
- }
- FreeLibrary(ntdll);
- }
-}
-#elif defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-void win16_probe_for_wine() { /* Probing for WINE from the Win16 layer */
- DWORD callw,retv;
-
- if (!genthunk32_init()) return;
- if (genthunk32w_ntdll == 0) return;
-
- callw = __GetProcAddress32W(genthunk32w_ntdll,"wine_get_version");
- if (callw == 0) return;
-
- retv = __CallProcEx32W(CPEX_DEST_STDCALL/*nothing to convert*/,0/*0 param*/,callw);
- if (retv == 0) return;
-
- windows_emulation = WINEMU_WINE;
- {
- /* NTS: We assume that WINE, just like real Windows, will not move or relocate
- * NTDLL.DLL and will not move the string it just returned. */
- /* TODO: You need a function the host program can call to free the selector
- * you allocated here, in case it wants to reclaim resources */
- uint16_t sel;
- uint16_t myds=0;
- __asm mov myds,ds
- sel = AllocSelector(myds);
- if (sel != 0) {
- /* the selector is directed at the string, then retained in this
- * code as a direct FAR pointer to WINE's version string */
- SetSelectorBase(sel,retv);
- SetSelectorLimit(sel,0xFFF); /* WINE's version string is rarely longer than 14 chars */
- windows_emulation_comment_str = MK_FP(sel,0);
- }
- }
-}
-#endif
-
-int detect_windows() {
-#if defined(TARGET_WINDOWS)
-# if TARGET_MSDOS == 32
-# ifdef WIN386
- /* Windows 3.0/3.1 with Win386 */
- if (!windows_init) {
- DWORD raw;
-
- windows_emulation = 0;
- windows_init = 1;
- windows_mode = WINDOWS_ENHANCED; /* most likely scenario is Windows 3.1 386 enhanced mode */
-
- raw = GetVersion();
- windows_version_method = "GetVersion";
- windows_version = (LOBYTE(LOWORD(raw)) << 8) | HIBYTE(LOWORD(raw));
- /* NTS: Microsoft documents GetVersion() as leaving bit 31 unset for NT, bit 31 set for Win32s and Win 9x/ME.
- * But that's not what the Win16 version of the function does! */
-
- if (dos_version == 0) probe_dos();
-
- /* Windows 3.1/9x/ME */
- raw = GetWinFlags();
- if (raw & WF_PMODE) {
- if (raw & WF_ENHANCED)
- windows_mode = WINDOWS_ENHANCED;
- else/* if (raw & WF_STANDARD)*/
- windows_mode = WINDOWS_STANDARD;
- }
- else {
- windows_mode = WINDOWS_REAL;
- }
-
- /* NTS: All 32-bit Windows systems since Windows NT 3.51 and Windows 95 return
- * major=3 minor=95 when Win16 applications query the version number. The only
- * exception to that rule is Windows NT 3.1, which returns major=3 minor=10,
- * the same version number returned by Windows 3.1. */
- if (windows_mode == WINDOWS_ENHANCED &&
- (dos_version >= 0x510 && dos_version <= 0x57f)/* MS-DOS v5.50 */ &&
- (windows_version == 0x035F /* Windows NT 4/2000/XP/Vista/7/8 */ ||
- windows_version == 0x030A /* Windows NT 3.1/3.5x */)) {
- /* if the real DOS version is 5.50 then we're under NT */
- windows_mode = WINDOWS_NT;
- }
-
- switch (dos_version>>8) {
- case 10: /* OS/2 1.x */
- case 20: /* OS/2 2.x (low=0), and OS/2 Warp 3 (low=30), and OS/2 Warp 4 (low=40) */
- windows_version_method = "Deduce from DOS version";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- break;
- };
- }
-# elif TARGET_WINDOWS >= 40 || defined(WINNT)
- /* Windows 95/98/ME/XP/2000/NT/etc. and Windows NT builds: We don't need to do anything.
- * The fact we're running means Windows is present */
- /* TODO: Clarify which Windows: Are we running under NT? or 9X/ME? What version? */
- if (!windows_init) {
- OSVERSIONINFO ovi;
-
- windows_emulation = 0;
- windows_init = 1;
- memset(&ovi,0,sizeof(ovi));
- ovi.dwOSVersionInfoSize = sizeof(ovi);
- GetVersionEx(&ovi);
-
- windows_version_method = "GetVersionEx";
- windows_version = (ovi.dwMajorVersion << 8) | ovi.dwMinorVersion;
- if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
- windows_mode = WINDOWS_NT;
- else
- windows_mode = WINDOWS_ENHANCED; /* Windows 3.1 Win32s, or Windows 95/98/ME */
-
- win32_probe_for_wine();
- }
-# elif TARGET_WINDOWS == 31
- /* Windows 3.1 with Win32s target build. Note that such programs run in the Win32 layer on Win95/98/ME/NT/2000/etc. */
- /* TODO: Clarify which Windows, using the limited set of functions available under Win32s, or perhaps using GetProcAddress
- * to use the later GetVersionEx() functions offered by Win95/98/NT/etc. */
- if (!windows_init) {
- DWORD raw;
-
- windows_emulation = 0;
- windows_init = 1;
- windows_mode = WINDOWS_ENHANCED; /* Assume Windows 3.1 386 Enhanced Mode. This 32-bit app couldn't run otherwise */
-
- raw = GetVersion();
- windows_version_method = "GetVersion";
- windows_version = (LOBYTE(LOWORD(raw)) << 8) | HIBYTE(LOWORD(raw));
- if (!(raw & 0x80000000UL)) { /* FIXME: Does this actually work? */
- /* Windows NT/2000/XP/etc */
- windows_mode = WINDOWS_NT;
- }
-
- /* TODO: GetProcAddress() GetVersionEx() and get the REAL version number from Windows */
-
- win32_probe_for_wine();
- }
-# else
-# error Unknown 32-bit Windows variant
-# endif
-# elif TARGET_MSDOS == 16
-# if TARGET_WINDOWS >= 30
- /* Windows 3.0/3.1, what we then want to know is what mode we're running under: Real? Standard? Enhanced?
- * The API function GetWinFlags() only exists in 3.0 and higher, it doesn't exist under 2.x */
- /* TODO */
- if (!windows_init) {
- DWORD raw;
-
- windows_emulation = 0;
- windows_init = 1;
- windows_mode = WINDOWS_ENHANCED; /* most likely scenario is Windows 3.1 386 enhanced mode */
-
- raw = GetVersion();
- windows_version_method = "GetVersion";
- windows_version = (LOBYTE(LOWORD(raw)) << 8) | HIBYTE(LOWORD(raw));
- /* NTS: Microsoft documents GetVersion() as leaving bit 31 unset for NT, bit 31 set for Win32s and Win 9x/ME.
- * But that's not what the Win16 version of the function does! */
-
- if (dos_version == 0) probe_dos();
-
- /* Windows 3.1/9x/ME */
- raw = GetWinFlags();
- if (raw & WF_PMODE) {
- if (raw & WF_ENHANCED)
- windows_mode = WINDOWS_ENHANCED;
- else/* if (raw & WF_STANDARD)*/
- windows_mode = WINDOWS_STANDARD;
- }
- else {
- windows_mode = WINDOWS_REAL;
- }
-
- /* NTS: All 32-bit Windows systems since Windows NT 3.51 and Windows 95 return
- * major=3 minor=95 when Win16 applications query the version number. The only
- * exception to that rule is Windows NT 3.1, which returns major=3 minor=10,
- * the same version number returned by Windows 3.1. */
- if (windows_mode == WINDOWS_ENHANCED &&
- (dos_version >= 0x510 && dos_version <= 0x57f)/* MS-DOS v5.50 */ &&
- (windows_version == 0x035F /* Windows NT 4/2000/XP/Vista/7/8 */ ||
- windows_version == 0x030A /* Windows NT 3.1/3.5x */)) {
- /* if the real DOS version is 5.50 then we're under NT */
- windows_mode = WINDOWS_NT;
- }
-
- switch (dos_version>>8) {
- case 10: /* OS/2 1.x */
- case 20: /* OS/2 2.x (low=0), and OS/2 Warp 3 (low=30), and OS/2 Warp 4 (low=40) */
- windows_version_method = "Deduce from DOS version";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- break;
- };
-
- /* If we're running under Windows 9x/ME or Windows NT/2000 we can thunk our way into
- * the Win32 world and call various functions to get a more accurate picture of the
- * Windows system we are running on */
- /* NTS: Under Windows NT 3.51 or later this technique is the only way to get the
- * true system version number. The Win16 GetVersion() will always return
- * some backwards compatible version number except for NT 3.1:
- *
- * Win16 Win32
- * +==========================
- * NT 3.1 | 3.1 3.1
- * NT 3.51 | 3.1 3.51
- * NT 4.0 | 3.95 4.0
- * 2000 | 3.95 5.0
- * XP | 3.95 5.1
- * Vista | 3.95 6.0
- * 7 | 3.95 6.1
- * 8 | 3.95 6.2
- *
- */
- if (genthunk32_init() && genthunk32w_kernel32_GetVersionEx != 0) {
- OSVERSIONINFO osv;
-
- memset(&osv,0,sizeof(osv));
- osv.dwOSVersionInfoSize = sizeof(osv);
- if (__CallProcEx32W(CPEX_DEST_STDCALL | 1/* convert param 1*/,
- 1/*1 param*/,genthunk32w_kernel32_GetVersionEx,
- (DWORD)((void far*)(&osv))) != 0UL) {
- windows_version_method = "GetVersionEx [16->32 CallProcEx32W]";
- windows_version = (osv.dwMajorVersion << 8) | osv.dwMinorVersion;
- if (osv.dwPlatformId == 2/*VER_PLATFORM_WIN32_NT*/)
- windows_mode = WINDOWS_NT;
- else
- windows_mode = WINDOWS_ENHANCED;
- }
- }
-
- win16_probe_for_wine();
- }
-# elif TARGET_WINDOWS >= 20
- /* Windows 2.x or higher. Use GetProcAddress() to locate GetWinFlags() if possible, else assume real mode
- * and find some other way to detect if we're running under the 286 or 386 enhanced versions of Windows 2.11 */
- /* TODO */
- if (!windows_init) {
- windows_init = 1;
- windows_version = 0x200;
- windows_mode = WINDOWS_REAL;
- windows_version_method = "Assuming";
- }
-# else
- /* Windows 1.x. No GetProcAddress, no GetWinFlags. Assume Real mode. */
- /* TODO: How exactly DO you get the Windows version in 1.1? */
- if (!windows_init) {
- windows_init = 1;
- windows_version = 0x101; /* Assume 1.1 */
- windows_mode = WINDOWS_REAL;
- windows_version_method = "Assuming";
- }
-# endif
-# else
-# error Unknown Windows bit target
-# endif
-#elif defined(TARGET_OS2)
- /* OS/2 16-bit or 32-bit. Obviously as something compiled for OS/2, we're running under OS/2 */
- if (!windows_init) {
- windows_version_method = "I'm an OS/2 program, therefore the environment is OS/2";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- windows_init = 1;
- }
-#else
- /* MS-DOS 16-bit or 32-bit. MS-DOS applications must try various obscure interrupts to detect whether Windows is running */
- /* TODO: How can we detect whether we're running under OS/2? */
- if (!windows_init) {
- union REGS regs;
-
- windows_version = 0;
- windows_mode = 0;
- windows_init = 1;
-
- switch (dos_version>>8) {
- case 10: /* OS/2 1.x */
- case 20: /* OS/2 2.x (low=0), and OS/2 Warp 3 (low=30), and OS/2 Warp 4 (low=40) */
- windows_version_method = "Deduce from DOS version";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- break;
- };
-
- if (windows_version == 0) {
- regs.w.ax = 0x160A;
-#if TARGET_MSDOS == 32
- int386(0x2F,®s,®s);
-#else
- int86(0x2F,®s,®s);
-#endif
- if (regs.w.ax == 0x0000 && regs.w.bx >= 0x300 && regs.w.bx <= 0x700) { /* Windows 3.1 */
- windows_version = regs.w.bx;
- switch (regs.w.cx) {
- case 0x0002: windows_mode = WINDOWS_STANDARD; break;
- case 0x0003: windows_mode = WINDOWS_ENHANCED; break;
- default: windows_version = 0; break;
- }
-
- if (windows_mode != 0)
- windows_version_method = "INT 2Fh AX=160Ah";
- }
- }
-
- if (windows_version == 0) {
- regs.w.ax = 0x4680;
-#if TARGET_MSDOS == 32
- int386(0x2F,®s,®s);
-#else
- int86(0x2F,®s,®s);
-#endif
- if (regs.w.ax == 0x0000) { /* Windows 3.0 or DOSSHELL in real or standard mode */
- /* FIXME: Okay... if DOSSHELL triggers this test how do I tell between Windows and DOSSHELL? */
- /* Also, this call does NOT work when Windows 3.0 is in enhanced mode, and for Real and Standard modes
- * does not tell us which mode is active.
- *
- * As far as I can tell there really is no way to differentiate whether it is running in Real or
- * Standard mode, because on a 286 there is no "virtual 8086" mode. The only way Windows can run
- * DOS level code is to thunk back into real mode. So for all purposes whatsoever, we might as well
- * say that we're running in Windows Real mode because during that time slice we have complete control
- * of the CPU. */
- windows_version = 0x300;
- windows_mode = WINDOWS_REAL;
- windows_version_method = "INT 2Fh AX=4680h";
- }
- }
-
- if (windows_version == 0) {
- regs.w.ax = 0x1600;
-#if TARGET_MSDOS == 32
- int386(0x2F,®s,®s);
-#else
- int86(0x2F,®s,®s);
-#endif
- if (regs.h.al == 1 || regs.h.al == 0xFF) { /* Windows 2.x/386 */
- windows_version = 0x200;
- windows_mode = WINDOWS_ENHANCED;
- }
- else if (regs.h.al == 3 || regs.h.al == 4) {
- windows_version = (regs.h.al << 8) + regs.h.ah;
- windows_mode = WINDOWS_ENHANCED; /* Windows 3.0 */
- }
-
- if (windows_mode != 0)
- windows_version_method = "INT 2Fh AX=1600h";
- }
-
- if (windows_version == 0 && windows_mode == WINDOWS_NONE) {
- /* well... if the above fails, but the "true" DOS version is 5.50, then we're running under Windows NT */
- /* NOTE: Every copy of NT/2000/XP/Vista I have reports 5.50, but assuming that will continue is stupid.
- * Microsoft is free to change that someday. */
- if (dos_version == 0) probe_dos();
- if (dos_version >= 0x510 && dos_version <= 0x57f) { /* FIXME: If I recall Windows NT really does stick to v5.50, so this range check should be changed into == 5.50 */
- windows_mode = WINDOWS_NT;
- windows_version = 0;
- windows_version_method = "Assuming from DOS version number";
- }
- }
-
- /* now... if this is Windows NT, the next thing we can do is use NTVDM.EXE's
- * BOP opcodes to load a "helper" DLL that allows us to call into Win32 */
-# if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
- if (windows_mode == WINDOWS_NT && ntvdm_dosntast_init()) {
- /* OK. Ask for the version number */
- OSVERSIONINFO ovi;
-
- memset(&ovi,0,sizeof(ovi));
- ovi.dwOSVersionInfoSize = sizeof(ovi);
- if (ntvdm_dosntast_getversionex(&ovi)) {
- windows_version_method = "GetVersionEx [NTVDM.EXE + DOSNTAST.VDD]";
- windows_version = (ovi.dwMajorVersion << 8) | ovi.dwMinorVersion;
- if (ovi.dwPlatformId == 2/*VER_PLATFORM_WIN32_NT*/)
- windows_mode = WINDOWS_NT;
- else
- windows_mode = WINDOWS_ENHANCED;
- }
- }
-# endif
- }
-#endif
-
- return (windows_mode != WINDOWS_NONE);
-}
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386)
-/* API for exploiting the QT_Thunk Win32 -> Win16 thunking offered by Windows 9x/ME */
-unsigned char win9x_qt_thunk_probed = 0;
-unsigned char win9x_qt_thunk_available = 0;
-
-void (__stdcall *QT_Thunk)() = NULL;
-DWORD (__stdcall *LoadLibrary16)(LPSTR lpszLibFileName) = NULL;
-VOID (__stdcall *FreeLibrary16)(DWORD dwInstance) = NULL;
-HGLOBAL16 (__stdcall *GlobalAlloc16)(UINT flags,DWORD size) = NULL;
-HGLOBAL16 (__stdcall *GlobalFree16)(HGLOBAL16 handle) = NULL;
-DWORD (__stdcall *GlobalLock16)(HGLOBAL16 handle) = NULL;
-BOOL (__stdcall *GlobalUnlock16)(HGLOBAL16 handle) = NULL;
-VOID (__stdcall *GlobalUnfix16)(HGLOBAL16 handle) = NULL;
-VOID (__stdcall *GlobalFix16)(HGLOBAL16 handle) = NULL;
-DWORD (__stdcall *GetProcAddress16)(DWORD dwInstance, LPSTR lpszProcName) = NULL;
-DWORD win9x_kernel_win16 = 0;
-DWORD win9x_user_win16 = 0;
-
-int Win9xQT_ThunkInit() {
- if (!win9x_qt_thunk_probed) {
- Win32OrdinalLookupInfo nfo;
- HMODULE kern32;
-
- win9x_qt_thunk_probed = 1;
- win9x_qt_thunk_available = 0;
-
- if (dos_version == 0) probe_dos();
- if (windows_mode == 0) detect_windows();
- if (windows_mode != WINDOWS_ENHANCED) return 0; /* This does not work under Windows NT */
- if (windows_version < 0x400) return 0; /* This does not work on Windows 3.1 Win32s (FIXME: Are you sure?) */
-
- /* This hack relies on undocumented Win16 support routines hidden in KERNEL32.DLL.
- * They're so super seekret, Microsoft won't even let us get to them through GetProcAddress() */
- kern32 = GetModuleHandle("KERNEL32.DLL");
- if (windows_emulation == WINEMU_WINE) {
- /* FIXME: Direct ordinal lookup doesn't work. Returned
- * addresses point to invalid regions of KERNEL32.DLL.
- * I doubt WINE is even putting a PE-compatible image
- * of it out there.
- *
- * WINE does allow us to GetProcAddress ordinals
- * (unlike Windows 9x which blocks it) but I'm not
- * really sure the returned functions are anything
- * like the Windows 9x equivalent. If we assume they
- * are, this code seems unable to get the address of
- * KRNL386.EXE's "GETVERSION" function.
- *
- * So basically WINE's Windows 9x emulation is more
- * like Windows XP's Application Compatability modes
- * than any serious attempt at pretending to be
- * Windows 9x. And the entry points may well be
- * stubs or other random functions in the same way
- * that ordinal 35 is unrelated under Windows XP. */
- return 0;
- }
- else if (Win32GetOrdinalLookupInfo(kern32,&nfo)) {
- GlobalFix16 = (void*)Win32GetOrdinalAddress(&nfo,27);
- GlobalLock16 = (void*)Win32GetOrdinalAddress(&nfo,25);
- GlobalFree16 = (void*)Win32GetOrdinalAddress(&nfo,31);
- LoadLibrary16 = (void*)Win32GetOrdinalAddress(&nfo,35);
- FreeLibrary16 = (void*)Win32GetOrdinalAddress(&nfo,36);
- GlobalAlloc16 = (void*)Win32GetOrdinalAddress(&nfo,24);
- GlobalUnfix16 = (void*)Win32GetOrdinalAddress(&nfo,28);
- GlobalUnlock16 = (void*)Win32GetOrdinalAddress(&nfo,26);
- GetProcAddress16 = (void*)Win32GetOrdinalAddress(&nfo,37);
- QT_Thunk = (void*)GetProcAddress(kern32,"QT_Thunk");
- }
- else {
- GlobalFix16 = NULL;
- GlobalLock16 = NULL;
- GlobalFree16 = NULL;
- GlobalUnfix16 = NULL;
- LoadLibrary16 = NULL;
- FreeLibrary16 = NULL;
- GlobalAlloc16 = NULL;
- GlobalUnlock16 = NULL;
- GetProcAddress16 = NULL;
- QT_Thunk = NULL;
- }
-
- if (LoadLibrary16 && FreeLibrary16 && GetProcAddress16 && QT_Thunk) {
- /* Prove the API works by loading a reference to KERNEL */
- win9x_kernel_win16 = LoadLibrary16("KERNEL");
- if (win9x_kernel_win16 != 0) {
- win9x_qt_thunk_available = 1;
- }
-
- win9x_user_win16 = LoadLibrary16("USER");
- }
- }
-
- return win9x_qt_thunk_available;
-}
-
-void Win9xQT_ThunkFree() {
- if (win9x_kernel_win16) {
- FreeLibrary16(win9x_kernel_win16);
- win9x_kernel_win16 = 0;
- }
-}
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-unsigned char ToolHelpProbed = 0;
-HMODULE ToolHelpDLL = 0;
-BOOL (PASCAL FAR *__TimerCount)(TIMERINFO FAR *t) = NULL;
-BOOL (PASCAL FAR *__InterruptUnRegister)(HTASK htask) = NULL;
-BOOL (PASCAL FAR *__InterruptRegister)(HTASK htask,FARPROC callback) = NULL;
-
-int ToolHelpInit() {
- if (!ToolHelpProbed) {
- UINT oldMode;
-
- ToolHelpProbed = 1;
-
- /* BUGFIX: In case TOOLHELP.DLL is missing (such as when running under Windows 3.0)
- * this prevents sudden interruption by a "Cannot find TOOLHELP.DLL" error
- * dialog box */
- oldMode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
- ToolHelpDLL = LoadLibrary("TOOLHELP.DLL");
- SetErrorMode(oldMode);
- if (ToolHelpDLL != 0) {
- __TimerCount = (void far*)GetProcAddress(ToolHelpDLL,"TIMERCOUNT");
- __InterruptRegister = (void far*)GetProcAddress(ToolHelpDLL,"INTERRUPTREGISTER");
- __InterruptUnRegister = (void far*)GetProcAddress(ToolHelpDLL,"INTERRUPTUNREGISTER");
- }
- }
-
- return (ToolHelpDLL != 0) && (__TimerCount != NULL) && (__InterruptRegister != NULL) &&
- (__InterruptUnRegister != NULL);
-}
-
-void ToolHelpFree() {
- if (ToolHelpDLL) {
- FreeLibrary(ToolHelpDLL);
- ToolHelpDLL = 0;
- }
- __InterruptUnRegister = NULL;
- __InterruptRegister = NULL;
- __TimerCount = NULL;
-}
-#endif
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NTVDM.EXE DOSNTAST.VDD call support */
-#include <windows/ntvdm/ntvdmlib.h>
-#endif
-
-enum {
- WINEMU_NONE=0,
- WINEMU_WINE
-};
-
-enum {
- WINDOWS_NONE=0,
- WINDOWS_REAL,
- WINDOWS_STANDARD,
- WINDOWS_ENHANCED,
- WINDOWS_NT,
- WINDOWS_OS2, /* Not Windows, OS/2 */
- /* Exact meaning: If we're a DOS/Windows program, then we know we're running under OS/2
- and OS/2 is emulating DOS/Windows. If we're an OS/2 program, then we're in our native
- environment */
- WINDOWS_MAX
-};
-
-extern const char *windows_mode_strs[WINDOWS_MAX];
-#define windows_mode_str(x) windows_mode_strs[x]
-
-extern uint8_t windows_mode;
-extern uint16_t windows_version;
-extern uint8_t windows_emulation;
-extern const char *windows_version_method;
-extern const char *windows_emulation_comment_str;
-
-/* TODO: Someday, these will become variables */
-
-/* whether the Windows emulation allows Win16 to call DPMI */
-#define windows_emulation_includes_dpmi 0
-
-int detect_windows();
-const char *windows_emulation_str(uint8_t e);
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386)
-# include <windows.h>
-# include <stdint.h>
-
-extern unsigned char win9x_qt_thunk_probed;
-extern unsigned char win9x_qt_thunk_available;
-
-typedef WORD HGLOBAL16; /* <- NTS: Taken from WINE header definitions */
-
-extern void (__stdcall *QT_Thunk)();
-extern DWORD (__stdcall *LoadLibrary16)(LPSTR lpszLibFileName);
-extern VOID (__stdcall *FreeLibrary16)(DWORD dwInstance);
-extern HGLOBAL16 (__stdcall *GlobalAlloc16)(UINT flags,DWORD size);
-extern HGLOBAL16 (__stdcall *GlobalFree16)(HGLOBAL16 handle);
-extern DWORD (__stdcall *GlobalLock16)(HGLOBAL16 handle);
-extern BOOL (__stdcall *GlobalUnlock16)(HGLOBAL16 handle);
-extern VOID (__stdcall *GlobalUnfix16)(HGLOBAL16 handle);
-extern DWORD (__stdcall *GetProcAddress16)(DWORD dwInstance, LPSTR lpszProcName);
-extern VOID (__stdcall *GlobalFix16)(HGLOBAL16 handle);
-
-extern DWORD win9x_kernel_win16;
-extern DWORD win9x_user_win16;
-
-int Win9xQT_ThunkInit();
-void Win9xQT_ThunkFree();
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-# include <toolhelp.h>
-extern HMODULE ToolHelpDLL;
-extern unsigned char ToolHelpProbed;
-extern BOOL (PASCAL FAR *__TimerCount)(TIMERINFO FAR *t);
-extern BOOL (PASCAL FAR *__InterruptUnRegister)(HTASK htask);
-extern BOOL (PASCAL FAR *__InterruptRegister)(HTASK htask,FARPROC callback);
-
-int ToolHelpInit();
-void ToolHelpFree();
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-
-#if TARGET_MSDOS == 32
-int _dos_xread(int fd,void *buffer,int bsz) { /* NTS: The DOS extender takes care of translation here for us */
- int rd = -1;
- __asm {
- mov ah,0x3F
- mov ebx,fd
- mov ecx,bsz
- mov edx,buffer
- int 0x21
- mov ebx,eax
- sbb ebx,ebx
- or eax,ebx
- mov rd,eax
- }
- return rd;
-}
-#else
-int _dos_xread(int fd,void far *buffer,int bsz) {
- int rd = -1;
- __asm {
- mov ah,0x3F
- mov bx,fd
- mov cx,bsz
- mov dx,word ptr [buffer+0]
- mov si,word ptr [buffer+2]
- push ds
- mov ds,si
- int 0x21
- pop ds
- mov bx,ax
- sbb bx,bx
- or ax,bx
- mov rd,ax
- }
- return rd;
-}
-#endif
-
-#if TARGET_MSDOS == 32
-int _dos_xwrite(int fd,void *buffer,int bsz) { /* NTS: The DOS extender takes care of translation here for us */
- int rd = -1;
- __asm {
- mov ah,0x40
- mov ebx,fd
- mov ecx,bsz
- mov edx,buffer
- int 0x21
- mov ebx,eax
- sbb ebx,ebx
- or eax,ebx
- mov rd,eax
- }
- return rd;
-}
-#else
-int _dos_xwrite(int fd,void far *buffer,int bsz) {
- int rd = -1;
- __asm {
- mov ah,0x40
- mov bx,fd
- mov cx,bsz
- mov dx,word ptr [buffer+0]
- mov si,word ptr [buffer+2]
- push ds
- mov ds,si
- int 0x21
- pop ds
- mov bx,ax
- sbb bx,bx
- or ax,bx
- mov rd,ax
- }
- return rd;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if !defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-void far *dpmi_getexhandler(unsigned char n) {
- unsigned short s=0,o=0;
-
- __asm {
- mov ax,0x202
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,dx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int dpmi_setexhandler(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x),o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x203
- mov bl,n
- mov cx,s
- mov dx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-#endif
-
-#if !defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-void far *dpmi_getexhandler(unsigned char n) {
- unsigned short s=0;
- unsigned int o=0;
-
- __asm {
- mov ax,0x202
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,edx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int dpmi_setexhandler(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x);
- unsigned int o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x203
- mov bl,n
- mov cx,s
- mov edx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-unsigned int dpmi_test_rm_entry_call(struct dpmi_realmode_call *rc) {
- unsigned int res = 0;
-
- __asm {
- mov ax,0x0301
- xor bx,bx
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- jnc ok
-
- mov res,1 ; just incase some fucked up DPMI server returns CF=1 EAX=0
- or eax,eax
- jz ok
-
- mov res,eax ; OK store the error code as-is
-ok:
- }
-
- return res;
-}
-
-static unsigned char *alt_rm_call = NULL;
-static uint16_t alt_rm_call_sel = 0;
-
-/* using this hack, subvert INT 06h (invalid opcode exception)
- which the BIOS and DOS are unlikely to use during this hack */
-#define ALT_INT 0x06
-
-int dpmi_alternate_rm_call(struct dpmi_realmode_call *rc) {
- uint32_t oe;
-
- if (alt_rm_call == NULL) {
- alt_rm_call = dpmi_alloc_dos(32,&alt_rm_call_sel);
- if (alt_rm_call == NULL) {
- fprintf(stderr,"FATAL: DPMI alternate call: cannot alloc\n");
- return 0;
- }
- }
-
- /* Fuck you DOS4/GW! */
- /* prepare executable code */
- alt_rm_call[0] = 0x9A; /* CALL FAR IMM */
- *((uint16_t*)(alt_rm_call+1)) = rc->ip;
- *((uint16_t*)(alt_rm_call+3)) = rc->cs;
- alt_rm_call[5] = 0xCF; /* IRET */
-
- /* replace real-mode interrupt vector */
- _cli();
- oe = ((uint32_t*)0x00000000)[ALT_INT];
- ((uint32_t*)0x00000000)[ALT_INT] =
- (((uint32_t)alt_rm_call >> 4UL) << 16UL) | /* seg */
- ((uint32_t)alt_rm_call & 0xFUL); /* ofs */
- _sti();
-
- /* call it! */
- __asm {
- mov ax,0x0300
- mov bx,ALT_INT
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-
- /* restore interrupt vector */
- _cli();
- ((uint32_t*)0x00000000)[ALT_INT] = oe;
- _sti();
-
- return 1;
-}
-
-int dpmi_alternate_rm_call_stacko(struct dpmi_realmode_call *rc) {
- uint32_t oe;
-
- if (alt_rm_call == NULL) {
- alt_rm_call = dpmi_alloc_dos(32,&alt_rm_call_sel);
- if (alt_rm_call == NULL) {
- fprintf(stderr,"FATAL: DPMI alternate call: cannot alloc\n");
- return 0;
- }
- }
-
- /* Fuck you DOS4/GW! */
- /* prepare executable code */
- {
- static unsigned char code[] = {
- 0xFC, /* CLD */
- 0x8C,0xD0, /* MOV AX,SS */
- 0x8E,0xD8, /* MOV DS,AX */
- 0x8E,0xC0, /* MOV ES,AX */
- 0x89,0xE5, /* MOV BP,SP */
- 0x8D,0x76,0x06, /* LEA SI,[BP+6] <- 6 byte interrupt stack */
- 0x83,0xEC,0x20, /* SUB SP,0x20 */
- 0xB9,0x10,0x00, /* MOV CX,0x10 */
- 0x89,0xE7, /* MOV DI,SP */
- 0xF3,0xA5 /* REP MOVSW */
- };
- memcpy(alt_rm_call,code,0x16);
- }
-
- alt_rm_call[0x16] = 0x9A; /* CALL FAR IMM */
- *((uint16_t*)(alt_rm_call+0x16+1)) = rc->ip;
- *((uint16_t*)(alt_rm_call+0x16+3)) = rc->cs;
- alt_rm_call[0x16+5] = 0x89; /* MOV SP,BP */
- alt_rm_call[0x16+6] = 0xEC;
- alt_rm_call[0x16+7] = 0xCF; /* IRET */
-
- /* replace real-mode interrupt vector */
- _cli();
- oe = ((uint32_t*)0x00000000)[ALT_INT];
- ((uint32_t*)0x00000000)[ALT_INT] =
- (((uint32_t)alt_rm_call >> 4UL) << 16UL) | /* seg */
- ((uint32_t)alt_rm_call & 0xFUL); /* ofs */
- _sti();
-
- /* call it! */
- __asm {
- mov ax,0x0300
- mov bx,ALT_INT
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-
- /* restore interrupt vector */
- _cli();
- ((uint32_t*)0x00000000)[ALT_INT] = oe;
- _sti();
-
- return 1;
-}
-#undef ALT_INT
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void mux_realmode_2F_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x002F
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-#endif
-#if TARGET_MSDOS == 16 && defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void mux_realmode_2F_call(struct dpmi_realmode_call far *rc) {
- __asm {
- push es
- mov ax,0x0300
- mov bx,0x002F
- xor cx,cx
- mov di,word ptr [rc+2]
- mov es,di
- mov di,word ptr [rc]
- int 0x31 ; call DPMI
- pop es
- }
-}
-#endif
-
+++ /dev/null
-/* emm.c
- *
- * Expanded Memory Manager library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-/* api library for DOS programs that want to use Expanded Memory (usually, EMM386.EXE)
- *
- * NOTES:
- * This code is intended for use with 16-bit real-mode programs. 32-bit programs have whatever the DOS extender
- * offers and have no need for expanded memory, in fact, the DOS extender will often take up all extended
- * & expanded memory for it's use and leave us nothing, which is why 32-bit builds of this library do not
- * function.
- *
- * Testing:
- *
- * YES* = Yes, if DOS underneath provides it (or if DOS, when configured to load EMM386.EXE). Otherwise, No
- *
- * System/configuration Works? Limit?
- * DOSBox 0.74 YES NO
- * DOSBox 0.74 +
- * Microsoft Windows 3.0
- * Real mode YES* NO
- * Standard mode NO -- EMM functions present, but will always report 0KB free. If more than 16MB of RAM is present, Windows causes a serious fault and DOSBox aborts
- * 386 Enhanced mode YES* ?
- * Microsoft Windows 3.1
- * Standard mode NO -- EMM functions present, but will always report 0KB free
- * 386 Enhanced mode YES* NO
- * Microsoft Windows 3.11
- * Standard mode NO -- EMM functions present, but will always report 0KB free
- * 386 Enhanced mode YES* NO
- * QEMU/VirtualBox
- * Microsoft Windows 95 (4.00.950)[1]
- * Normal mode YES* 64MB API usually reports 16MB free. The test VM had 96MB of RAM
- * Safe mode YES* 64MB
- * MS-DOS mode (official) YES* 32MB
- * MS-DOS mode (gui=0) YES* 32MB
- * Microsoft Windows 98 (4.10.1998)[1]
- * Normal mode YES* 64MB API usually reports 16MB free. The test VM had 96MB of RAM
- * MS-DOS mode (gui=0) YES* 32MB
- * Microsoft Windows ME (4.90.3000)[2]
- * Normal mode YES* 64MB The API will never report more than 16MB free, but you can hack
- * the PIF editor for the DOS program to allow up to 65534KB of
- * EMM memory. The test program seems to have no problem allocating
- * 48MB of expanded memory when said hack is applied. I suppose the
- * API could handle more, but remember limits are imposed by the
- * DOS Box VM and those are apparently represented by unsigned
- * 16-bit integers, thus the 64MB (65534KB) limit.
- * MS-DOS mode (bootdisk) ? ? I am unable to get Windows ME to make a bootdisk at this time.
- * So I attemped to use a Windows ME bootdisk from bootdisk.com,
- * and added DEVICE=EMM386.EXE only to find that at boot time
- * it locks up the computer! So, I have no way of knowing what
- * a pure MS-DOS mode EMM386.EXE from Windows ME does. It probably
- * acts just like the Windows 95/98 versions...
- * Microsoft Windows 2000 Professional
- * Normal mode YES 32MB For whatever reason NTVDM defaults to NOT providing EMM memory.
- * Limits to 32MB even if you type in larger values in the PIF editor.
- *
- * [1] EMM386.EXE for these systems will not be able to automatically find a page frame in QEMU or VirtualBox, probably because for
- * unmapped regions the emulator returns 0x00 not 0xFF. To work around that, open CONFIG.SYS in a text editor and edit the
- * line referring to EMM386.EXE. Add I=E000-EFFF and save. It should look like:
- *
- * DEVICE=C:\WINDOWS\EMM386.EXE I=E000-EFFF.
- *
- * [2] You're probably wondering... if Windows ME ignores AUTOEXEC.BAT and CONFIG.SYS then how the hell do you get EMM386.EXE
- * loaded? Well, it's very obscure and undocumented, but you can get it loaded on boot up as follows:
- *
- * 1. Go to the start menu, select "run" and type "notepad c:\windows\system.ini"
- * 2. Locate the [386Enh] section, go to the bottom of the section, and add the following lines of text to the end of [386Enh]
- *
- * EMMInclude=E000-EFFF
- * ReservePageFrame=yes
- *
- * 3. Reboot, and enjoy
- */
-#if !defined(TARGET_OS2) && !defined(TARGET_WINDOWS)
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/emm.h>
-
-unsigned char emm_status = 0xFF; /* initialize to 0xFF as a way of indicating that nobody checked yet */
-unsigned char emm_present = 0;
-unsigned char emm_version = 0;
-unsigned char emm_phys_pages = 0;
-unsigned short emm_total_pages = 0;
-unsigned int emm_page_frame_segment = 0;
-unsigned short emm_unallocated_pages = 0;
-struct emm_phys_page_map *emm_phys_map = NULL; /* maps physical page number -> segment address */
-static const char *devname = "EMMXXXX0";
-static const char *devname2 = "EMMQXXX0"; /* Microsoft publishes EMM standard then breaks it subtly in non-backwards compatible way... news at 11 */
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-static uint16_t emm_phys_map_sel = 0;
-
-static void emm_realmode_67_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x0067
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-#endif
-
-void emm_phys_pages_sort() {
- /* TODO */
-}
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
-void emm_update_page_count() {
- emm_unallocated_pages = 0;
- emm_total_pages = 0;
-
- if (!emm_present) return;
-
- __asm {
- mov ah,0x42
- push es
- int 0x67
- pop es
- mov emm_unallocated_pages,bx
- mov emm_total_pages,dx
- }
-}
-
-int probe_emm() {
- void far *emmptr;
-
- emm_present = 0;
- emmptr = (void far*)_dos_getvect(0x67);
- if (emmptr == (void far*)0)
- return 0;
-
- /* apparently 10 bytes into the segment there is the magic string */
- if ( _fmemcmp((char far*)MK_FP(FP_SEG(emmptr),0x000A),(char far*)devname,8) != 0 &&
- _fmemcmp((char far*)MK_FP(FP_SEG(emmptr),0x000A),(char far*)devname2,8) != 0)
- return 0;
-
- emm_present = 1;
- emm_phys_pages = 1;
- emm_page_frame_segment = 0;
-
- __asm {
- mov ah,0x40
- push es
- int 0x67
- pop es
- mov emm_status,ah
-
- mov ah,0x41
- push es
- int 0x67
- pop es
- or ah,ah
- jnz pfn_end
- mov emm_page_frame_segment,bx
-
- mov ah,0x46
- push es
- int 0x67
- pop es
- mov emm_version,al
-pfn_end:
- }
-
- if (emm_phys_map != NULL) {
- free(emm_phys_map);
- emm_phys_map = NULL;
- }
-
- if (emm_phys_map == NULL) {
- /* see if the EMM provides a mapping table describing the real-mode segments
- * corresponding to each physical page. if not, then assume only one page
- * available. the table could be up to 256 entries. the API really doesn't
- * have a way to tell us ahead of time, so assume the worst. */
- assert(sizeof(struct emm_phys_page_map) == (size_t)4);
- emm_phys_map = malloc(sizeof(struct emm_phys_page_map) * 256);
- if (emm_phys_map != NULL) {
- const unsigned int s = FP_SEG(emm_phys_map);
- const unsigned int o = FP_OFF(emm_phys_map);
- unsigned int c = 0;
- __asm {
- push es
- mov ax,0x5800
- mov di,s
- mov es,di
- mov di,o
- int 0x67
- or ah,ah
- jnz fail
- mov c,cx
-fail: pop es
- }
-
- if (c == 0) {
- free(emm_phys_map);
- emm_phys_map = NULL;
- }
- else {
- emm_phys_pages = c;
- if (c < 256) {
- void *x = realloc(emm_phys_map,sizeof(struct emm_phys_page_map) * c);
- if (x != NULL) { /* NTS: if we cannot realloc, well, too bad */
- emm_phys_map = x;
- }
- }
-
- /* WARNING: we are assuming several things about the table.
- * - That the table is sorted by real-mode segment (as described in the standard)
- * - There are no duplicate page numbers
- * - The table has as many entries as physical pages */
-
- /* do ourself a favor and sort by page number the table */
- emm_phys_pages_sort();
- }
- }
- }
-
- return 1;
-}
-
-int emm_alloc_pages(unsigned int pages) {
- int handle = -1;
-
- if (emm_present) {
- __asm {
- mov ah,0x43
- mov bx,pages
- push es
- int 0x67
- pop es
- or ah,ah
- jnz fail
- mov handle,dx
-fail:
- }
- }
-
- return handle;
-}
-
-int emm_free_pages(unsigned int handle) {
- int retv = 0;
-
- if (emm_present) {
- __asm {
- mov ah,0x45
- mov dx,handle
- push es
- int 0x67
- pop es
- or ah,ah
- jnz fail
- mov retv,1
-fail:
- }
- }
-
- return retv;
-}
-
-int emm_map_page(unsigned int handle,unsigned int phys_page,unsigned int log_page) {
- int retv = 0;
-
- if (phys_page >= (unsigned int)emm_phys_pages)
- return 0;
-
- if (emm_present) {
- __asm {
- mov ah,0x44
- mov al,byte ptr phys_page
- mov bx,log_page
- mov dx,handle
- push es
- int 0x67
- pop es
- or ah,ah
- jnz fail
- mov retv,1
-fail:
- }
- }
-
- return retv;
-}
-
-/* given physical page number, return real-mode segment value */
-unsigned short emm_last_phys_page_segment(unsigned int phys_page) {
- unsigned int i;
-
- if (phys_page >= (unsigned int)emm_phys_pages)
- return 0;
-
- /* if we don't have a copy of the EMM's mapping table, then assume that there is
- * only physical page 0 at the page frame address */
- if (phys_page == 0 && emm_phys_map == NULL)
- return emm_page_frame_segment;
-
- for (i=0;i < emm_phys_pages && emm_phys_map != NULL;i++) {
- struct emm_phys_page_map *me = emm_phys_map + i;
- if (phys_page == me->number)
- return me->segment;
- }
-
- return 0;
-}
-#else
-void emm_update_page_count() {
- emm_unallocated_pages = 0;
- emm_total_pages = 0;
-
- if (!emm_present) return;
-
- __asm {
- mov ah,0x42
- push es
- int 0x67
- pop es
- mov emm_unallocated_pages,bx
- mov emm_total_pages,dx
- }
-}
-
-int probe_emm() {/*32-bit*/
- unsigned int emm_seg;
-
- sanity();
- emm_present = 0;
- /* Tricky. The DOS extender would likely translate the vector, when what we
- really want is the segment value of int 67h */
- emm_seg = *((uint16_t*)((0x67 << 2) + 2));
- sanity();
-
- /* apparently 10 bytes into the segment there is the magic string */
- if ( memcmp((void*)(((unsigned long)emm_seg << 4UL) + 0x000A),devname,8) != 0 &&
- memcmp((void*)(((unsigned long)emm_seg << 4UL) + 0x000A),devname2,8) != 0)
- return 0;
-
- sanity();
- emm_present = 1;
- emm_phys_pages = 1;
- emm_page_frame_segment = 0;
-
- __asm {
- mov ah,0x40
- push es
- int 0x67
- pop es
- mov emm_status,ah
-
- mov ah,0x41
- push es
- int 0x67
- pop es
- or ah,ah
- jnz pfn_end
- mov word ptr emm_page_frame_segment,bx
-
- mov ah,0x46
- push es
- int 0x67
- pop es
- mov emm_version,al
-pfn_end:
- }
- sanity();
-
- if (emm_phys_map != NULL) {
- dpmi_free_dos(emm_phys_map_sel);
- emm_phys_map_sel = 0;
- emm_phys_map = NULL;
- }
-
- if (emm_phys_map == NULL) {
- /* see if the EMM provides a mapping table describing the real-mode segments
- * corresponding to each physical page. if not, then assume only one page
- * available. the table could be up to 256 entries. the API really doesn't
- * have a way to tell us ahead of time, so assume the worst. */
- assert(sizeof(struct emm_phys_page_map) == (size_t)4);
- emm_phys_map = dpmi_alloc_dos(sizeof(struct emm_phys_page_map) * 256,&emm_phys_map_sel);
- if (emm_phys_map != NULL) {
- const unsigned int s = ((uint32_t)emm_phys_map) >> 4;
- const unsigned int o = ((uint32_t)emm_phys_map) & 0xF;
- struct dpmi_realmode_call rc={0};
- unsigned int c = 0;
-
- rc.eax = 0x5800;
- rc.edi = o;
- rc.es = s;
- rc.ds = s;
- emm_realmode_67_call(&rc);
- if ((rc.eax&0xFF) == 0) c = rc.ecx & 0xFFFF;
-
- if (c == 0) {
- dpmi_free_dos(emm_phys_map_sel);
- emm_phys_map_sel = 0;
- emm_phys_map = NULL;
- }
- else {
- emm_phys_pages = c;
-
- /* WARNING: we are assuming several things about the table.
- * - That the table is sorted by real-mode segment (as described in the standard)
- * - There are no duplicate page numbers
- * - The table has as many entries as physical pages */
-
- /* do ourself a favor and sort by page number the table */
- emm_phys_pages_sort();
- }
- }
- }
-
- return 1;
-}
-
-int emm_alloc_pages(unsigned int pages) {
- int handle = -1;
-
- if (emm_present) {
- __asm {
- mov ah,0x43
- mov ebx,pages
- push es
- int 0x67
- pop es
- or ah,ah
- jnz fail
- and edx,0xFFFF
- mov handle,edx
-fail:
- }
- }
-
- return handle;
-}
-
-int emm_free_pages(unsigned int handle) {
- int retv = 0;
-
- if (emm_present) {
- __asm {
- mov ah,0x45
- mov edx,handle
- push es
- int 0x67
- pop es
- or ah,ah
- jnz fail
- mov retv,1
-fail:
- }
- }
-
- return retv;
-}
-
-int emm_map_page(unsigned int handle,unsigned int phys_page,unsigned int log_page) {
- int retv = 0;
-
- if (phys_page >= (unsigned int)emm_phys_pages)
- return 0;
-
- if (emm_present) {
- __asm {
- mov ah,0x44
- mov al,byte ptr phys_page
- mov ebx,log_page
- mov edx,handle
- push es
- int 0x67
- pop es
- or ah,ah
- jnz fail
- mov retv,1
-fail:
- }
- }
-
- return retv;
-}
-
-unsigned short emm_last_phys_page_segment(unsigned int phys_page) {
- unsigned int i;
-
- if (phys_page >= (unsigned int)emm_phys_pages)
- return 0;
-
- /* if we don't have a copy of the EMM's mapping table, then assume that there is
- * only physical page 0 at the page frame address */
- if (phys_page == 0 && emm_phys_map == NULL)
- return emm_page_frame_segment;
-
- for (i=0;i < emm_phys_pages && emm_phys_map != NULL;i++) {
- struct emm_phys_page_map *me = emm_phys_map + i;
- if (phys_page == me->number)
- return me->segment;
- }
-
- return 0;
-}
-#endif
-
-#endif /* !defined(TARGET_OS2) && !defined(TARGET_WINDOWS) */
-
+++ /dev/null
-/* himemsys.h
- *
- * Support calls to use HIMEM.SYS
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-
-/* HMA memory is present */
-#define HIMEM_F_HMA (1 << 0)
-/* HIMEM.SYS supports extended functions to address up to 4GB of RAM (surpassing the older API's 64MB limit) */
-#define HIMEM_F_4GB (1 << 1)
-
-extern unsigned char himem_sys_present;
-extern unsigned int himem_sys_version;
-extern unsigned long himem_sys_entry;
-extern unsigned char himem_sys_flags;
-extern unsigned long himem_sys_total_free;
-extern unsigned long himem_sys_largest_free;
-
-#pragma pack(push,1)
-struct himem_block_info {
- uint32_t block_length_kb;
- unsigned char lock_count;
- unsigned char free_handles;
-};
-#pragma pack(pop)
-
-int probe_himem_sys();
-int himem_sys_query_a20();
-int himem_sys_local_a20(int enable);
-int himem_sys_global_a20(int enable);
-void himem_sys_update_free_memory_status();
-int __cdecl himem_sys_alloc(unsigned long size/* in KB---not bytes*/);
-int himem_sys_move(unsigned int dst_handle,uint32_t dst_offset,unsigned int src_handle,uint32_t src_offset,uint32_t length);
-int __cdecl himem_sys_realloc(unsigned int handle,unsigned long size/* in KB---not bytes*/);
-int himem_sys_get_handle_info(unsigned int handle,struct himem_block_info *b);
-uint32_t himem_sys_lock(unsigned int handle);
-int himem_sys_unlock(unsigned int handle);
-int himem_sys_free(int handle);
-
-#endif /* !defined(TARGET_WINDOWS) && !defined(TARGET_OS2) */
-
+++ /dev/null
-/* lol.c
- *
- * Test program: Make use of the MS-DOS "List of Lists" to print various things
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-/* FIXME: MS-DOS 6.22 under QEMU: This hangs, or causes QEMU to crash? */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-
-int main() {
- int i,c,line = 0;
- unsigned char FAR *LOL;
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- printf(" Flavor: '%s'\n",dos_flavor_str(dos_flavor));
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (detect_dosbox_emu())
- printf("I am also running under DOSBox\n");
-
- if ((LOL = dos_list_of_lists()) != NULL) {
- printf("DOS List of Lists at ");
-#if TARGET_MSDOS == 32
- printf("0x%08lX\n",(unsigned long)LOL);
-#else
- printf("%04x:%04x\n",FP_SEG(LOL),FP_OFF(LOL));
-#endif
- }
- else {
- printf("Unable to locate the DOS 'list of lists'\n");
- return 0;
- }
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
-
- /* list MCBs */
- {
- struct dos_psp_cooked pspnfo;
- struct dos_mcb_enum men;
-
- if (dos_mcb_first(&men)) {
- printf("Resident MCBs\n"); line++;
- do {
- mcb_filter_name(&men);
-
- printf("[%04x]: %02x PSP=%04x size=%04x %-8s ",
- men.cur_segment,men.type,men.psp,men.size,men.name);
- for (i=0;i < 32;i++) {
- c = men.ptr[i];
- if (c >= 32 && c <= 126) printf("%c",c);
- else printf(".");
- }
- printf("\n");
-
- if (men.psp >= 0x80 && men.psp < 0xFFFFU && dos_parse_psp(men.psp,&pspnfo)) {
- printf(" PSP memsize=%04xh callpsp=%04xh env=%04xh command='%s'\n",
- pspnfo.memsize,pspnfo.callpsp,pspnfo.env,pspnfo.cmd);
-
- if (++line >= 20) {
- line -= 20;
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- }
-
- if (++line >= 20) {
- line -= 20;
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- } while (dos_mcb_next(&men));
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- }
-
- /* list devices */
- {
- struct dos_device_enum denu;
-
- if (dos_device_first(&denu)) {
- printf("Device drivers\n"); line++;
- do {
- printf(" ATTR=%04Xh entry=%04Xh int=%04Xh %s\n",denu.attr,denu.entry,denu.intent,denu.name);
-
- if (++line >= 20) {
- line -= 20;
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- } while (dos_device_next(&denu));
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-/* ntastrm.c
- *
- * Utility program: Manually trigger the removal of the DOSNTAST driver.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * If a program using DOSNTAST fails to unload the driver, it will remain resident.
- * This program allows you to remove it manually if that happens. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/dosntvdm.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- /* probe_dos() and detect_windows() should NOT auto-load the DOSNTAST driver.
- * we're going to unload it if resident. */
- lib_dos_option.dont_load_dosntast=1;
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- printf(" Method: '%s'\n",dos_version_method);
-
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%u\n",windows_version>>8,windows_version&0xFF);
- printf(" Method: '%s'\n",windows_version_method);
- if (windows_emulation != WINEMU_NONE)
- printf(" Emulation: '%s'\n",windows_emulation_str(windows_emulation));
- if (windows_emulation_comment_str != NULL)
- printf(" Emulation comment: '%s'\n",windows_emulation_comment_str);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
- printf("DOSNTAST.VDD driver was loaded (handle=%u), unloading...\n",ntvdm_dosntast_handle);
- ntvdm_dosntast_unload();
- }
-#endif
-
- return 0;
-}
-
+++ /dev/null
-
-DOS support library
- dos.obj ......................... Helper functions for DOS I/O to far and huge memory
- emm.obj ......................... Utility library to make use of the Expanded Memory Manager (usually, EMM386.EXE)
- dosbox.obj ...................... Utility function to detect if we're running in the DOSBox emulator
- biosext.obj ..................... Utility function for real-mode software to use BIOS INT 15H AH=0x87 extended memory copy function
- himemsys.obj .................... Utility library to make use of Extended Memory via HIMEM.SYS
+++ /dev/null
-/* test.c
- *
- * Test program: Various info about DOS
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/dosntvdm.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- printf(" Method: '%s'\n",dos_version_method);
- printf(" Flavor: '%s'\n",dos_flavor_str(dos_flavor));
- if (dos_flavor == DOS_FLAVOR_FREEDOS) {
- printf(" FreeDOS kernel %u.%u.%u (%lX)\n",
- (unsigned int)((freedos_kernel_version >> 16UL) & 0xFFUL),
- (unsigned int)((freedos_kernel_version >> 8UL) & 0xFFUL),
- (unsigned int)((freedos_kernel_version) & 0xFFUL),
- (unsigned long)freedos_kernel_version);
- if (freedos_kernel_version_str != NULL) {
-#if TARGET_MSDOS == 32
- printf(" FreeDOS kernel version string: %s\n",
- freedos_kernel_version_str);
-#else
- printf(" FreeDOS kernel version string: %Fs\n",
- freedos_kernel_version_str);
-#endif
- }
- }
-
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%u\n",windows_version>>8,windows_version&0xFF);
- printf(" Method: '%s'\n",windows_version_method);
- if (windows_emulation != WINEMU_NONE)
- printf(" Emulation: '%s'\n",windows_emulation_str(windows_emulation));
- if (windows_emulation_comment_str != NULL)
- printf(" Emulation comment: '%s'\n",windows_emulation_comment_str);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
- OSVERSIONINFO o;
- WAVEOUTCAPS woc;
- unsigned int i,j;
- uint32_t dw;
-
- printf("This program is using the DOSNTAST.VDD driver (handle=%u io=0x%03X)\n",ntvdm_dosntast_handle,ntvdm_dosntast_io_base);
-
- printf("GetTickCount() = %lu\n",ntvdm_dosntast_GetTickCount());
- printf("waveOutGetNumDevs() = %d\n",j=ntvdm_dosntast_waveOutGetNumDevs());
- for (i=0;i < j;i++) {
- memset(&woc,0,sizeof(woc));
- if ((dw=ntvdm_dosntast_waveOutGetDevCaps(i,&woc,sizeof(woc))) == 0) {
- printf(" [%u]: %s v%u.%u\n",i,woc.szPname,woc.vDriverVersion>>8,woc.vDriverVersion&0xFF);
- printf(" MID=0x%04lX PID=0x%04lX FMTS=0x%08lX chan=%u\n",
- (unsigned long)woc.wMid,
- (unsigned long)woc.wPid,
- (unsigned long)woc.dwFormats,
- woc.wChannels);
- printf(" CAPS: ");
- if (woc.dwSupport & WAVECAPS_LRVOLUME) printf("LRVOL ");
- if (woc.dwSupport & WAVECAPS_PITCH) printf("PITCH ");
- if (woc.dwSupport & WAVECAPS_PLAYBACKRATE) printf("PLAYRATE ");
- if (woc.dwSupport & WAVECAPS_SYNC) printf("SYNC ");
- if (woc.dwSupport & WAVECAPS_VOLUME) printf("VOL ");
- if (woc.dwSupport & WAVECAPS_SAMPLEACCURATE) printf("SAMPLEACCURATE ");
- printf("\n");
- }
- else {
- printf(" [%u]: Cannot read err=0x%08lX\n",i,dw);
- }
- }
-
- printf("GetVersionEx() = ");
- o.dwOSVersionInfoSize = sizeof(o);
- if (ntvdm_dosntast_getversionex(&o)) {
- printf("v%lu.%lu build #%lu platform=%lu '%s'",
- o.dwMajorVersion,
- o.dwMinorVersion,
- o.dwBuildNumber,
- o.dwPlatformId,
- o.szCSDVersion);
- }
- else {
- printf("failed?");
- }
- printf("\n");
-
- ntvdm_dosntast_MessageBox("Hello!\n\nIf you can read this, DOS programs are able to use the driver successfully!");
- }
-#endif
-
- if (detect_dosbox_emu())
- printf("I am also running under DOSBox\n");
- if (detect_virtualbox_emu())
- printf("I am also running under Sun/Oracle VirtualBox %s\n",virtualbox_version_str);
-
- probe_dpmi();
-#if dpmi_present != 0
- if (dpmi_present) {
- printf("DPMI present:\n");
-# if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
- if (dpmi_no_0301h > 0) printf(" - DPMI function 0301H: Call real-mode far routine NOT AVAILABLE\n");
- printf(" - Flags: 0x%04x\n",dpmi_flags);
- printf(" - Entry: %04x:%04x (real mode)\n",(unsigned int)(dpmi_entry_point>>16UL),(unsigned int)(dpmi_entry_point & 0xFFFFUL));
- printf(" - Processor type: %02x\n",dpmi_processor_type);
- printf(" - Version: %u.%u\n",dpmi_version>>8,dpmi_version&0xFF);
- printf(" - Private data length: %u paras\n",dpmi_private_data_length_paragraphs);
-# endif
- }
-#endif
-
- if (probe_vcpi()) {
- printf("VCPI present (v%d.%d)\n",
- vcpi_major_version,
- vcpi_minor_version);
- }
-
-#ifdef WINFCON_STOCK_WIN_MAIN
- {
- char c;
-
- printf("---------[Type junk here]---------\n");
- do {
- c = getch();
- if (c == 27) break;
- else if (c == 13) printf("\n");
- else printf("%c",c);
- } while (1);
- }
-#endif
-
- return 0;
-}
-
+++ /dev/null
-/* testbext.c
- *
- * Test program: Use INT 15h to copy extended memory.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * This program shows that the API works, and also reveals whether or not
- * the BIOS API is limited to 16MB. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/biosext.h>
-
-int main() {
-#if TARGET_MSDOS == 16
- {
- unsigned int i;
- unsigned long addr;
- unsigned char tmp[16];
-
- printf("Copying data out of extended memory via BIOS\n");
- for (addr=0xFFF80UL;addr < 0x100000UL;addr += sizeof(tmp)) {
- memset(tmp,0,sizeof(tmp));
- if (bios_extcopy(ptr2phys(tmp),addr,16)) {
- printf("Problem copying\n");
- break;
- }
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- for (i=0;i < 16;i++) printf("%c",tmp[i] >= 32 ? tmp[i] : ' ');
- printf("\n");
- }
- while (getch() != 13);
-
- printf("Copying data out of extended memory via BIOS (16MB higher)\n");
- for (addr=0x10FFF80UL;addr < 0x1100000UL;addr += sizeof(tmp)) {
- memset(tmp,0,sizeof(tmp));
- if (bios_extcopy(ptr2phys(tmp),addr,16)) {
- printf("Problem copying\n");
- break;
- }
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- for (i=0;i < 16;i++) printf("%c",tmp[i] >= 32 ? tmp[i] : ' ');
- printf("\n");
- }
- while (getch() != 13);
- }
-#else
- printf("Test does not apply to 32-bit builds\n");
-#endif
-
- return 0;
-}
-
+++ /dev/null
-/* testdpmi.c
- *
- * Test program: DPMI entry/exit functions
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-
-#ifdef TARGET_WINDOWS
-#error wrong target
-#endif
-
-int main(int argc,char **argv) {
- unsigned char want = DPMI_ENTER_AUTO;
-
- if (argc > 1) {
- want = atoi(argv[1]);
- if (want < 16 || want > 32) return 1;
- }
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- printf(" Method: '%s'\n",dos_version_method);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- printf(" Method: '%s'\n",windows_version_method);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- probe_dpmi();
- if (!dpmi_present) {
- printf("This test requires DPMI\n");
- return 1;
- }
-
- printf("DPMI present:\n");
-#if dpmi_no_0301h != 0
- if (dpmi_no_0301h > 0) printf(" - DPMI function 0301H: Call real-mode far routine NOT AVAILABLE\n");
-#endif
- printf(" - Flags: 0x%04x\n",dpmi_flags);
- printf(" - Entry: %04x:%04x (real mode)\n",(unsigned int)(dpmi_entry_point>>16UL),(unsigned int)(dpmi_entry_point & 0xFFFFUL));
- printf(" - Processor type: %02x\n",dpmi_processor_type);
- printf(" - Version: %u.%u\n",dpmi_version>>8,dpmi_version&0xFF);
- printf(" - Private data length: %u paras\n",dpmi_private_data_length_paragraphs);
-
- /* enter DPMI. the routine will briefly run in protected mode before finding it's way
- * back to real mode where it can return back to this function */
- if (!dpmi_enter(want)) {
- printf("Unable to enter DPMI server\n");
- return 1;
- }
- printf("Allocated DPMI private segment: 0x%04x\n",dpmi_private_data_segment);
- printf("DPMI entered as %u-bit.\n",dpmi_entered);
- printf(" - PM CS:%04x DS:%04x ES:%04x SS:%04x\n",dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss);
- printf(" - Real to protected entry: %04x:%04x [rmode]\n",
- (unsigned int)(dpmi_pm_entry>>16UL),(unsigned int)(dpmi_pm_entry&0xFFFFUL));
- if (dpmi_entered == 32)
- printf(" - Protected to real entry: %04x:%08lx [pmode]\n",
- (unsigned int)((dpmi_rm_entry>>32ULL)&0xFFFFUL),(unsigned long)(dpmi_rm_entry&0xFFFFFFFFUL));
- else
- printf(" - Protected to real entry: %04x:%04x [pmode]\n",
- (unsigned int)(dpmi_rm_entry>>16UL),(unsigned int)(dpmi_rm_entry&0xFFFFUL));
-
- return 0;
-}
-
+++ /dev/null
-/* testemm.c
- *
- * Test program: Expanded Memory Manager functions
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/emm.h>
-#include <hw/dos/doswin.h>
-
-static const char *message = "Hello world. How are you?";
-static const char *message2 = "Pingas. Sup dawg. Hello world. Dork. Hahahajajaja.";
-static char tmp[128],tmp2[128];
-
-#if 1
-# define x_memcpy(a,b,c) memcpy(a,b,c)
-#else
-/* what have we come to when friggin' memcpy() causes a GPF?!? */
-static void x_memcpy(unsigned char *dst,const unsigned char *src,size_t c) {
- fprintf(stderr,"memcpy %p -> %p (%lu)\n",
- dst,src,(unsigned long)c);
-
- while (c != 0) {
- *dst++ = *src++;
- c--;
- }
-}
-#endif
-
-int main() {
- size_t message_l = strlen(message),message2_l = strlen(message2);
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- sanity();
- if (probe_emm()) {
- int h1,h2,h3;
-
- sanity();
- printf("Expanded memory manager present. Status = 0x%02x Page frame @0x%04x v%x.%x\n",emm_status,emm_page_frame_segment,emm_version>>4,emm_version&0x0F);
- emm_update_page_count();
- sanity();
- printf(" Unallocated pages: %u (%luKB)\n",
- emm_unallocated_pages,
- (unsigned long)emm_unallocated_pages << 4UL); /* 2^14 = 16384 */
- printf(" Total pages: %u (%luKB)\n",
- emm_total_pages,
- (unsigned long)emm_total_pages << 4UL);
- printf(" Physical pages: %u (%luKB)\n",
- emm_phys_pages,
- (unsigned long)emm_phys_pages << 4UL);
-
- while (getch() != 13);
- sanity();
-
- /* print out the mapping table, if available */
- if (emm_phys_map != NULL) {
- struct emm_phys_page_map *me;
- unsigned int i;
-
- printf("Physical page to segment table\n");
- for (i=0;i < emm_phys_pages;i++) {
- me = emm_phys_map + i;
- printf(" %02x: 0x%04x",me->number,me->segment);
- if ((i%5) == 4) printf("\n");
- }
- printf("\n");
- sanity();
- }
-
- printf("Allocating EMM pages (1): ");
- h1 = emm_alloc_pages(1);
- sanity();
- if (h1 >= 0) {
- printf("OK, handle=%u\n",h1);
- if (!emm_free_pages(h1)) printf("cannot free\n");
- }
- else printf("FAILED\n");
-
- printf("Allocating EMM pages (16KB): ");
- h1 = emm_alloc_pages(1);
- sanity();
- if (h1 >= 0) printf("OK, handle=%u\n",h1);
- else printf("FAILED\n");
-
- printf("Allocating EMM pages (1MB): ");
- h2 = emm_alloc_pages(0x100000UL >> 14UL);
- sanity();
- if (h2 >= 0) printf("OK, handle=%u\n",h2);
- else printf("FAILED\n");
-
- printf("Allocating EMM pages (12MB): ");
- h3 = emm_alloc_pages(0xC00000UL >> 14UL);
- sanity();
- if (h3 >= 0) printf("OK, handle=%u\n",h3);
- else printf("FAILED\n");
-
- while (getch() != 13);
-
- if (h1 >= 0 && !emm_free_pages(h1)) printf("Cannot free\n");
- sanity();
- if (h2 >= 0 && !emm_free_pages(h2)) printf("Cannot free\n");
- sanity();
- if (h3 >= 0 && !emm_free_pages(h3)) printf("Cannot free\n");
- sanity();
-
- printf("Allocating EMM pages (32KB): ");
- h1 = emm_alloc_pages(2);
- sanity();
- if (h1 >= 0) {
- printf("OK, handle=%u\n",h1);
- if (emm_map_page(h1,/*physical*/0,/*logical*/0)) {
- unsigned int segm = emm_last_phys_page_segment(0);
- printf("Seg %04x\n",segm);
- sanity();
- if (segm > 0) {
-#if TARGET_MSDOS == 16
- char far *ptr = MK_FP(segm,0);
-#else
- char *ptr = (char*)(segm << 4UL);
-#endif
-
-#if TARGET_MSDOS == 16
- _fmemcpy(ptr,(char far*)message,message_l+1);
- _fmemcpy((char far*)tmp,ptr,message_l+1);
-#else
- x_memcpy(ptr,message,message_l+1);
- x_memcpy(tmp,ptr,message_l+1);
-#endif
- printf("After writing message there, I read back: '%s'\n",tmp);
-
- if (!emm_map_page(h1,0,1)) printf("Cannot remap\n");
-
-#if TARGET_MSDOS == 16
- _fmemcpy(ptr,(char far*)message2,message2_l+1);
- _fmemcpy((char far*)tmp,ptr,message2_l+1);
-#else
- x_memcpy(ptr,message2,message2_l+1);
- x_memcpy(tmp,ptr,message2_l+1);
-#endif
- printf("After mapping to page 2 and writing there, I read back: '%s'\n",tmp);
-
- if (!emm_map_page(h1,0,0)) printf("Cannot remap\n");
-
-#if TARGET_MSDOS == 16
- _fmemcpy((char far*)tmp,ptr,message_l+1);
-#else
- x_memcpy(tmp,ptr,message_l+1);
-#endif
- printf("After mapping back to 1, I read back: '%s'\n",tmp);
-
- if (emm_map_page(h1,0,2)) printf("Whoops, I was able to map logical pages beyond what I allocated\n");
- }
- else {
- printf("Cannot get segment\n");
- }
- if (!emm_map_page(h1,0,0xFFFF)) printf("Cannot unmap\n");
- }
- else {
- printf("Cannot map\n");
- }
- if (!emm_free_pages(h1)) printf("Cannot free\n");
- }
- else printf("FAILED\n");
-
- printf("Allocating EMM pages (32KB): ");
- h1 = emm_alloc_pages(2);
- if (h1 >= 0) {
- printf("OK, handle=%u\n",h1);
- if ( emm_map_page(h1,/*physical*/0,/*logical*/0) &&
- emm_map_page(h1,/*physical*/1,/*logical*/1)) {
- unsigned int seg1 = emm_last_phys_page_segment(0);
- unsigned int seg2 = emm_last_phys_page_segment(1);
- printf("Seg %04x,%04x\n",seg1,seg2);
- if (seg1 > 0 && seg2 > 0) {
-#if TARGET_MSDOS == 16
- char far *ptr1 = MK_FP(seg1,0);
- char far *ptr2 = MK_FP(seg2,0);
-#else
- char *ptr1 = (char*)(seg1 << 4UL);
- char *ptr2 = (char*)(seg2 << 4UL);
-#endif
-
-#if TARGET_MSDOS == 16
- _fmemcpy(ptr1,(char far*)message,message_l+1);
- _fmemcpy(ptr2,(char far*)message2,message2_l+1);
-#else
- memcpy(ptr1,message,message_l+1);
- memcpy(ptr2,message2,message2_l+1);
-#endif
-
-#if TARGET_MSDOS == 16
- _fmemcpy((char far*)tmp,ptr1,message_l+1);
- _fmemcpy((char far*)tmp2,ptr2,message2_l+1);
-#else
- memcpy(tmp,ptr1,message_l+1);
- memcpy(tmp2,ptr2,message2_l+1);
-#endif
-
- printf("After writing message there, I read back:\n'%s'\n'%s'\n",tmp,tmp2);
-
- /* now swap the pages */
- if (!emm_map_page(h1,1,0)) printf("cannot map log 1 -> phys 0\n");
- if (!emm_map_page(h1,0,1)) printf("cannot map log 0 -> phys 1\n");
-
-#if TARGET_MSDOS == 16
- _fmemcpy((char far*)tmp,ptr1,message2_l+1);
- _fmemcpy((char far*)tmp2,ptr2,message_l+1);
-#else
- memcpy(tmp,ptr1,message2_l+1);
- memcpy(tmp2,ptr2,message_l+1);
-#endif
-
- printf("After swapping pages, I read back:\n'%s'\n'%s'\n",tmp,tmp2);
- }
- else {
- printf("Cannot get segment\n");
- }
- if (!emm_map_page(h1,0,0xFFFF) || !emm_map_page(h1,1,0xFFFF)) printf("Cannot unmap\n");
- }
- else {
- printf("Cannot map\n");
- }
- if (!emm_free_pages(h1)) printf("Cannot free\n");
- }
- else printf("FAILED\n");
-
- /* we do this test because Microsoft EMM386.EXE seems to max out at 32MB.
- * the host could have 256MB of total memory and it would still report 32MB in EMS */
- printf("Allocating EMM pages (48MB): ");
- h1 = emm_alloc_pages((48UL << 20UL) >> 14UL);
- if (h1 >= 0) {
- printf("OK, handle=%u\n",h1);
- if (!emm_free_pages(h1)) printf("cannot free\n");
- }
- else printf("FAILED\n");
-
- printf("Allocating EMM pages (96MB): ");
- h1 = emm_alloc_pages((96UL << 20UL) >> 14UL);
- if (h1 >= 0) {
- printf("OK, handle=%u\n",h1);
- if (!emm_free_pages(h1)) printf("cannot free\n");
- }
- else printf("FAILED\n");
- }
-
- return 0;
-}
-
+++ /dev/null
-/* testsmrt.c
- *
- * Test program: Demonstrate SMARTDRV detection code.
- * (C) 2014 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-
-int main() {
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- printf(" Flavor: '%s'\n",dos_flavor_str(dos_flavor));
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (smartdrv_detect()) {
- printf("SMARTDRV %u.%02u detected!\n",smartdrv_version>>8,smartdrv_version&0xFF);
- printf("Now flushing\n");
- smartdrv_flush();
- printf("Made it.\n");
- smartdrv_close();
- }
-
- return 0;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/tgusmega.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-struct mega_em_info megaem_info={0};
-
-int gravis_mega_em_detect(struct mega_em_info *x) {
-/* TODO: Cache results, only need to scan once */
- union REGS regs={0};
- regs.w.ax = 0xFD12;
- regs.w.bx = 0x3457;
-#if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-#else
- int86(0x21,®s,®s);
-#endif
- if (regs.w.ax == 0x5678) {
- x->intnum = regs.h.cl;
- x->version = regs.w.dx;
- x->response = regs.w.bx;
-
- if (x->version == 0) {
- if (x->response == 0x1235)
- x->version = 0x200;
- else if (x->response == 0x1237)
- x->version = 0x300;
- }
- return 1;
- }
- return 0;
-}
-#endif
-
+++ /dev/null
-
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-# define HAVE_GUS_MEGAEM_DETECT
-struct mega_em_info {
- unsigned char intnum;
- uint16_t version;
- uint16_t response;
-};
-
-extern struct mega_em_info megaem_info;
-
-int gravis_mega_em_detect(struct mega_em_info *x);
-#endif
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/tgussbos.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* returns interrupt vector */
-/* these functions are duplicates of the ones in the ULTRASND library
- because it matters to this library whether or not we're talking to
- Gravis Ultrasound and shitty SB emulation */
-int gravis_sbos_detect() {
- unsigned char FAR *ex;
- uint16_t s,o;
- int i = 0x78;
-
- while (i < 0x90) {
-#if TARGET_MSDOS == 32
- o = *((uint16_t*)(i*4U));
- s = *((uint16_t*)((i*4U)+2U));
-#else
- o = *((uint16_t far*)MK_FP(0,(uint16_t)i*4U));
- s = *((uint16_t far*)MK_FP(0,((uint16_t)i*4U)+2U));
-#endif
-
- if (o == 0xFFFF || s == 0x0000 || s == 0xFFFF) {
- i++;
- continue;
- }
-
- /* we're looking for "SBOS" signature */
-#if TARGET_MSDOS == 32
- ex = (unsigned char*)((s << 4UL) + 0xA);
- if (memcmp(ex,"SBOS",4) == 0) return i;
-#else
- ex = MK_FP(s,0xA);
- if (_fmemcmp(ex,"SBOS",4) == 0) return i;
-#endif
-
- i++;
- }
-
- return -1;
-}
-#endif
-
+++ /dev/null
-
-int gravis_sbos_detect();
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/tgusumid.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* returns interrupt vector */
-int gravis_ultramid_detect() {
- unsigned char FAR *ex;
- uint16_t s,o;
- int i = 0x78;
-
- while (i < 0x90) {
-#if TARGET_MSDOS == 32
- o = *((uint16_t*)(i*4U));
- s = *((uint16_t*)((i*4U)+2U));
-#else
- o = *((uint16_t far*)MK_FP(0,(uint16_t)i*4U));
- s = *((uint16_t far*)MK_FP(0,((uint16_t)i*4U)+2U));
-#endif
-
- if (o == 0xFFFF || s == 0x0000 || s == 0xFFFF) {
- i++;
- continue;
- }
-
- /* we're looking for "ULTRAMID" signature */
-#if TARGET_MSDOS == 32
- ex = (unsigned char*)((s << 4UL) + 0x103);
- if (memcmp(ex,"ULTRAMID",8) == 0) return i;
-#else
- ex = MK_FP(s,0x103);
- if (_fmemcmp(ex,"ULTRAMID",8) == 0) return i;
-#endif
-
- i++;
- }
-
- return -1;
-}
-#endif /* !defined(TARGET_WINDOWS) */
-
+++ /dev/null
-
-int gravis_ultramid_detect();
-
+++ /dev/null
--fr=nul -fo=dos386f/.obj -i=.. -i../.. -e=2 -zq -mf -d0 -bt=dos -oilrtfm -wx -fp3 -3r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=386 -DMMODE=f -q dosdpmi.c
+++ /dev/null
-/* tstbiom.c
- *
- * Test program: BIOS extended memory layout and reporting
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/biosmem.h>
-
-int main() {
-#if TARGET_MSDOS == 16
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- {
- unsigned int l;
- if (biosmem_size_88(&l)) {
- printf("BIOS memory (INT 15H AH=0x88)\n");
- printf(" Total memory: %uKB (%uMB)\n",l,l >> 10UL);
- }
- }
-
- {
- unsigned int l,h;
- if (biosmem_size_E801(&l,&h)) {
- printf("BIOS memory (INT 15H AX=0xE801)\n");
- printf(" Total memory: 1MB + %uKB + %luKB = %luKB (%luMB)\n",
- l,(unsigned long)h * 64UL,(unsigned long)l + ((unsigned long)h * 64UL) + 1024UL,
- ((unsigned long)l + ((unsigned long)h * 64UL) + 1024UL) >> 10UL);
- if (l != 0) printf(" 1-16MB: 0x%08lX-0x%08lX\n",0x100000UL,0x100000UL + ((unsigned long)l << 10UL) - 1UL);
- if (h != 0) printf(" 16MB+: 0x%08lX-0x%08lX\n",0x1000000UL,0x1000000UL + ((unsigned long)h << 16UL) - 1UL);
- }
- }
-
- {
- struct bios_E820 nfo;
- unsigned long index,pindex;
- int len;
-
- index = pindex = 0;
- if ((len=biosmem_size_E820(&index,&nfo)) > 0) {
- printf("BIOS memory (INT 15H AX=E820)\n");
- do {
- printf(" len=%u index=0x%02lX 0x%012llx-0x%012llx type=0x%02lx attr=0x%02lx\n",
- len,(unsigned long)pindex,
- (unsigned long long)nfo.base,
- (unsigned long long)(nfo.base + nfo.length - 1ULL),
- nfo.type,nfo.ext_attributes);
- if (index == 0) break; /* the BIOS will return with EBX == 0 when returning the last item */
- pindex = index;
- } while ((len=biosmem_size_E820(&index,&nfo)) > 0);
- }
- }
-#else /* == 32 */
- printf("This program is pointless in 32-bit protected mode\n");
-#endif
- return 0;
-}
-
+++ /dev/null
-/* tstlp.c
- *
- * Test program: DOS memory map awareness library
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-
-#if TARGET_MSDOS == 32
-uint16_t cpu_read_my_cs() {
- uint16_t r=0;
-
- __asm {
- push cs
- pop ax
- mov r,ax
- }
-
- return r;
-}
-#endif
-
-int main() {
-#if TARGET_MSDOS == 32
- uint16_t sg;
- int c;
-#endif
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (detect_dosbox_emu())
- printf("I am also running under DOSBox\n");
-
-#if TARGET_MSDOS == 16
- /* TODO: Someday the dos_ltp() code will work in 16-bit mode, for environments like EMM386.EXE v86 or from within
- * the 16-bit Windows 3.1 world */
- printf("This program is intended to test memory mapping under 32-bit protected mode and does not apply to 16-bit real mode\n");
-#else
- if (!dos_ltp_probe()) {
- printf("DOS linear->physical translation probe failed\n");
- return 1;
- }
-
- sg = cpu_read_my_cs();
- printf("Results:\n");
- printf(" Paging: %u (CPU paging enabled)\n",dos_ltp_info.paging);
- printf(" DOS remap: %u (memory below 1MB is remapped, not 1:1)\n",dos_ltp_info.dos_remap);
- printf(" Should lock pages: %u (Extender may page to disk or move pages)\n",dos_ltp_info.should_lock_pages);
- printf(" Can't xlate: %u (No way to determine physical mem addr)\n",dos_ltp_info.cant_xlate);
- printf(" Using PAE: %u (DOS extender is using PAE)\n",dos_ltp_info.using_pae);
- printf(" DMA DOS xlate: %u (DMA is translated too, virtualized)\n",dos_ltp_info.dma_dos_xlate);
- printf(" use VCPI xlate: %u (VCPI server can provide translation)\n",dos_ltp_info.vcpi_xlate);
- printf(" CR0: 0x%08lx\n",dos_ltp_info.cr0);
- printf(" CR3: 0x%08lx\n",dos_ltp_info.cr3);
- printf(" CR4: 0x%08lx\n",dos_ltp_info.cr4);
- printf(" CS: 0x%04x %s CPL=%u\n",(unsigned int)sg,sg & 4 ? "LDT" : "GDT",sg&3);
-
- while ((c=getch()) != 13) {
- if (c == 27) return 1;
- }
-
- {
- uint32_t l;
- uint64_t p;
- int line=0;
-
- printf("Map test (32MB):\n");
- for (l=0;l < (32UL << 20UL);l += 4096) {
- printf("0x%08lX: ",l); fflush(stdout);
- p = dos_linear_to_phys(l);
- if (p == DOS_LTP_FAILED) printf("N/A\n");
- else printf("0x%08llX\n",p);
-
- if (++line >= 24) {
- line -= 24;
- while ((c=getch()) != 13) {
- if (c == 27) return 1;
- }
- }
- }
- }
-#endif
-
- return 0;
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* Watcom C does not provide getvect/setvect for Win16, so we abuse the DPMI server within and provide one anyway */
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-void far *win16_getexhandler(unsigned char n) {
- unsigned short s=0,o=0;
-
- __asm {
- mov ax,0x202
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,dx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int win16_setexhandler(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x),o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x203
- mov bl,n
- mov cx,s
- mov dx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-void far *win16_getvect(unsigned char n) {
- unsigned short s=0,o=0;
-
- __asm {
- mov ax,0x204
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,dx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int win16_setvect(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x),o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x205
- mov bl,n
- mov cx,s
- mov dx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-
-/* if provided by the system, these functions allow library and application code to call out to the Win32 world from Win16.
- * Which is absolutely necessary given that Win16 APIs tend to lie for compatibility reasons. */
-
-DWORD genthunk32w_ntdll = 0;
-DWORD genthunk32w_kernel32 = 0;
-DWORD genthunk32w_kernel32_GetVersion = 0;
-DWORD genthunk32w_kernel32_GetVersionEx = 0;
-DWORD genthunk32w_kernel32_GetLastError = 0;
-BOOL __GenThunksExist = 0;
-BOOL __GenThunksChecked = 0;
-DWORD (PASCAL FAR *__LoadLibraryEx32W)(LPCSTR lpName,DWORD reservedhfile,DWORD dwFlags) = NULL;
-BOOL (PASCAL FAR *__FreeLibrary32W)(DWORD hinst) = NULL;
-DWORD (PASCAL FAR *__GetProcAddress32W)(DWORD hinst,LPCSTR name) = NULL;
-DWORD (PASCAL FAR *__GetVDMPointer32W)(LPVOID ptr,UINT mask) = NULL;
-DWORD (PASCAL FAR *__CallProc32W)(DWORD procaddr32,DWORD convertMask,DWORD params,...) = NULL; /* <- FIXME: How to use? */
-DWORD (_cdecl _far *__CallProcEx32W)(DWORD params,DWORD convertMask,DWORD procaddr32,...) = NULL;
-
-int genthunk32_init() {
- if (!__GenThunksChecked) {
- HMODULE kern32;
-
- genthunk32_free();
- __GenThunksExist = 0;
- __GenThunksChecked = 1;
- kern32 = GetModuleHandle("KERNEL");
- if (kern32 != NULL) {
- __LoadLibraryEx32W = (void far*)GetProcAddress(kern32,"LOADLIBRARYEX32W");
- __FreeLibrary32W = (void far*)GetProcAddress(kern32,"FREELIBRARY32W");
- __GetProcAddress32W = (void far*)GetProcAddress(kern32,"GETPROCADDRESS32W");
- __GetVDMPointer32W = (void far*)GetProcAddress(kern32,"GETVDMPOINTER32W");
- __CallProcEx32W = (void far*)GetProcAddress(kern32,"_CALLPROCEX32W"); /* <- Hey thanks Microsoft
- maybe if your docs mentioned
- the goddamn underscore I would
- have an easier time linking to it */
- __CallProc32W = (void far*)GetProcAddress(kern32,"CALLPROC32W");
-
- if (__LoadLibraryEx32W && __FreeLibrary32W && __GetProcAddress32W && __GetVDMPointer32W &&
- __CallProc32W && __CallProcEx32W) {
- __GenThunksExist = 1;
-
- genthunk32w_kernel32 = __LoadLibraryEx32W("KERNEL32.DLL",0,0);
- if (genthunk32w_kernel32 != 0) {
- genthunk32w_kernel32_GetVersion =
- __GetProcAddress32W(genthunk32w_kernel32,"GetVersion");
- genthunk32w_kernel32_GetVersionEx =
- __GetProcAddress32W(genthunk32w_kernel32,"GetVersionExA");
- genthunk32w_kernel32_GetLastError =
- __GetProcAddress32W(genthunk32w_kernel32,"GetLastError");
- }
-
- genthunk32w_ntdll = __LoadLibraryEx32W("NTDLL.DLL",0,0);
- }
- }
- }
-
- return __GenThunksExist;
-}
-
-void genthunk32_free() {
- genthunk32w_kernel32_GetVersion = 0;
- genthunk32w_kernel32_GetVersionEx = 0;
- genthunk32w_kernel32_GetLastError = 0;
- if (genthunk32w_kernel32) {
- __FreeLibrary32W(genthunk32w_kernel32);
- genthunk32w_kernel32 = 0;
- }
-}
-
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386)
-
-/* this library of code deals with the problem of getting ordinal-only exported functions out of KERNEL32.DLL in
- * Windows 9x/ME. GetProcAddress() won't do it for us, so instead, we forcibly read it out from memory ourself.
- * That's what you get for being a jack-ass about Win16 compatibility Microsoft */
-
-/* Note that this code would work under Windows 9x/ME and NT/2000/XP, but it is only needed for 9x/ME.
- * Windows XP SP2 and later change the handle slightly to try and confuse code like this (they take the HANDLE
- * value of the module and set the least significant bit), and I have reason to believe Microsoft will eventually
- * outright change the interface to make the handle an actual opaque handle someday (while of course making it
- * utterly impossible for programs like us to get to the API functions we need to do our fucking job). Because they're
- * Microsoft, and that's what they do with the Windows API. */
-
-/* How to use: Use the 32-bit GetModuleHandle() function to get the HMODULE value. In Windows so far, this HMODULE
- * value is literally the linear memory address where Windows loaded (or mapped) the base of the DLL image, complete
- * with MS-DOS header and PE image. This hack relies on that to then traverse the PE structure directly and forcibly
- * retrieve from the ordinal export table the function we desire. */
-
-/* returns: DWORD* pointer to PE image's export ordinal table, *entries is filled with the number of entries, *base
- * is filled with the ordinal number of the first entry. */
-
-static IMAGE_NT_HEADERS *Win32ValidateHModuleMSDOS_PE_Header(BYTE *p) {
- if (!memcmp(p,"MZ",2)) {
- /* then at offset 0x3C there should be the offset to the PE header */
- DWORD offset = *((DWORD*)(p+0x3C));
- if (offset < 0x40 || offset > 0x10000) return NULL;
- p += offset;
- if (IsBadReadPtr(p,4096)) return NULL;
- if (!memcmp(p,"PE\0\0",4)) {
- /* wait, before we celebrate, make sure it's sane! */
- IMAGE_NT_HEADERS *pp = (IMAGE_NT_HEADERS*)p;
-
- if (pp->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
- return NULL;
- if (pp->FileHeader.SizeOfOptionalHeader < 88) /* <- FIXME */
- return NULL;
- if (pp->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
- return NULL;
-
- return pp;
- }
- }
-
- return NULL;
-}
-
-static IMAGE_DATA_DIRECTORY *Win32GetDataDirectory(IMAGE_NT_HEADERS *p) {
- return p->OptionalHeader.DataDirectory;
-}
-
-DWORD *Win32GetExportOrdinalTable(HMODULE mod,DWORD *entries,DWORD *base,DWORD *base_addr) {
- IMAGE_EXPORT_DIRECTORY *exdir;
- IMAGE_DATA_DIRECTORY *dir;
- IMAGE_NT_HEADERS *ptr;
-
- /* Hack for Windows XP SP2: Clear the LSB, the OS sets it for some reason */
- mod = (HMODULE)((DWORD)mod & 0xFFFFF000UL);
- /* reset vars */
- *entries = *base = 0;
- if (mod == NULL) return NULL;
-
- /* the module pointer should point an image of the DLL in memory. Right at the pointer we should see
- * the letters "MZ" and the MS-DOS stub EXE header */
- ptr = Win32ValidateHModuleMSDOS_PE_Header((BYTE*)mod);
- if (ptr == NULL) return NULL;
-
- /* OK, now locate the Data Directory. The number of entries is in ptr->OptionalHeader.NumberOfRvaAndSizes */
- dir = Win32GetDataDirectory(ptr);
- if (ptr == NULL) return NULL;
-
- /* the first directory is the Export Address Table */
- exdir = (IMAGE_EXPORT_DIRECTORY*)((DWORD)mod + (DWORD)dir->VirtualAddress);
- if (IsBadReadPtr(exdir,2048)) return NULL;
-
- *base = exdir->Base;
- *entries = exdir->NumberOfFunctions;
- *base_addr = (DWORD)mod;
- return (DWORD*)((DWORD)mod + exdir->AddressOfFunctions);
-}
-
-int Win32GetOrdinalLookupInfo(HMODULE mod,Win32OrdinalLookupInfo *info) {
- DWORD *x = Win32GetExportOrdinalTable(mod,&info->entries,&info->base,&info->base_addr);
- if (x == NULL) return 0;
- info->table = x;
- return 1;
-}
-
-void *Win32GetOrdinalAddress(Win32OrdinalLookupInfo *nfo,unsigned int ord) {
- if (nfo == NULL || nfo->table == NULL) return NULL;
- if (ord < nfo->base) return NULL;
- if (ord >= (nfo->base+nfo->entries)) return NULL;
- return (void*)((char*)nfo->table[ord-nfo->base] + nfo->base_addr);
-}
-#endif
-
+++ /dev/null
-/* winfcon.c
- *
- * Fake console for Windows applications where a console is not available.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * This code allows the DOS/CPU test code to print to a console despite the
- * fact that Windows 3.0/3.1 and Win32s do not provide a console. For this
- * code to work, the program must include specific headers and #define a
- * macro. The header will then redefine various standard C functions to
- * redirect their use into this program. This code is not used for targets
- * that provide a console.
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-# include <windows/apihelp.h>
-#else
-# error what
-#endif
-
-#include <setjmp.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/winfcon.h>
-
-#ifdef WIN_STDOUT_CONSOLE
-
-/* _export is not valid for Win32. this silences a Watcom linker warning */
-#if TARGET_MSDOS == 32
-# define winproc_export
-#else
-# define winproc_export _export
-#endif
-
-#undef read
-#undef write
-#undef getch
-#undef isatty
-
-#define KBSIZE 256
-
-static char _win_WindowProcClass[128];
-
-/* If we stick all these variables in the data segment and reference
- * them directly, then we'll work from a single instance, but run into
- * problems with who's data segment to use once we run in multiple
- * instances. The problem, is that when an application creates a
- * window of our class, the Window Proc is not guaranteed to be called
- * with our DS segment/selector. In fact, it often seems to be the
- * data segment of the first instance by which the window class was
- * created. And under Windows 3.0, unless you used __loadds and
- * MakeProcInstance, the DS segment could be any random segment
- * that happened to be there when you were called.
- *
- * Our Window Proc below absolves itself of these problems by storing
- * the pointer to the context in the Window data associated with the
- * window (GetWindowLong/SetWindowLong), then using only that context
- * pointer for maintaining itself.
- *
- * This DS segment limitation only affects the Window procedure and
- * any functions called by the Window procedure. Other parts, like
- * WinMain, do not have to worry about whether DS is correct and the
- * data segment will always be the current instance running.
- *
- * Note that the above limitations are only an issue for the Win16
- * world. The Win32 world is free from this hell and so we only
- * have to maintain one context structure. */
-typedef struct _win_console_ctx {
- char console[80*25];
- char _win_kb[KBSIZE];
- int conHeight,conWidth;
- int _win_kb_i,_win_kb_o;
- int monoSpaceFontHeight;
-#if TARGET_MSDOS == 32 && defined(WIN386)
- short int monoSpaceFontWidth;
-#else
- int monoSpaceFontWidth;
-#endif
- HFONT monoSpaceFont;
- int pendingSigInt;
- int userReqClose;
- int allowClose;
- int conX,conY;
- jmp_buf exit_jmp;
- HWND hwndMain;
- int myCaret;
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
- WORD my_ds;
-#endif
-};
-
-HINSTANCE _win_hInstance;
-static struct _win_console_ctx _this_console;
-static char temprintf[1024];
-
-#if TARGET_MSDOS == 32 && defined(WIN386)
-# define USER_GWW_CTX 0
-# define USER_GWW_MAX 6
-#elif TARGET_MSDOS == 16
-# define USER_GWW_CTX 0
-# define USER_GWW_MAX 4
-#else
-# define USER_GWW_MAX 0
-#endif
-#define USER_GCW_MAX 0
-
-HWND _win_hwnd() {
- return _this_console.hwndMain;
-}
-
-int _win_kb_insert(struct _win_console_ctx FAR *ctx,char c) {
- if ((ctx->_win_kb_i+1)%KBSIZE == ctx->_win_kb_o) {
- MessageBeep(-1);
- return -1;
- }
-
- ctx->_win_kb[ctx->_win_kb_i] = c;
- if (++ctx->_win_kb_i >= KBSIZE) ctx->_win_kb_i = 0;
- return 0;
-}
-
-void _win_sigint() {
- void (*sig)(int x) = signal(SIGINT,SIG_DFL);
- if (sig != SIG_IGN && sig != SIG_DFL) sig(SIGINT);
- signal(SIGINT,sig);
- if (sig == SIG_DFL) longjmp(_this_console.exit_jmp,1);
-}
-
-void _win_sigint_post(struct _win_console_ctx FAR *ctx) {
- /* because doing a longjmp() out of a Window proc is very foolish */
- ctx->pendingSigInt = 1;
-}
-
-#if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
-FARPROC _win_WindowProc_MPI;
-#endif
-/* NTS: Win16 only: DS (data segment) is NOT necessarily the data segment of the instance
- * that spawned the window! Any attempt to access local variables will likely refer
- * to the copy in the first instance */
-/* NTS: All code in this routine deliberately does not refer to the local data segment, unless it
- * has to (which it does through the segment value in the context). This reduces problems with
- * the screwy callback design in Windows 3.0/3.1. */
-/* NTS: Do NOT use __loadds on this function prototype. It will seem to work, but because __loadds
- * reloads the (cached) instance data segment it will cause all instances to crash when you
- * spawn multiple instances and then close the first one you spawned. NOT using __loadds
- * removes that crash. */
-WindowProcType_NoLoadDS winproc_export _win_WindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam) {
-#if TARGET_MSDOS == 32 && defined(WIN386)
- struct _win_console_ctx FAR *_ctx_console;
- {
- unsigned short s = GetWindowWord(hwnd,USER_GWW_CTX);
- unsigned int o = GetWindowLong(hwnd,USER_GWW_CTX+2);
- _ctx_console = (void far *)MK_FP(s,o);
- }
- if (_ctx_console == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
-#elif TARGET_MSDOS == 16
- struct _win_console_ctx FAR *_ctx_console;
- _ctx_console = (void far *)GetWindowLong(hwnd,USER_GWW_CTX);
- if (_ctx_console == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
-#else
-# define _ctx_console (&_this_console)
-#endif
-
- if (message == WM_GETMINMAXINFO) {
-#if TARGET_MSDOS == 32 && defined(WIN386) /* Watcom Win386 does NOT translate LPARAM for us */
- MINMAXINFO FAR *mm = (MINMAXINFO FAR*)win386_help_MapAliasToFlat(lparam);
- if (mm == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
-#else
- MINMAXINFO FAR *mm = (MINMAXINFO FAR*)(lparam);
-#endif
- mm->ptMaxSize.x = (_ctx_console->monoSpaceFontWidth * _ctx_console->conWidth) +
- (2 * GetSystemMetrics(SM_CXFRAME));
- mm->ptMaxSize.y = (_ctx_console->monoSpaceFontHeight * _ctx_console->conHeight) +
- (2 * GetSystemMetrics(SM_CYFRAME)) + GetSystemMetrics(SM_CYCAPTION);
- mm->ptMinTrackSize.x = mm->ptMaxSize.x;
- mm->ptMinTrackSize.y = mm->ptMaxSize.y;
- mm->ptMaxTrackSize.x = mm->ptMaxSize.x;
- mm->ptMaxTrackSize.y = mm->ptMaxSize.y;
- return 0;
- }
- else if (message == WM_CLOSE) {
- if (_ctx_console->allowClose) DestroyWindow(hwnd);
- else _win_sigint_post(_ctx_console);
- _ctx_console->userReqClose = 1;
- }
- else if (message == WM_DESTROY) {
- _ctx_console->allowClose = 1;
- _ctx_console->userReqClose = 1;
- if (_ctx_console->myCaret) {
- HideCaret(hwnd);
- DestroyCaret();
- _ctx_console->myCaret = 0;
- }
-
- PostQuitMessage(0);
- _ctx_console->hwndMain = NULL;
- return 0; /* OK */
- }
- else if (message == WM_SETCURSOR) {
- if (LOWORD(lparam) == HTCLIENT) {
- SetCursor(LoadCursor(NULL,IDC_ARROW));
- return 1;
- }
- else {
- return DefWindowProc(hwnd,message,wparam,lparam);
- }
- }
- else if (message == WM_ACTIVATE) {
- if (wparam) {
- if (!_ctx_console->myCaret) {
- CreateCaret(hwnd,NULL,_ctx_console->monoSpaceFontWidth,_ctx_console->monoSpaceFontHeight);
- SetCaretPos(_ctx_console->conX * _ctx_console->monoSpaceFontWidth,
- _ctx_console->conY * _ctx_console->monoSpaceFontHeight);
- ShowCaret(hwnd);
- _ctx_console->myCaret = 1;
- }
- }
- else {
- if (_ctx_console->myCaret) {
- HideCaret(hwnd);
- DestroyCaret();
- _ctx_console->myCaret = 0;
- }
- }
-
- /* BUGFIX: Microsoft Windows 3.1 SDK says "return 0 if we processed the message".
- * Yet if we actually do, we get funny behavior. Like if I minimize another
- * application's window and then activate this app again, every keypress
- * causes Windows to send WM_SYSKEYDOWN/WM_SYSKEYUP. Somehow passing it
- * down to DefWindowProc() solves this. */
- return DefWindowProc(hwnd,message,wparam,lparam);
- }
- else if (message == WM_CHAR) {
- if (wparam > 0 && wparam <= 126) {
- if (wparam == 3) {
- /* CTRL+C */
- if (_ctx_console->allowClose) DestroyWindow(hwnd);
- else _win_sigint_post(_ctx_console);
- }
- else {
- _win_kb_insert(_ctx_console,(char)wparam);
- }
- }
- }
- else if (message == WM_ERASEBKGND) {
- RECT um;
-
- if (GetUpdateRect(hwnd,&um,FALSE)) {
- HBRUSH oldBrush,newBrush;
- HPEN oldPen,newPen;
-
- newPen = (HPEN)GetStockObject(NULL_PEN);
- newBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
-
- oldPen = SelectObject((HDC)wparam,newPen);
- oldBrush = SelectObject((HDC)wparam,newBrush);
-
- Rectangle((HDC)wparam,um.left,um.top,um.right+1,um.bottom+1);
-
- SelectObject((HDC)wparam,oldBrush);
- SelectObject((HDC)wparam,oldPen);
- }
-
- return 1; /* Important: Returning 1 signals to Windows that we processed the message. Windows 3.0 gets really screwed up if we don't! */
- }
- else if (message == WM_PAINT) {
- RECT um;
-
- if (GetUpdateRect(hwnd,&um,TRUE)) {
- PAINTSTRUCT ps;
- HFONT of;
- int y;
-
- BeginPaint(hwnd,&ps);
- SetBkMode(ps.hdc,OPAQUE);
- SetBkColor(ps.hdc,RGB(255,255,255));
- SetTextColor(ps.hdc,RGB(0,0,0));
- of = (HFONT)SelectObject(ps.hdc,_ctx_console->monoSpaceFont);
- for (y=0;y < _ctx_console->conHeight;y++) {
- TextOut(ps.hdc,0,y * _ctx_console->monoSpaceFontHeight,
- _ctx_console->console + (_ctx_console->conWidth * y),
- _ctx_console->conWidth);
- }
- SelectObject(ps.hdc,of);
- EndPaint(hwnd,&ps);
- }
-
- return 0; /* Return 0 to signal we processed the message */
- }
- else {
- return DefWindowProc(hwnd,message,wparam,lparam);
- }
-
- return 0;
-}
-
-int _win_kbhit() {
- _win_pump();
- return _this_console._win_kb_i != _this_console._win_kb_o;
-}
-
-int _win_getch() {
- do {
- if (_win_kbhit()) {
- int c = (int)((unsigned char)_this_console._win_kb[_this_console._win_kb_o]);
- if (++_this_console._win_kb_o >= KBSIZE) _this_console._win_kb_o = 0;
- return c;
- }
-
- _win_pump_wait();
- } while (1);
-
- return -1;
-}
-
-int _win_kb_read(char *p,int sz) {
- int cnt=0;
-
- while (sz-- > 0)
- *p++ = _win_getch();
-
- return cnt;
-}
-
-int _win_kb_write(const char *p,int sz) {
- int cnt=0;
-
- while (sz-- > 0)
- _win_putc(*p++);
-
- return cnt;
-}
-
-int _win_read(int fd,void *buf,int sz) {
- if (fd == 0) return _win_kb_read((char*)buf,sz);
- else if (fd == 1 || fd == 2) return -1;
- else return read(fd,buf,sz);
-}
-
-int _win_write(int fd,const void *buf,int sz) {
- if (fd == 0) return -1;
- else if (fd == 1 || fd == 2) return _win_kb_write(buf,sz);
- else return write(fd,buf,sz);
-}
-
-int _win_isatty(int fd) {
- if (fd == 0 || fd == 1 || fd == 2) return 1; /* we're emulating one, so, yeah */
- return isatty(fd);
-}
-
-void _win_pump_wait() {
- MSG msg;
-
- if (GetMessage(&msg,NULL,0,0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
-
- if (_this_console.pendingSigInt) {
- _this_console.pendingSigInt = 0;
- _win_sigint();
- }
-}
-
-void _win_pump() {
- MSG msg;
-
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
- /* Hack: Windows has this nice "GetTickCount()" function that has serious problems
- * maintaining a count if we don't process the message pump! Doing this
- * prevents portions of this code from getting stuck in infinite loops
- * waiting for the damn timer to advance. Note that this is a serious
- * problem that only plagues Windows 3.1 and earlier. Windows 95 doesn't
- * have this problem. */
- PostMessage(_this_console.hwndMain,WM_USER,0,0);
-#endif
- if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
- do {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- } while (PeekMessage(&msg,NULL,0,0,PM_REMOVE));
- }
-
- if (_this_console.pendingSigInt) {
- _this_console.pendingSigInt = 0;
- _win_sigint();
- }
-}
-
-void _win_update_cursor() {
- if (_this_console.myCaret)
- SetCaretPos(_this_console.conX * _this_console.monoSpaceFontWidth,
- _this_console.conY * _this_console.monoSpaceFontHeight);
-}
-
-void _win_redraw_line_row() {
- if (_this_console.conY >= 0 && _this_console.conY < _this_console.conHeight) {
- HDC hdc = GetDC(_this_console.hwndMain);
- HFONT of;
-
- SetBkMode(hdc,OPAQUE);
- SetBkColor(hdc,RGB(255,255,255));
- SetTextColor(hdc,RGB(0,0,0));
- of = (HFONT)SelectObject(hdc,_this_console.monoSpaceFont);
- if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
- TextOut(hdc,0,_this_console.conY * _this_console.monoSpaceFontHeight,
- _this_console.console + (_this_console.conWidth * _this_console.conY),_this_console.conWidth);
- if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
- SelectObject(hdc,of);
- ReleaseDC(_this_console.hwndMain,hdc);
- }
-}
-
-void _win_redraw_line_row_partial(int x1,int x2) {
- if (x1 >= x2) return;
-
- if (_this_console.conY >= 0 && _this_console.conY < _this_console.conHeight) {
- HDC hdc = GetDC(_this_console.hwndMain);
- HFONT of;
-
- SetBkMode(hdc,OPAQUE);
- SetBkColor(hdc,RGB(255,255,255));
- SetTextColor(hdc,RGB(0,0,0));
- of = (HFONT)SelectObject(hdc,_this_console.monoSpaceFont);
- if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
- TextOut(hdc,x1 * _this_console.monoSpaceFontWidth,_this_console.conY * _this_console.monoSpaceFontHeight,
- _this_console.console + (_this_console.conWidth * _this_console.conY) + x1,x2 - x1);
- if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
- SelectObject(hdc,of);
- ReleaseDC(_this_console.hwndMain,hdc);
- }
-}
-
-void _win_scrollup() {
- HDC hdc = GetDC(_this_console.hwndMain);
- if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
- BitBlt(hdc,0,0,_this_console.conWidth * _this_console.monoSpaceFontWidth,
- _this_console.conHeight * _this_console.monoSpaceFontHeight,hdc,
- 0,_this_console.monoSpaceFontHeight,SRCCOPY);
- if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
- ReleaseDC(_this_console.hwndMain,hdc);
-
- memmove(_this_console.console,_this_console.console+_this_console.conWidth,
- (_this_console.conHeight-1)*_this_console.conWidth);
- memset(_this_console.console+((_this_console.conHeight-1)*_this_console.conWidth),
- ' ',_this_console.conWidth);
-}
-
-void _win_newline() {
- _this_console.conX = 0;
- if ((_this_console.conY+1) == _this_console.conHeight) {
- _win_redraw_line_row();
- _win_scrollup();
- _win_redraw_line_row();
- _win_update_cursor();
- _gdi_pause();
- }
- else {
- _win_redraw_line_row();
- _this_console.conY++;
- }
-}
-
-/* write to the console. does NOT redraw the screen unless we get a newline or we need to scroll up */
-void _win_putc(char c) {
- if (c == 10) {
- _win_newline();
- }
- else if (c == 13) {
- _this_console.conX = 0;
- _win_redraw_line_row();
- _win_update_cursor();
- _gdi_pause();
- }
- else {
- if (_this_console.conX < _this_console.conWidth)
- _this_console.console[(_this_console.conY*_this_console.conWidth)+_this_console.conX] = c;
- if (++_this_console.conX == _this_console.conWidth)
- _win_newline();
- }
-}
-
-size_t _win_printf(const char *fmt,...) {
- int fX = _this_console.conX;
- va_list va;
- char *t;
-
- va_start(va,fmt);
- vsnprintf(temprintf,sizeof(temprintf)-1,fmt,va);
- va_end(va);
-
- t = temprintf;
- if (*t != 0) {
- while (*t != 0) {
- if (*t == 13 || *t == 10) fX = 0;
- _win_putc(*t++);
- }
- if (fX <= _this_console.conX) _win_redraw_line_row_partial(fX,_this_console.conX);
- _win_update_cursor();
- }
-
- _win_pump();
- return 0;
-}
-
-/* HACK: I don't know if real systems do this or QEMU is doing something wrong, but apparently if a program
- * rapidly prints a lot of text under Windows 3.1 (like the RDTSC test program) it can cause the GDI
- * to become 100% focused on TextOut() to the point not even the cursor updates when you move it, and
- * keyboard events to become severely stalled. Our solution to this problem is to see if we're running
- * under Windows 3.1 or earlier, and if so, purposely slow down our output with a software delay */
-void _gdi_pause() {
-#if defined(TARGET_WINDOWS)
-# if TARGET_MSDOS == 32 && defined(WIN386)
-# else
- const DWORD ConDelay = 16UL; /* 16ms */
-# endif
-#endif
-
-#if defined(TARGET_WINDOWS)
- if (windows_mode != WINDOWS_NT) {
-# if TARGET_MSDOS == 32 && defined(WIN386)
- /* nothing */
-# else
-# if TARGET_MSDOS == 16
- if (ToolHelpInit()) {
- DWORD base,m;
- TIMERINFO ti;
- ti.dwSize = sizeof(ti);
- if (__TimerCount(&ti)) {
- base = ti.dwmsSinceStart;
-
- do {
- Yield();
- _win_pump();
- if (!__TimerCount(&ti)) break;
- m = ti.dwmsSinceStart;
- } while ((m - base) < ConDelay);
- }
- }
- else {
-# else
- {
-# endif
- DWORD base,m;
-
- base = GetTickCount();
- do {
- Yield();
- _win_pump();
- m = GetTickCount();
- } while ((m - base) < ConDelay);
- }
-# endif
- }
-#endif
-}
-
-/* NOTES:
- * For Win16, programmers generally use WINAPI WinMain(...) but WINAPI is defined in such a way
- * that it always makes the function prolog return FAR. Unfortunately, when Watcom C's runtime
- * calls this function in a memory model that's compact or small, the call is made as if NEAR,
- * not FAR. To avoid a GPF or crash on return, we must simply declare it PASCAL instead. */
-int PASCAL _win_main_con_entry(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow,int (_cdecl *_main_f)(int argc,char**,char**)) {
- WNDCLASS wnd;
- MSG msg;
-
- _win_hInstance = hInstance;
- snprintf(_win_WindowProcClass,sizeof(_win_WindowProcClass),"_HW_DOS_WINFCON_%lX",(DWORD)hInstance);
-#if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
- _win_WindowProc_MPI = MakeProcInstance((FARPROC)_win_WindowProc,hInstance);
-#endif
-
- /* clear the console */
- memset(&_this_console,0,sizeof(_this_console));
- memset(_this_console.console,' ',sizeof(_this_console.console));
- _this_console._win_kb_i = _this_console._win_kb_o = 0;
- _this_console.conHeight = 25;
- _this_console.conWidth = 80;
- _this_console.conX = 0;
- _this_console.conY = 0;
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
- {
- WORD s=0;
-
- __asm {
- mov ax,ds
- mov s,ax
- }
- _this_console.my_ds = s;
- }
-#endif
-
- /* we need to know at this point what DOS/Windows combination we're running under */
- probe_dos();
- detect_windows();
-
- /* we want each instance to have it's own WNDCLASS, even though Windows (Win16) considers them all instances
- * coming from the same HMODULE. In Win32, there is no such thing as a "previous instance" anyway */
- wnd.style = CS_HREDRAW|CS_VREDRAW;
-#if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
- wnd.lpfnWndProc = (WNDPROC)_win_WindowProc_MPI;
-#else
- wnd.lpfnWndProc = _win_WindowProc;
-#endif
- wnd.cbClsExtra = USER_GCW_MAX;
- wnd.cbWndExtra = USER_GWW_MAX;
- wnd.hInstance = hInstance;
- wnd.hIcon = NULL;
- wnd.hCursor = NULL;
- wnd.hbrBackground = NULL;
- wnd.lpszMenuName = NULL;
- wnd.lpszClassName = _win_WindowProcClass;
-
- if (!RegisterClass(&wnd)) {
- MessageBox(NULL,"Unable to register Window class","Oops!",MB_OK);
- return 1;
- }
-
-/* Use the full path of our EXE image by default */
- {
- char title[256];
-
- if (!GetModuleFileName(hInstance,title,sizeof(title)-1))
- strcpy(title,"<unknown>");
-
- _this_console.hwndMain = CreateWindow(_win_WindowProcClass,title,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,CW_USEDEFAULT,
- 100,40,
- NULL,NULL,
- hInstance,NULL);
- }
-
- if (!_this_console.hwndMain) {
- MessageBox(NULL,"Unable to create window","Oops!",MB_OK);
- return 1;
- }
-
-#if TARGET_MSDOS == 32 && defined(WIN386)
- /* our Win386 hack needs the address of our console context */
- SetWindowWord(_this_console.hwndMain,USER_GWW_CTX,(WORD)FP_SEG(&_this_console));
- SetWindowLong(_this_console.hwndMain,USER_GWW_CTX+2,(DWORD)FP_OFF(&_this_console));
-#elif TARGET_MSDOS == 16
- /* our Win16 hack needs the address of our console context */
- SetWindowLong(_this_console.hwndMain,USER_GWW_CTX,(DWORD)(&_this_console));
-#endif
-
- /* Create the monospace font we use for terminal display */
- {
- _this_console.monoSpaceFont = CreateFont(-12,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH | FF_DONTCARE,"Terminal");
- if (!_this_console.monoSpaceFont) {
- MessageBox(NULL,"Unable to create Font","Oops!",MB_OK);
- return 1;
- }
-
- {
- HWND hwnd = GetDesktopWindow();
- HDC hdc = GetDC(hwnd);
- _this_console.monoSpaceFontHeight = 12;
- if (!GetCharWidth(hdc,'A','A',&_this_console.monoSpaceFontWidth)) _this_console.monoSpaceFontWidth = 9;
- ReleaseDC(hwnd,hdc);
- }
- }
-
- ShowWindow(_this_console.hwndMain,nCmdShow);
- UpdateWindow(_this_console.hwndMain);
- SetWindowPos(_this_console.hwndMain,HWND_TOP,0,0,
- (_this_console.monoSpaceFontWidth * _this_console.conWidth) +
- (2 * GetSystemMetrics(SM_CXFRAME)),
- (_this_console.monoSpaceFontHeight * _this_console.conHeight) +
- (2 * GetSystemMetrics(SM_CYFRAME)) + GetSystemMetrics(SM_CYCAPTION),
- SWP_NOMOVE);
-
- if (setjmp(_this_console.exit_jmp) == 0)
- _main_f(0,NULL,NULL); /* <- FIXME: We need to take the command line and generate argv[]. Also generate envp[] */
-
- if (!_this_console.userReqClose) {
- _win_printf("\n<program terminated>");
- _this_console.allowClose = 1;
- while (GetMessage(&msg,NULL,0,0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- else {
- if (IsWindow(_this_console.hwndMain)) {
- DestroyWindow(_this_console.hwndMain);
- while (GetMessage(&msg,NULL,0,0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- }
-
- DeleteObject(_this_console.monoSpaceFont);
- _this_console.monoSpaceFont = NULL;
- return 0;
-}
-#endif
-
+++ /dev/null
-/* winfcon.h
- *
- * Fake console for Windows applications where a console is not available.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-/* Windows 3.1 and earlier, even for Win32s: there is no system given console.
- * We either have to draw and maintain our own window, or find some other way to printf() and display it. */
-#if defined(TARGET_WINDOWS) && (TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && TARGET_WINDOWS == 31) || (defined(WIN386) && TARGET_MSDOS == 32))
-# define WIN_STDOUT_CONSOLE
-# define getch _win_getch
-# define kbhit _win_kbhit
-# define fprintf __XXX_TODO_fprintf
-# define printf _win_printf
-# define isatty _win_isatty
-# define write _win_write
-# define read _win_read
-
-void _win_pump();
-int _win_kbhit();
-int _win_getch();
-HWND _win_hwnd();
-void _gdi_pause();
-void _win_pump_wait();
-void _win_putc(char c);
-int _win_isatty(int fd);
-int _win_read(int fd,void *buf,int sz);
-size_t _win_printf(const char *fmt,...);
-int _win_write(int fd,const void *buf,int sz);
-int _cdecl main(int argc,char **argv,char **envp);
-int PASCAL _win_main_con_entry(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow,int (_cdecl *_main_f)(int argc,char**,char**));
-
-extern HINSTANCE _win_hInstance;
-
-# ifdef WINFCON_STOCK_WIN_MAIN
-int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) {
- return _win_main_con_entry(hInstance,hPrevInstance,lpCmdLine,nCmdShow,main);
-}
-# endif
-
-#endif
-
+++ /dev/null
-@echo off\r
-\r
-set WHAT=make\r
-if "%1" == "clean" set WHAT=clean\r
-\r
-echo Building: hello\r
-cd hello\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo All done\r
+++ /dev/null
-@echo off\r
-if exist *.map del *.map\r
-if exist *.obj del *.obj\r
-if exist *.sym del *.sym\r
-if exist *.exe del *.exe\r
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-
-# The build system we have has no effect on NASM (at the moment) and
-# all memory models+CPU modes build the same binary. So why build them
-# again and again? Build them only in dos86s mode.
-!ifndef TARGET_WINDOWS
-! ifndef TARGET_OS2
-! ifeq TARGET_MSDOS 16
-! ifeq TARGET86 86
-! ifeq MMODE s
-BUILD_NASM_COM = 1
-! endif
-! endif
-! endif
-! endif
-!endif
-
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-AFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NASMFLAGS_THIS =
-NOW_BUILDING = DOSDRV_HELLO
-
-!ifdef BUILD_NASM_COM
-# MS-DOS COM output
-HELLO_SYS = $(SUBDIR)$(HPS)hello.sys
-!endif
-
-all: exe .symbolic
-
-exe: $(HELLO_SYS) .symbolic
-
-!ifdef BUILD_NASM_COM
-$(HELLO_SYS): hello.asm
- nasm -o $@ -f bin $(NASMFLAGS) $[@
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_CPU_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-DEVICE=HELLO.SYS\r
-\r
+++ /dev/null
-; MS-DOS device driver "hello"
-; .COM type
-bits 16 ; 16-bit real mode
-org 0 ; MS-DOS .SYS style
-
-; =================== HEADER ====================
-dw 0xFFFF,0xFFFF ; next device ptr
-dw 0xA800 ; bit 15: 1=character device
- ; bit 14: 0=does not support IOCTL control strings
- ; bit 13: 0=does not support output until busy
- ; bit 11: 1=understands open/close
- ; bit 6: 0=does not understand 3.2 functions
- ; bit 3:0: 0=not NUL, STDIN, STDOUT, CLOCK, etc.
-dw drv_strategy ; offset of strategy routine
-dw drv_interrupt ; offset of interrupt routine
-db 'HELLO ' ; device name
-db 0
-
-; var storage
-req_pkt:dd 0
-
-; =================== Strategy routine ==========
-drv_strategy:
- mov [cs:req_pkt+0],bx ; BYTE ES:BX+0x00 = length of request header
- mov [cs:req_pkt+2],es ; BYTE ES:BX+0x01 = unit number
- retf ; BYTE ES:BX+0x02 = command code
- ; WORD ES:BX+0x03 = driver return status word
- ; ES:BX+0x05 = reserved??
-
-; =================== Interrupt routine =========
-drv_interrupt:
- push ax
- push bx
- push si
- push ds
- push es
- les bx,[cs:req_pkt] ; ES:BX MS-DOS request
- mov al,[es:bx+2] ; so, what request?
-
- cmp al,17 ; request #16 or less
- jae .out_of_range
-
- xor ah,ah
- shl ax,1
- mov si,ax ; SI = AL * 2
- call word [cs:func_table+si]
-.return:
- pop es
- pop ds
- pop si
- pop bx
- pop ax
- retf
-
-.out_of_range:
- mov word [es:bx+3],0x810C ; general error/done
- jmp short .return
-
-; ===================== func table ================
-func_table: dw func_init ; 0x00 INIT
- dw ignore ; 0x01 MEDIA CHECK
- dw bad_request ; 0x02 BUILD BIOS BPB
- dw bad_request ; 0x03 I/O read
- dw read ; 0x04 READ
- dw nd_read ; 0x05 NON-DESTRUCTIVE READ
- dw input_status ; 0x06 INPUT STATUS
- dw ignore ; 0x07 FLUSH INPUT BUFFERS
- dw write ; 0x08 WRITE
- dw write ; 0x09 WRITE WITH VERIFY
- dw output_status ; 0x0A OUTPUT STATUS
- dw ignore ; 0x0B FLUSH OUTPUT BUFFERS
- dw bad_request ; 0x0C I/O write
- dw open ; 0x0D open
- dw close ; 0x0E close
- dw bad_request ; 0x0F REMOVABLE MEDIA CALL
- dw bad_request ; 0x10 OUTPUT UNTIL BUSY
-
-func_init: ; 0x00 INIT
- ; BYTE ES:BX+0x0D = number of units initialized
- ; DWORD ES:BX+0x0E = return break address (last address of driver)
- ; DWORD ES:BX+0x12 = pointer to the character on the CONFIG.SYS line following DEVICE=
- ; block devices return FAR pointer to BIOS param block here
- ; BYTE ES:BX+0x16 = drive number (A=0, B=1) for first unit of block driver (MS-DOS 3+)
- mov word [es:bx+3],0x0100 ; status: no error, done
- mov word [es:bx+14],end_resident ; change "last address in driver"
- mov word [es:bx+16],cs ; NTS: we MUST change this, else Windows 95 chokes
- ret
-
-ignore: ; 0x01 MEDIA CHECK
- ; 0x07 FLUSH INPUT BUFFERS
- ; 0x0B FLUSH OUTPUT BUFFERS
- mov word [es:bx+3],0x0100
- ret
-
-open:
-close:
- mov word [cs:data_fp],data
- ; 0x0D open
- ; 0x0E close
- mov word [es:bx+3],0x0100
- ret
-
-bad_request: ; 0x02 BUILD BIOS BPB
- ; 0x03 I/O read
- ; 0x0C I/O write
- ; 0x0F REMOVABLE MEDIA CALL
- ; 0x10 OUTPUT UNTIL BUSY
- mov word [es:bx+3],0x8103
- ret
-
-read: ; 0x04 READ
- ; BYTE ES:BX+0x0D = media descriptor byte
- ; DWORD ES:BX+0x0E = far pointer to buffer to read to
- ; WORD ES:BX+0x12 = count of bytes to read, on return, count of bytes read
- ; WORD ES:BX+0x14 = starting block number (block devices)
- ; DWORD ES:BX+0x16 = far pointer to volume label if error 15 reported
- mov word [es:bx+3],0x0100
- push cx
- push di
- push bp
- xor bp,bp ; BP = return byte counter
- lds di,[es:bx+0x0E] ; DS:DI = caller's buffer
- mov cx,[es:bx+0x12] ; CX = count of bytes to read
-.rloop: jcxz .end
- mov si,word [cs:data_fp]
- mov al,[cs:si]
- mov byte [di],al
- inc di ; DS:DI++
- dec cx ; count--
- inc bp ; BP++
- inc word [cs:data_fp]
- cmp word [cs:data_fp],data_eof
- jnz .rloop
- mov word [cs:data_fp],data
- jmp .rloop
-.end: mov [es:bx+0x12],bp
- pop bp
- pop di
- pop cx
- ret
-
-nd_read: ; 0x05 NON-DESTRUCTIVE READ
- ; BYTE ES:BX+0x0D = return char
- mov si,word [cs:data_fp]
- mov al,[cs:si]
- mov byte [es:bx+0x0D],al
- mov word [es:bx+3],0x0100
- ret
-
-write: ; 0x08 WRITE
- ; 0x09 WRITE WITH VERIFY
- mov word [es:bx+3],0x8105
- ret
-
-input_status: ; 0x06 INPUT STATUS
- mov word [es:bx+3],0x8105
- ret
-
-output_status: ; 0x0A OUTPUT STATUS
- mov word [es:bx+3],0x8105
- ret
-
-data_fp: dw data
-data: db "Hello world! First MS-DOS device driver!",13,10
-data_eof: equ $-$$
-
-end_resident: equ $-$$
-
*/
#if !defined(TARGET_OS2) && !defined(TARGET_WINDOWS)
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/emm.h>
-
-unsigned char emm_status = 0xFF; /* initialize to 0xFF as a way of indicating that nobody checked yet */
-unsigned char emm_present = 0;
-unsigned char emm_version = 0;
-unsigned char emm_phys_pages = 0;
-unsigned short emm_total_pages = 0;
+#include "src/lib/doslib/emm.h"
+
+byte emm_status = 0xFF; /* initialize to 0xFF as a way of indicating that nobody checked yet */
+byte emm_present = 0;
+byte emm_version = 0;
+byte emm_phys_pages = 0;
+word emm_total_pages = 0;
unsigned int emm_page_frame_segment = 0;
-unsigned short emm_unallocated_pages = 0;
+word emm_unallocated_pages = 0;
struct emm_phys_page_map *emm_phys_map = NULL; /* maps physical page number -> segment address */
static const char *devname = "EMMXXXX0";
static const char *devname2 = "EMMQXXX0"; /* Microsoft publishes EMM standard then breaks it subtly in non-backwards compatible way... news at 11 */
}
}
-int probe_emm() {
+int probe_emm0() {
void far *emmptr;
emm_present = 0;
}
/* given physical page number, return real-mode segment value */
-unsigned short emm_last_phys_page_segment(unsigned int phys_page) {
+word emm_last_phys_page_segment(unsigned int phys_page) {
unsigned int i;
if (phys_page >= (unsigned int)emm_phys_pages)
}
}
-int probe_emm() {/*32-bit*/
+/*int probe_emm() {//32-bit
unsigned int emm_seg;
sanity();
emm_present = 0;
- /* Tricky. The DOS extender would likely translate the vector, when what we
- really want is the segment value of int 67h */
+ // Tricky. The DOS extender would likely translate the vector, when what we
+ really want is the segment value of int 67h
emm_seg = *((uint16_t*)((0x67 << 2) + 2));
sanity();
- /* apparently 10 bytes into the segment there is the magic string */
+ // apparently 10 bytes into the segment there is the magic string
if ( memcmp((void*)(((unsigned long)emm_seg << 4UL) + 0x000A),devname,8) != 0 &&
memcmp((void*)(((unsigned long)emm_seg << 4UL) + 0x000A),devname2,8) != 0)
return 0;
}
if (emm_phys_map == NULL) {
- /* see if the EMM provides a mapping table describing the real-mode segments
- * corresponding to each physical page. if not, then assume only one page
- * available. the table could be up to 256 entries. the API really doesn't
- * have a way to tell us ahead of time, so assume the worst. */
+ // see if the EMM provides a mapping table describing the real-mode segments
+ // * corresponding to each physical page. if not, then assume only one page
+ // * available. the table could be up to 256 entries. the API really doesn't
+ // * have a way to tell us ahead of time, so assume the worst.
assert(sizeof(struct emm_phys_page_map) == (size_t)4);
emm_phys_map = dpmi_alloc_dos(sizeof(struct emm_phys_page_map) * 256,&emm_phys_map_sel);
if (emm_phys_map != NULL) {
else {
emm_phys_pages = c;
- /* WARNING: we are assuming several things about the table.
- * - That the table is sorted by real-mode segment (as described in the standard)
- * - There are no duplicate page numbers
- * - The table has as many entries as physical pages */
+ // * WARNING: we are assuming several things about the table.
+ // * - That the table is sorted by real-mode segment (as described in the standard)
+ // * - There are no duplicate page numbers
+ // * - The table has as many entries as physical pages
- /* do ourself a favor and sort by page number the table */
+ // do ourself a favor and sort by page number the table
emm_phys_pages_sort();
}
}
}
return 1;
-}
+}*/
int emm_alloc_pages(unsigned int pages) {
int handle = -1;
if (emm_present) {
__asm {
mov ah,0x43
- mov ebx,pages
+ mov bx,pages
push es
int 0x67
pop es
or ah,ah
jnz fail
- and edx,0xFFFF
- mov handle,edx
+ and dx,0xFFFF
+ mov handle,dx
fail:
}
}
if (emm_present) {
__asm {
mov ah,0x45
- mov edx,handle
+ mov dx,handle
push es
int 0x67
pop es
__asm {
mov ah,0x44
mov al,byte ptr phys_page
- mov ebx,log_page
- mov edx,handle
+ mov bx,log_page
+ mov dx,handle
push es
int 0x67
pop es
return retv;
}
-unsigned short emm_last_phys_page_segment(unsigned int phys_page) {
+word emm_last_phys_page_segment(unsigned int phys_page) {
unsigned int i;
if (phys_page >= (unsigned int)emm_phys_pages)
#include <stdio.h>
#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdio.h>
+#include <conio.h>
+#include <dos.h>
+
+//#include "src/lib/doslib/cpu.h"
+#include "src/lib/doslib/dos.h"
+
+extern byte emm_status;
+extern byte emm_present;
+extern byte emm_version;
+extern byte emm_phys_pages;
+extern word emm_total_pages;
+extern unsigned int emm_page_frame_segment;
+extern word emm_unallocated_pages;
+extern struct emm_phys_page_map *emm_phys_map;
+
/* FIXME: 32-bit protected mode: Who the fuck keeps changing the
value of ES?!? Watcom and our code rely on ES == DS! */
#if TARGET_MSDOS == 32
};
#pragma pack(pop)
-extern unsigned char emm_status;
-extern unsigned char emm_present;
-extern unsigned char emm_version;
-extern unsigned char emm_phys_pages;
-extern unsigned short emm_total_pages;
-extern unsigned int emm_page_frame_segment;
-extern unsigned short emm_unallocated_pages;
-extern struct emm_phys_page_map *emm_phys_map;
-
-int probe_emm();
+int probe_emm0();
void emm_phys_pages_sort();
void emm_update_page_count();
int emm_alloc_pages(unsigned int pages);
int emm_free_pages(unsigned int handle);
-unsigned short emm_last_phys_page_segment(unsigned int phys_page);
+word emm_last_phys_page_segment(unsigned int phys_page);
int emm_map_page(unsigned int handle,unsigned int phys_page,unsigned int log_page);
#define emm_was_probed() (emm_status != 0xFF)
* Normal mode YES NO Same problems as Windows 2000
*/
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/himemsys.h>
+#include "src/lib/doslib/himemsys.h"
#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
/*===================================== MS-DOS only ===================================*/
for: just allocate a block that is 64MB in size (DX == 0 but EDX == 0x00010000) and if the allocation
succeeds, use the Get Block Info command to verify that it is in fact 64MB in size. The broken implementation
will create a zero-length block (which is legal in the HIMEM.SYS standard) and will say so when we ask.
-
+
Known HIMEM.SYS broken emulation:
DOSBox 0.74:
- Responds to extended commands as if newer HIMEM.SYS but ignores upper 16 bits. You might as well
* <insert LGPL legal text here>
*/
+#ifndef __HW_DOS_XMM_H
+#define __HW_DOS_XMM_H
+
#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <stdio.h>
+#include <conio.h>
+#include <dos.h>
+
+//#include "src/lib/doslib/cpu.h"
+#include "src/lib/doslib/dos.h"
+
/* HMA memory is present */
#define HIMEM_F_HMA (1 << 0)
/* HIMEM.SYS supports extended functions to address up to 4GB of RAM (surpassing the older API's 64MB limit) */
#endif /* !defined(TARGET_WINDOWS) && !defined(TARGET_OS2) */
+#endif /* __HW_DOS_EMM_H */
+++ /dev/null
-/* 8042.c
- *
- * Intel 8042 keyboard controller library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * On "IBM compatible" hardware the keyboard controller is responsible for
- * receiving scan codes from the keyboard. On newer (post 1990) systems,
- * the controller also handles PS/2 mouse input and communication (AUX).
- *
- * Note that on recent hardware (1999 or later) it's entirely possible the
- * BIOS is using System Management Mode and/or a USB mouse & keyboard to
- * fake 8042 I/O ports and communications for backwards compatibility. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/8042/8042.h>
-
-unsigned char k8042_flags = 0;
-unsigned char k8042_last_status = 0;
-
-/* drain the 8042 buffer entirely */
-void k8042_drain_buffer() {
- unsigned char c;
-
- do {
- inp(K8042_DATA);
- c = inp(K8042_STATUS);
- } while (c&3);
- k8042_last_status = c;
-}
-
-/* probe for the existence of the 8042 controller I/O ports.
- * obviously as a DOS program the ports are there. but someday...
- * it's possible the newer BIOSes will stop emulating it sooner or later. */
-int k8042_probe() {
- if (inp(K8042_STATUS) == 0xFF)
- return 0;
-
- return 1;
-}
-
+++ /dev/null
-/* 8042.h
- *
- * Intel 8042 keyboard controller library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#ifndef __HW_8042_8042_H
-#define __HW_8042_8042_H
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#define K8042_STATUS 0x64 /* (R) */
-#define K8042_COMMAND 0x64 /* (W) */
-#define K8042_DATA 0x60 /* (R/W) */
-
-/* status bits */
-#define K8042_STATUS_OUTPUT_FULL 0x01
-#define K8042_STATUS_INPUT_FULL 0x02
-#define K8042_STATUS_SYSTEM 0x04
-#define K8042_STATUS_DATA_WRITE 0x08 /* 1=next write to 0x64 0=next write to 0x60 */
-#define K8042_STATUS_INHIBIT 0x10
-#define K8042_STATUS_XMIT_TIMEOUT 0x20
-#define K8042_STATUS_MOUSE_OUTPUT_FULL 0x20
-#define K8042_STATUS_RECV_TIMEOUT 0x40
-#define K8042_STATUS_PARITY_ERR 0x80
-
-#define K8042_IRQ 1
-#define K8042_MOUSE_IRQ 12
-
-int k8042_probe();
-int k8042_probe_aux();
-void k8042_drain_buffer();
-int k8042_write_aux_synaptics_E8(unsigned char c);
-int k8042_write_aux_synaptics_mode(unsigned char c);
-
-extern unsigned char k8042_flags;
-extern unsigned char k8042_last_status;
-
-#define K8042_F_AUX 0x01
-
-/* NTS: Do not confuse our input with the controller's input. This reflects the controller's input
- * meaning: Can we, the host, OUTPUT DATA to the CONTROLLER'S INPUT? */
-static inline unsigned char k8042_wait_for_input_buffer() {
- unsigned int patience = 0xFFFFU;
- unsigned char c;
-
- do { c = inp(K8042_STATUS);
- } while ((c&2) && --patience != 0U);
- k8042_last_status = c;
- return (c & 2) == 0;
-}
-
-/* NTS: Do not confue our output with the controller's output. This reflects the controller's output
- * meaning: Can we, the host, INPUT DATA from the CONTROLLER'S OUTPUT? */
-static inline unsigned char k8042_wait_for_output() {
- unsigned int patience = 0xFFFFU;
- unsigned char c;
-
- do { c = inp(K8042_STATUS);
- } while ((c&1) == 0 && --patience != 0U);
- k8042_last_status = c;
- return (c & 1);
-}
-
-static inline unsigned char k8042_is_output_ready() {
- return ((k8042_last_status = inp(K8042_STATUS)) & K8042_STATUS_OUTPUT_FULL);
-}
-
-static inline unsigned char k8042_is_mouse_output_ready() {
- return ((k8042_last_status = inp(K8042_STATUS)) & (K8042_STATUS_OUTPUT_FULL|K8042_STATUS_MOUSE_OUTPUT_FULL)) ==
- (K8042_STATUS_OUTPUT_FULL|K8042_STATUS_MOUSE_OUTPUT_FULL);
-}
-
-static inline unsigned char k8042_output_was_aux() {
- return (k8042_flags & K8042_F_AUX) != 0 && (k8042_last_status & K8042_STATUS_MOUSE_OUTPUT_FULL) != 0;
-}
-
-/* WARNING: caller is expected to use k8042_wait_for_output() prior to calling this */
-static inline unsigned char k8042_read_output() {
- return inp(K8042_DATA);
-}
-
-static inline int k8042_read_output_wait() {
- if (k8042_wait_for_output() || k8042_wait_for_output() || k8042_wait_for_output())
- return k8042_read_output();
- else
- return -1;
-}
-
-static inline unsigned char k8042_write_command(unsigned char c) {
- unsigned char r = k8042_wait_for_input_buffer();
- if (r) outp(K8042_COMMAND,c);
- return r;
-}
-
-static inline unsigned char k8042_write_data(unsigned char c) {
- unsigned char r = k8042_wait_for_input_buffer();
- if (r) outp(K8042_DATA,c);
- return r;
-}
-
-static inline int k8042_read_command_byte() {
- if (k8042_write_command(0x20))
- return k8042_read_output_wait();
- return -1;
-}
-
-static inline unsigned char k8042_write_command_byte(unsigned char c) {
- if (k8042_write_command(0x60) && k8042_write_data(c))
- return 1;
-
- return 0;
-}
-
-static inline void k8042_disable_keyboard() {
- k8042_write_command(0xAD); /* disable keyboard */
-}
-
-static inline void k8042_enable_keyboard() {
- k8042_write_command(0xAE); /* enable keyboard */
-}
-
-static inline void k8042_disable_aux() {
- k8042_write_command(0xA7); /* disable aux */
-}
-
-static inline void k8042_enable_aux() {
- k8042_write_command(0xA8); /* enable aux */
-}
-
-static inline unsigned char k8042_write_aux(unsigned char c) {
- return (k8042_write_command(0xD4) && k8042_write_data(c));
-}
-
-#endif /* __HW_8042_8042_H */
-
+++ /dev/null
-/* 8042.c
- *
- * Intel 8042 keyboard controller library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * On "IBM compatible" hardware the keyboard controller is responsible for
- * receiving scan codes from the keyboard. On newer (post 1990) systems,
- * the controller also handles PS/2 mouse input and communication (AUX).
- *
- * Note that on recent hardware (1999 or later) it's entirely possible the
- * BIOS is using System Management Mode and/or a USB mouse & keyboard to
- * fake 8042 I/O ports and communications for backwards compatibility. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/8042/8042.h>
-
-/* Probe the 8042 for the AUX port. This verifies that AUX is present, it does NOT
- * necessarily mean that a PS/2 mouse is attached to it. */
-int k8042_probe_aux() {
- int r=0;
-
- k8042_flags &= ~K8042_F_AUX;
- k8042_disable_keyboard();
- k8042_drain_buffer();
-
- /* write command byte to enable the AUX and KEYB interrupts */
- if (k8042_write_command_byte(0x47)) { /* XLAT=1, enable aux, enable keyboard, SYS=1, enable IRQ12, enable IRQ1 */
- /* Check for 8024 AUX support by stuffing something into it's output register */
- k8042_enable_aux();
- k8042_flags |= K8042_F_AUX;
- if (k8042_write_command(0xD3) && k8042_write_data(0xAA)) {
- if (k8042_read_output_wait() == 0xAA && k8042_output_was_aux()) { /* NTS: We demand that the byte come back WITH the indication that it's from AUX */
- if (k8042_write_command(0xD3) && k8042_write_data(0x55)) {
- if (k8042_read_output_wait() == 0x55 && k8042_output_was_aux()) {
- r = 1; /* Aux works for me! */
- }
- }
- }
- }
- }
-
- if (r) {
- k8042_enable_aux();
- }
- else {
- k8042_flags &= ~K8042_F_AUX;
- }
-
- k8042_enable_keyboard();
- return r;
-}
-
-/* write a Synaptics touchpad command. caller is expected to read back 3 bytes */
-int k8042_write_aux_synaptics_mode(unsigned char c) {
- if (k8042_write_aux(0xE7) && k8042_read_output_wait() == 0xFA && /* set scaling 2:1 */
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>6)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>4)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>2)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>0)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0x14) && k8042_read_output_wait() == 0xFA) { /* 0xE9 status request */
- return 1;
- }
-
- return 0;
-}
-
-/* write a Synaptics touchpad command. caller is expected to read back 3 bytes */
-int k8042_write_aux_synaptics_E8(unsigned char c) {
- if (k8042_write_aux(0xE7) && k8042_read_output_wait() == 0xFA && /* set scaling 2:1 */
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>6)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>4)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>2)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xE8) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux((c>>0)&3) && k8042_read_output_wait() == 0xFA &&
- k8042_write_aux(0xE9) && k8042_read_output_wait() == 0xFA) { /* 0xE9 status request */
- return 1;
- }
-
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_8042_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = 8042.c
-OBJS = $(SUBDIR)$(HPS)8042.obj $(SUBDIR)$(HPS)8042aux.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_8042_LIB): $(OBJS)
- wlib -q -b -c $(HW_8042_LIB) -+$(SUBDIR)$(HPS)8042.obj -+$(SUBDIR)$(HPS)8042aux.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_8042_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_8042_LIB) $(HW_8042_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(HW_8042_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)test.obj name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_8042_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* test.c
- *
- * Intel 8042 keyboard controller library test program.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * This program allows you (the curious programmer) to play with your
- * keyboard controller and experiment to see what it is capable of,
- * and to get a better idea of what is involved in writing software
- * to talk to it.
- *
- * WARNING: This code can put your keyboard controller in a state where
- * the keyboard stops responding temporarily until you reboot,
- * or is in the wrong scan code set. As far as I know, this code
- * cannot damage your keyboard or keyboard controller in any
- * way. In the unlikely chance it does, this code carries no
- * warranty express or implied. */
-
-/* NTS: This should work well on all systems I have, except for one 386 motherboard that I know has
- * an annoying quirk with it's controller: when the controller sets the "OUTPUT FULL" bit
- * it leaves it set for about 30-40ms after we read it. If we blindly rely on reading output
- * whenever that's set we end up with many duplicate characters. So while this test code is
- * probably the simplest way to do it, the best way to do it is to hook IRQ 1 and read data
- * THERE, not poll. */
-/* NTS: I can also attest from programming experience that most PC/AT and modern PC hardware is
- * FAR from ideal when it comes to implementing or emulating the 8042 keyboard controller.
- * Many implementations have bugs or corner cases that might cause problems with this
- * program. The most common one it seems is that certain commands like Set/Reset LEDs are
- * prone to leave the keyboard in a disabled state if the user is mashing keys while triggering
- * the command. */
-/* NTS: Emulator testing: Bochs and VirtualBox are fine for testing this code, but DO NOT USE DOSBox.
- * DOSBox 0.74's emulation of the 8042 is pitifully minimalist and a lot of what we play with
- * here is not implemented at all. At best you can verify that, yes, DOSBox 0.74 is sending us
- * scan codes. That's it. */
-/* NTS: Don't forget what we play with here is a limited subset of what most keyboards and keyboard
- * controllers are capable of. However such commands could easily put the keyboard in a state
- * that makes our UI unusable, especially the ones that change scan code conversion or switch
- * scan code modes. To fully play around with this system and understand what you are doing
- * you need to download or obtain a 8042 and keyboard programming reference. */
-/* NTS: Apparently on newer hardware, when faking 8042 via "Legacy USB support" in the BIOS, there
- * is a very real danger that issuing "self-test" command could completely sever the connection
- * within the BIOS between the fakery and the USB keyboard, making your USB keyboard unusable!
- * The USB fakery is especially fragile on some nVidia nforce + AMD systems I have that were
- * bought around 2003-ish, sometimes for no reason at all keyboard input can just go dead!
- * Also: Set LEDs command doesn't work
- * Diagnostic echo doesn't work
- * Keyboard ID doesn't work
- * Keyboard reset doesn't work */
-
-/* Other known bugs:
- *
- * PS/2 raw input on Sun/Oracle VirtualBox on 32-bit builds running under DOS4G/W:
- * Symptoms: For unknown reasons, raw input will only show the first byte of the PS/2 packet.
- * The main loop will show all three (as "discarding" bytes). This probably has something
- * to do with DOS4GW.EXE's shitty handling of the second interrupt controller, the
- * same problem that plagues our Sound Blaster test program. The interrupt indicators
- * at the top of the screen will show intermittent IRQ activity for IRQ 12 when PS/2 raw
- * input is active.
- *
- * Solution: Replace the DOS4G/W extender with DOS32a, or use another emulator that doesn't
- * have this strange conflict with DOS4G/W
- */
-/* FIXME: This code does something to the BIOS's shift status where pusing '8' to toggle the LEDs
- * only works once, the user has to type SHIFT+8 to toggle again. Why is that? */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <i86.h>
-#include <dos.h>
-
-#include <hw/8042/8042.h>
-
-unsigned char chain_irq1 = 1;
-void (__interrupt __far *prev_irq1)() = NULL;
-static void __interrupt __far irq1() {
-#if TARGET_MSDOS == 32
- (*((unsigned char*)(0xB8000)))++; /* keyboard shift flags 1 */
- *((unsigned char*)(0xB8001)) = 0x1E;
-#else
- (*((unsigned char far*)MK_FP(0xB800,0)))++; /* keyboard shift flags 1 */
- *((unsigned char far*)MK_FP(0xB800,1)) = 0x1E;
-#endif
-
- if (chain_irq1) {
- prev_irq1();
- }
- else {
- outp(0x20,0x20);
- }
-}
-
-unsigned char chain_irq12 = 1;
-void (__interrupt __far *prev_irq12)() = NULL;
-static void __interrupt __far irq12() {
-#if TARGET_MSDOS == 32
- (*((unsigned char*)(0xB8002)))++; /* keyboard shift flags 1 */
- *((unsigned char*)(0xB8003)) = 0x1E;
-#else
- (*((unsigned char far*)MK_FP(0xB800,2)))++; /* keyboard shift flags 1 */
- *((unsigned char far*)MK_FP(0xB800,3)) = 0x1E;
-#endif
-
- if (chain_irq12) {
- prev_irq12();
- }
- else {
- outp(0xA0,0x20);
- outp(0x20,0x20);
- }
-}
-
-/* the problem with our raw input intervention is that the user might have had modifier
- * keys down (shift, alt, etc.) and if we don't clear those states, the user will find
- * themselves accidentally typing in all caps or worse */
-void force_clear_bios_shift_states() {
-#if TARGET_MSDOS == 32
- *((unsigned char*)(0x400+0x17)) = 0x00; /* keyboard shift flags 1 */
- *((unsigned char*)(0x400+0x18)) = 0x00; /* keyboard shift flags 2 */
-#else
- *((unsigned char far*)MK_FP(0x40,0x17)) = 0x00; /* keyboard shift flags 1 */
- *((unsigned char far*)MK_FP(0x40,0x18)) = 0x00; /* keyboard shift flags 2 */
-#endif
-}
-
-/* FIXME: This code has problems with sometimes leaving the keyboard unresponsive at random.
- * Otherwise, a lot of fun. Perhaps a future upgrade would be to have this inner loop
- * interpret scan codes directly, along with a subroutine to take in bytes and return
- * integer values representing either ASCII or extended info */
-void ps2_mouse_main() {
- int c;
-
- _cli();
- if (!k8042_probe_aux() && !k8042_probe_aux()) {
- printf("PS/2 AUX port does not appear to be present\n");
- _sti();
- return;
- }
-
- /* mouse interface test */
- k8042_disable_keyboard();
- k8042_disable_aux();
- k8042_drain_buffer();
- if (k8042_write_command(0xA9)) {
- c = k8042_read_output_wait();
- printf("Mouse interface test result: ");
- if (c >= 0) printf("0x%02x\n",c);
- else printf("??\n");
- }
- else {
- c = 0;
- printf("Mouse interface test failed, cannot write command\n");
- }
- k8042_enable_aux();
- k8042_enable_keyboard();
- _sti();
-
- if (c != 0x00)
- return;
-
- /* Okay, reset mouse */
- printf("Resetting PS/2 mouse (if possible)... "); fflush(stdout);
- _cli();
- chain_irq1 = chain_irq12 = 0;
- k8042_disable_keyboard();
- k8042_drain_buffer();
- if (k8042_write_aux(0xFF)) { /* "returns BAT value (0xAA) and device ID" my ass. It 0xFA acks like everybody else */
- c = k8042_read_output_wait();
- if (!k8042_output_was_aux()) printf("Non-AUX response 0x%02x\n",c);
- else if (c != 0xFA) printf("Not ACK 0x%02x\n",c);
- else printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- printf("Setting defaults... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xF6)) {
- c = k8042_read_output_wait();
- /* an ancient PS/2 mouse I have response with 0xFE */
- if (c == 0xFE) {
- c = k8042_read_output_wait();
- if (c < 0) c = k8042_read_output_wait();
- if (c < 0) c = k8042_read_output_wait();
- }
- if (!k8042_output_was_aux()) printf("Non-AUX response 0x%02x\n",c);
- else if (c != 0xFA) printf("Not ACK 0x%02x\n",c);
- else printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- printf("Setting rate to 60... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(60) && k8042_read_output_wait() == 0xFA) {
- printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xF2) && k8042_read_output_wait() == 0xFA) {
- /* FIXME: extra long delay needed for my Toshiba laptop */
- c = k8042_read_output_wait();
- if (c < 0) c = k8042_read_output_wait();
- if (c < 0) c = k8042_read_output_wait();
- printf("OK: %02x\n",c);
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- printf("Turning on streaming mode... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xEA) && k8042_read_output_wait() == 0xFA) {
- printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- printf("Enabling reporting mode... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xF4) && k8042_read_output_wait() == 0xFA) {
- printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- _sti();
-
- if (!(k8042_write_data(0xF4) && k8042_read_output_wait() == 0xFA))
- printf("Cannot enable keyboard\n");
-
- do {
- k8042_enable_keyboard();
- printf("PS/2 mouse: 1. raw input 2. Reinit AUX 3. Status 4. Init Scrollwheel\n");
- printf(" 5. Init scroll + 4th/5th btns 6. DeviceID 7. Synaptics ID\n");
- printf(" 8. Synaptics touchpad modes 9. Synaptics capabilities\n");
- printf(" A. Synaptics model ID B. Synaptics serial\n");
- printf(" C. Synaptics resolutions D. Synaptics Abs. mode\n");
- printf(" E. Synaptics relative mode\n");
-
- /* read the keyboard directly. we must do this to ensure that any AUX bytes coming in
- * are discarded and removed from the H/W buffers. if we don't, then, depending on the
- * 8042 controller we're talking to, keyboard I/O could easily be locked out because
- * of the single path that both take through the 8042 controller. */
- while (1) {
- c = k8042_read_output_wait();
- if (c < 0) continue;
-
- if (k8042_output_was_aux())
- fprintf(stderr,"Discarding AUX input %02X\n",c);
- else if (c & 0x80)
- continue; /* ignore break codes */
- else {
- switch (c) {
- case 1: c = 27; break;
- case 2: c = '1'; break;
- case 3: c = '2'; break;
- case 4: c = '3'; break;
- case 5: c = '4'; break;
- case 6: c = '5'; break;
- case 7: c = '6'; break;
- case 8: c = '7'; break;
- case 9: c = '8'; break;
- case 10: c = '9'; break;
- case 0x1E: c = 'A'; break;
- case 0x30: c = 'B'; break;
- case 0x2E: c = 'C'; break;
- case 0x20: c = 'D'; break;
- case 0x12: c = 'E'; break;
- case 0x39: c = ' '; break;
- default: c = -1; break;
- }
-
- if (c >= 0) break;
- }
- }
-
- k8042_disable_keyboard();
- if (c == 27) break;
- else if (c == 'E') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_mode(0x40)) {
- printf("OK\n");
- }
- }
- else if (c == 'D') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_mode(0xC1)) {
- printf("OK\n");
- }
- }
- else if (c == 'C') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_E8(0x08)) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("Status: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- }
- }
- else if (c == 'B') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_E8(0x06)) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("pre: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- }
- if (k8042_write_aux_synaptics_E8(0x07)) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("suf: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- }
- }
- else if (c == 'A') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_E8(0x03)) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("Status: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- printf("Yes, this is a Synaptics PS/2 touchpad\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
- }
- else if (c == '9') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_E8(0x02)) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("Status: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- printf("Yes, this is a Synaptics PS/2 touchpad\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
- }
- else if (c == '8') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_E8(0x01)) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("Status: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- if (b1 == 0x3B && b2 == 0x47) printf("Yes, this is a Synaptics PS/2 touchpad\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
- }
- else if (c == '7') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- /* E8 00 E8 00 E8 00 E8 00 E9 */
- if (k8042_write_aux_synaptics_E8(0x00)) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("Status: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- if (b2 == 0x47) printf("Yes, this is a Synaptics PS/2 touchpad\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
- }
- else if (c == '6') {
- printf("Reading device ID... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xF2) && k8042_read_output_wait() == 0xFA) {
- c = k8042_read_output_wait();
- printf("OK: %02x\n",c);
- }
- else {
- printf("..Cannot write AUX\n");
- }
- }
- else if (c == '5') {
- k8042_drain_buffer();
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(200) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 200\n");
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(100) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 100\n");
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(80) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 80\n");
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(200) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 200\n");
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(200) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 200\n");
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(80) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 80\n");
- }
- else if (c == '4') {
- k8042_drain_buffer();
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(200) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 200\n");
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(100) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 100\n");
- if (k8042_write_aux(0xF3) && k8042_read_output_wait() == 0xFA && k8042_write_aux(80) && k8042_read_output_wait() == 0xFA)
- printf(" OK-set 80\n");
- }
- else if (c == '3') {
- k8042_drain_buffer();
- if (k8042_write_aux(0xE9) && k8042_read_output_wait() == 0xFA) {
- int b1,b2,b3;
- b1 = k8042_read_output_wait();
- b2 = k8042_read_output_wait();
- b3 = k8042_read_output_wait();
- printf("Status: 0x%02X 0x%02x 0x%02x\n",b1,b2,b3);
- }
- }
- else if (c == '2') {
- k8042_disable_aux();
- k8042_enable_aux();
- k8042_drain_buffer();
-
- printf("Turning on streaming mode... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xEA) && k8042_read_output_wait() == 0xFA) {
- printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- printf("Enabling reporting mode... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xF4) && k8042_read_output_wait() == 0xFA) {
- printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
- }
- else if (c == '1') {
- _cli();
- k8042_enable_keyboard();
- printf("PS/2 mouse raw input: (hit ESC to exit)\n");
- do {
- /* NTS: to avoid any BIOS conflicts we read the keyboard ourself */
- c = k8042_read_output_wait();
- if (c < 0) continue;
-
- /* was that keyboard input or mouse input? */
- if (k8042_output_was_aux()) {
- printf("%02x ",c); /* mouse input */
- fflush(stdout);
- }
- else { /* keyboard input. we're looking for "escape" */
- if (c == 0x81) break; /* the "break" code */
- else {
- printf("<KEY %02x> ",c);
- fflush(stdout);
- }
- }
- } while(1);
- force_clear_bios_shift_states();
- printf("\n");
- _sti();
- }
- } while(1);
-
- /* most test routines in this program aren't equipped to distinguish AUX and KEYBOARD input,
- * so we need to shutdown the AUX port and shutdown the mouse */
- printf("Disabling reporting mode... "); fflush(stdout);
- k8042_drain_buffer();
- if (k8042_write_aux(0xF5) && k8042_read_output_wait() == 0xFA) {
- printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- k8042_drain_buffer();
- if (k8042_write_aux(0xFF)) { /* "returns BAT value (0xAA) and device ID" my ass. It 0xFA acks like everybody else */
- c = k8042_read_output_wait();
- if (!k8042_output_was_aux()) printf("Non-AUX response 0x%02x\n",c);
- else if (c != 0xFA) printf("Not ACK 0x%02x\n",c);
- else printf("OK\n");
- }
- else {
- printf("..Cannot write AUX\n");
- }
-
- k8042_disable_aux();
- k8042_drain_buffer(); /* <- disabling AUX may cause readback of an ACK.
- adding this fixes the bug where reiniting AUX then exiting
- the menu leaves the keyboard unresponsive in VirtualBox and
- on most actual PC hardware */
- k8042_enable_keyboard();
- chain_irq1 = chain_irq12 = 1;
-}
-
-int main() {
- unsigned char leds = 0x7;
- int c,i;
-
- printf("8042 keyboard controller test code\n");
- if (!k8042_probe())
- printf("Warning: unable to probe 8042 controller. Is it there?\n");
-
- prev_irq1 = _dos_getvect(K8042_IRQ+0x08);
- _dos_setvect(K8042_IRQ+0x8,irq1);
-
- prev_irq12 = _dos_getvect(K8042_MOUSE_IRQ-8+0x70);
- _dos_setvect(K8042_MOUSE_IRQ-8+0x70,irq12);
-
- do {
- /* NTS: Unfortunately, DOSBox 0.74's 8042 emulation ignores a lot of the commands we play with here, but
- * this code works on actual hardware. */
- /* NTS: It is VERY important that these commands disable the keyboard (0xAD) *THEN* drain the buffer
- * before issuing the command and reading back the response. If you do not, any keypress that
- * happens between draining and disabling the keyboard will get in the way and be mistaken for
- * the command's response. Very unlikely, but if you mash the keyboard and cause a lot of input
- * here that *can* happen. */
- printf("\n");
- printf(" 1. Raw input 2. Command byte 3. Self-test\n");
- printf(" 4. Keyboard intf. test 5. Input port 6. Output port\n");
- printf(" 7. Test inputs 8. Cycle LEDs 9. Diag. echo\n");
- printf(" A. Keyboard ID B. Reset C. Write out\n");
- printf(" M: PS/2 aux. menu S. Read scan code set !. Scancode1\n");
- printf(" t: s.c.1 and disable xlat @. Scancode2 #. Scancode3\n");
- c = getch();
- if (c == 'M') {
- ps2_mouse_main();
- }
- else if (c == '!' || c == '@' || c == '#') {
- int set = 1;
- int ok = 0;
- _cli();
- if (c == '!') set = 1;
- else if (c == '@') set = 2;
- else if (c == '#') set = 3;
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- /* set scan code #1 */
- if (k8042_write_data(0xF0) && k8042_read_output_wait() == 0xFA && k8042_write_data(set) && k8042_read_output_wait() == 0xFA) {
- /* it is unspecified whether the keyboard ACKs again after setting the scan code. VirtualBox seems to do it anyway */
- if (k8042_read_output_wait() != 0xFA) printf("...no extra ack?\n");
- /* Now wait... did the keyboard actually switch scan codes or not?
- * Many laptops I own for example seem to ignore the set scancode command and when we disable translation, we get Scan Code Set 2 */
- c = 0xFF;
- if (k8042_write_data(0xF0) && k8042_read_output_wait() == 0xFA) {
- if (k8042_write_data(0x00)) {
- c = k8042_read_output_wait();
- if (c == 0xFA) {
- c = k8042_read_output_wait();
- if (c < 0) printf("...Ack, but then no response?\n");
- }
- else {
- if (k8042_read_output_wait() != 0xFA) printf("...no extra ack?\n");
- }
- }
- }
-
- if ( (set == 1 && (c == 0x43 || c == 0x01)) ||
- (set == 2 && (c == 0x41 || c == 0x02)) ||
- (set == 3 && (c == 0x3F || c == 0x03))) {
- /* now write command byte to disable translation */
- printf("I set scan code 1, now disabling translation\n");
- if (k8042_write_command_byte(0x05)) { /* XLAT=0 keyb/mouse enable SYS=1 INT2=0 INT=1 */
- printf("And translation should be disabled now\n");
- ok = 1;
- }
- }
- else {
- /* nope, it ignore us */
- printf("Nope, your keyboard did not switch to scan code set 1.\n");
- }
- }
- else {
- printf("Failed to send 0x00\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
-
- if (ok) {
- /* echo them */
- chain_irq1 = 0;
- printf("Printing raw input from keyboard. Hit ESC to quit.\n");
- do {
- _cli();
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("0x%02x ",c); fflush(stdout);
- }
- _sti();
- } while ((set == 1 && c != 0x01) ||
- (set == 2 && c != 0x76) ||
- (set == 3 && c != 0x08));
- /* eat ESC key-up */
- do {
- _cli();
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("0x%02x ",c); fflush(stdout);
- }
- _sti();
- } while ((set == 1 && c != 0x81 && c != 0x01) ||
- (set == 2 && c != 0x76) ||
- (set == 3 && c != 0x08));
- chain_irq1 = 1;
-
- /* fun's over */
- _cli();
- force_clear_bios_shift_states();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- /* set scan code #2 (most modern systems have this) */
- if (k8042_write_data(0xF0) && k8042_read_output_wait() == 0xFA && k8042_write_data(0x02) && k8042_read_output_wait() == 0xFA) {
- /* it is unspecified whether the keyboard ACKs again after setting the scan code. VirtualBox seems to do it anyway */
- if (k8042_read_output_wait() != 0xFA) printf("...no extra ack?\n");
- /* Now wait... did the keyboard actually switch scan codes or not?
- * Many laptops I own for example seem to ignore the set scancode command and when we disable translation, we get Scan Code Set 2 */
- c = 0xFF;
- if (k8042_write_data(0xF0) && k8042_read_output_wait() == 0xFA) {
- if (k8042_write_data(0x00)) {
- c = k8042_read_output_wait();
- if (c == 0xFA) {
- c = k8042_read_output_wait();
- if (c < 0) printf("...Ack, but then no response?\n");
- }
- else {
- if (k8042_read_output_wait() != 0xFA) printf("...no extra ack?\n");
- }
- }
- }
-
- if (c == 0x41 || c == 0x02) {
- /* now write command byte to disable translation */
- printf("I set scan code 2\n");
- }
- if (k8042_write_command_byte(0x45)) { /* XLAT=1 keyb/mouse enable SYS=1 INT2=0 INT=1 */
- printf("And translation should be enabled now\n");
- }
- }
- else {
- printf("Failed to send 0x00\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- }
- else if (c == 't') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- /* set scan code #1 */
- if (k8042_write_data(0xF0) && k8042_read_output_wait() == 0xFA && k8042_write_data(0x01) && k8042_read_output_wait() == 0xFA) {
- /* it is unspecified whether the keyboard ACKs again after setting the scan code. VirtualBox seems to do it anyway */
- if (k8042_read_output_wait() != 0xFA) printf("...no extra ack?\n");
- /* Now wait... did the keyboard actually switch scan codes or not?
- * Many laptops I own for example seem to ignore the set scancode command and when we disable translation, we get Scan Code Set 2 */
- c = 0xFF;
- if (k8042_write_data(0xF0) && k8042_read_output_wait() == 0xFA) {
- if (k8042_write_data(0x00)) {
- c = k8042_read_output_wait();
- }
- }
-
- if (c == 0x43 || c == 0x01) {
- /* now write command byte to disable translation */
- printf("I set scan code 1, now disabling translation\n");
- if (k8042_write_command_byte(0x05)) { /* XLAT=0 keyb/mouse enable SYS=1 INT2=0 INT=1 */
- printf("And translation should be disabled now\n");
- }
- }
- else {
- /* nope, it ignore us */
- printf("Nope, your keyboard did not switch to scan code set 1.\n");
- }
- }
- else {
- printf("Failed to send 0x00\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- printf("Alright, go ahead and type. The input should be the same as normal\n");
- goto scancode_watch;
- }
- else if (c == 'S') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_data(0xF0) && k8042_read_output_wait() == 0xFA) {
- c = 0xFF;
- if (k8042_write_data(0x00)) {
- printf("Wrote 0xF0, ");
- i = 0;
- do { /* NTS: Some keyboard and keyboard controller combos I have take quite a long time (250-500ms) to reset! */
- c = k8042_read_output_wait();
- /* NTS: Some keyboard controllers return ACK then the response,
- * others the response then ACK */
- } while ((c < 0 || c == 0xFA) && (++i) < 2);
- if (c >= 0) printf("Read back: %02x ",c);
- else printf("?? ");
- printf("\n");
- if (c == 0x43) printf("Scan code set #1\n");
- else if (c == 0x41) printf("Scan code set #2\n");
- else if (c == 0x3F) printf("Scan code set #3\n");
- else if (c == 0xFA) printf("Immediate ACK, probably not supported by your keyboard\n");
- if (c != 0xFA) {
- c = k8042_read_output_wait();
- if (c != 0xFA) printf("WARNING: No ACK after return value!\n");
- }
- /* NTS: DOSBox 0.74's emulation is so minimalist it stupidly ACKs even this command (returns 0xFA) */
- }
- else {
- printf("Failed to send 0x00 after 0xF0\n");
- }
- }
- else {
- printf("Failed to send 0x00\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == 'C') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_command(0xD2) && k8042_write_data(0xAA)) {
- printf("Wrote 0xAA, ");
- i = 0;
- do { /* NTS: Some keyboard and keyboard controller combos I have take quite a long time (250-500ms) to reset! */
- c = k8042_read_output_wait();
- } while (c < 0 && (++i) < 2);
- if (c >= 0) printf("Read back: %02x ",c);
- else printf("?? ");
- printf("\n");
- /* NTS: DOSBox 0.74's emulation is so minimalist it stupidly ACKs even this command (returns 0xFA) */
- }
- else {
- printf("Failed to send 0xF2\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == 'B') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_data(0xFF) && k8042_read_output_wait() == 0xFA) {
- i = 0;
- do { /* NTS: Some keyboard and keyboard controller combos I have take quite a long time (250-500ms) to reset! */
- c = k8042_read_output_wait();
- } while (c < 0 && (++i) < 32);
- if (c >= 0) printf("Reset BAT: %02x ",c);
- else printf("?? ");
- printf("\n");
-
- /* power-on might be "disabled" state */
- if (k8042_write_data(0xF4) && k8042_read_output_wait() == 0xFA) {
- printf("Reenable OK\n");
- }
- else {
- printf("Failed to reenable keyboard\n");
- }
- }
- else {
- printf("Failed to send 0xF2\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == 'A') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_data(0xF2) && k8042_read_output_wait() == 0xFA) {
- c = k8042_read_output_wait();
- if (c >= 0) printf("%02x ",c);
- else printf("?? ");
-
- c = k8042_read_output_wait();
- if (c >= 0) printf("%02x ",c);
- else printf("?? ");
-
- printf("\n");
- }
- else {
- printf("Failed to send 0xF2\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '9') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_data(0xEE)) {
- c = k8042_read_output_wait();
- if (c == 0xFA) { /* NTS: Hah! DOSBox 0.74's emulation is too lazy to implement this command! */
- printf("Your keyboard returned 0xFA (ACK) for command 0xEE, it shouldn't\n");
- c = k8042_read_output_wait(); /* NTS: I happen to know some old systems I have lying around would actually return 0xFA then 0xEE */
- }
- if (c == 0xEE)
- printf("OK\n");
- else
- printf("Keyboard did not return 0xEE\n");
- }
- else {
- printf("Failed to send 0xEE\n");
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '8') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_data(0xED) && (c=k8042_read_output_wait()) == 0xFA) {
- if (k8042_write_data(leds) && (c=k8042_read_output_wait()) == 0xFA) {
- }
- else {
- printf("Failed to send 0xED data (c = 0x%02X)\n",c);
- }
- }
- else {
- printf("Failed to send 0xED (c = 0x%02X)\n",c);
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- /* hopefully this is effective at resolving those "keyboard becomes unresponsive" issues
- * I see on test machines when you hold down '8' */
- k8042_drain_buffer();
- k8042_drain_buffer();
-
- printf("%u%u%u\n",(leds >> 2) & 1,(leds >> 1) & 1,leds & 1);
- leds = (leds+1)&7;
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '1') {
-scancode_watch:
- chain_irq1 = 0;
- printf("Printing raw input from keyboard. Hit ESC to quit.\n");
- do {
- _cli();
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("0x%02x ",c); fflush(stdout);
- }
- _sti();
- } while (c != 0x01);
- /* eat ESC key-up */
- do {
- _cli();
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("0x%02x ",c); fflush(stdout);
- }
- _sti();
- } while (c != 0x81);
- chain_irq1 = 1;
- printf("\n");
- }
- else if (c == '2') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_command(0x20)) {
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("Command byte: 0x%02x\n",c);
- }
- else {
- /* some emulators [DOSBox] do not emulate this command and do not respond */
- printf("Unable to read command byte. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
- }
- else {
- printf("Unable to write command. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '3') {
- _cli();
- chain_irq1 = 0;
-
- if (!(k8042_write_data(0xF5) && (c=k8042_read_output_wait()) == 0xFA))
- printf("Cannot disable keyboard (read 0x%02X)\n",c);
-
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_command(0xAA)) {
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("Self-test result: 0x%02x\n",c);
- }
- else {
- /* some emulators [DOSBox] do not emulate this command and do not respond */
- printf("Unable to read response. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
- }
- else {
- printf("Unable to write command. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
-
- /* some motherboards seem to reset the command byte on self-test */
- if (!k8042_write_command_byte(0x45))
- printf("Cannot write command byte\n");
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- c = -1;
- if (!(k8042_write_data(0xF4) && (c=k8042_read_output_wait()) == 0xFA))
- printf("Cannot enable keyboard (read 0x%02X)\n",c);
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '4') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_command(0xAB)) {
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("Self-test result: 0x%02x\n",c);
- }
- else {
- /* some emulators [DOSBox] do not emulate this command and do not respond */
- printf("Unable to read response. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
- }
- else {
- printf("Unable to write command. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- if (!(k8042_write_data(0xF4) && k8042_read_output_wait() == 0xFA))
- printf("Cannot enable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '5') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_command(0xC0)) {
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("Input port: 0x%02x\n",c);
- }
- else {
- /* some emulators [DOSBox] do not emulate this command and do not respond */
- printf("Unable to read response. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
- }
- else {
- printf("Unable to write command. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '6') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_command(0xD0)) {
- c = k8042_read_output_wait();
- if (c >= 0) {
- /* Holy shit---DOSBox actually emulates this! */
- printf("Output port: 0x%02x\n",c);
- }
- else {
- printf("Unable to read response. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
- }
- else {
- printf("Unable to write command. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == '7') {
- _cli();
- chain_irq1 = 0;
- if (!k8042_write_command(0xAD))
- printf("Cannot disable keyboard\n");
- k8042_drain_buffer();
- if (k8042_write_command(0xE0)) {
- c = k8042_read_output_wait();
- if (c >= 0) {
- printf("Test port: 0x%02x\n",c);
- }
- else {
- printf("Unable to read response. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
- }
- else {
- printf("Unable to write command. 0x64=0x%02x\n",inp(K8042_STATUS));
- }
-
- if (!k8042_write_command(0xAE))
- printf("Cannot disable keyboard\n");
-
- chain_irq1 = 1;
- _sti();
- }
- else if (c == 27) {
- break;
- }
- } while (1);
-
- _dos_setvect(K8042_MOUSE_IRQ-8+0x70,prev_irq12);
- _dos_setvect(K8042_IRQ+0x8,prev_irq1);
- return 0;
-}
-
+++ /dev/null
-/* 8237.c
- *
- * Intel 8237 DMA controller library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * On IBM compatible hardware, the 8237 (or emulation thereof)
- * controls DMA transfers to/from system memory and devices on the
- * ISA bus. PCI devices are not involved, since under normal circumstances
- * PCI devices cannot use ISA DMA channels (though in the mid to late 1990s
- * it was somewhat common for PCI sound card drivers to use virtualization
- * or a special connection to the motherboard to emulate Sound Blaster audio).
- *
- * DMA channels are numbered 0 through 7. 0 through 3 carry forward from the
- * original PC architecture, while 4-7 were added with the 16-bit AT bus to
- * enable 16-bit wide DMA transfers. In most cases, 8-bit at a time transfers
- * are carried over DMA 0-3 and 16-bit at a time over 4-7. However on EISA/PCI
- * chipsets made in the 1994-1997 timeframe by Intel, there did exist control
- * registers to change the "width" of the DMA channel, including the ability
- * to transfer 32-bit at a time to EISA devices.
- *
- * DMA channel 4 is a "cascade" channel that is used internally by the two
- * controllers linked together, it is never used by the system for data
- * transfers.
- *
- * DMA controller addresses are limited to 24 bits (20 on really old hardware).
- * This is why on systems with >= 16MB of RAM it is not possible to DMA from
- * just any location in memory. In fact this limitation is the reason the x86
- * platform builds of the Linux kernel like to reserve lower "DMA" memory
- * (whatever it can reserve below 16MB). On some Intel chipsets used in the 1995-2000
- * timeframe however, there exist extended EISA registers that enable DMA from the
- * full 32-bit addressable range. These extended control registers lie in the 4xxh
- * range, however probing for them is nearly impossible because in most cases the
- * registers are write-only. The only way to detect it it seems, is to ask the
- * ISA PnP BIOS for the system DMA controller and see if the reported I/O range
- * includes I/O ports 400h-4FFh. We do not detect this case by default, because the
- * ISA PnP library is huge and we don't want to cause EXE bloat. Just like the Sound
- * Blaster library, the EISA/PCI support routines and detection code is in a separate
- * PnP-aware portion. */
-
-/* TODO: PnP support code in 8237pnp.c, code that PnP aware programs can use to enable
- * the extended code and extended functions. */
-
-/* NTS: As of 2011/02/27 the 8254 routines no longer do cli/sti for us, we are expected
- * to do them ourself. This is for performance reasons as well as for sanity reasons
- * should we ever need to use the subroutines from within an interrupt handler */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8237/8237.h>
-#include <hw/dos/doswin.h>
-
-unsigned char d8237_flags = 0;
-unsigned char d8237_channels = 0;
-unsigned char d8237_dma_address_bits = 0;
-unsigned char d8237_dma_counter_bits = 0;
-uint32_t d8237_dma_address_mask = 0;
-uint32_t d8237_dma_counter_mask = 0;
-unsigned char *d8237_page_ioport_map = NULL;
-unsigned char d8237_page_ioport_map_xt[8] = {0x87,0x83,0x81,0x82, 0x8F,0x8F,0x8F,0x8F}; /* TODO: how to detect PC/XT? */
-unsigned char d8237_page_ioport_map_at[8] = {0x87,0x83,0x81,0x82, 0x8F,0x8B,0x89,0x8A};
-
-/* one bit per channel that is 16-bit AND requires address shift (lower 16 bits >> 1) AND the counter is # of WORDs */
-/* in the original implementation we take the lower 16 bits and shift right by 1 for WORD transfers,
- * the later Intel chipsets allow for 8, 16 & 32-bit transfers on any channel with or without
- * the 16-bit address shift, which is why this is a variable not a const */
-unsigned char d8237_16bit_ashift = 0xF0;
-
-static int d8237_readwrite_test4(unsigned int bch) {
- int j,i;
-
- if (bch & 4) {
- for (j=8;j < 16;j++) {
- if (inp(0xC0+(j*2)) != 0xFF) break; /* found SOMETHING */
- }
- }
- else {
- for (j=8;j < 16;j++) {
- if (inp(j) != 0xFF) break; /* found SOMETHING */
- }
- }
-
- if (j != 16) { /* OK. Now go through any DMA channel that still reads 0xFFFF 0xFFFF
- and try to modify the value. As for conflicts with active
- DMA channels? Well... if they're all reading 0xFFFF then none
- of them are active, so what's to worry about really? */
- for (i=0;i < 4;i++) {
- if (d8237_read_base_lo16(bch+i) == 0xFFFFU && d8237_read_count_lo16(bch+i) == 0xFFFFU) {
- d8237_write_count(bch+i,0x20); /* harmless short count */
- d8237_write_base(bch+i,0xBBBB0UL); /* direct it harmlessly at unused VGA RAM */
- if (d8237_read_base_lo16(bch+i) != 0xFFFFU || d8237_read_count_lo16(bch+i) != 0xFFFFU) {
- d8237_write_count(bch+i,0xFFFF);
- d8237_write_base(bch+i,0xFFFFFF);
- return 1; /* found one */
- }
- }
- else {
- return 1; /* wait, found one! */
- }
- }
- }
-
- return 0;
-}
-
-/* probing function, for several reasons:
- * - post-2011 systems may very well omit the DMA controller entirely, as legacy hardware
- * - pre-AT hardware may not have the secondary DMA controller
- * - EISA and PCI systems have a newer chipset with extended registers for addressing
- * memory above the 16MB ISA barrier in transfer sizes up to 16MB (Intel 82357, Intel 82374, etc.) */
-/* FIXME: Programming experience says that while most 1995-2000-ish motherboards do support these extended
- * registers, reading the I/O ports will still yield 0xFF and therefore probing the I/O ports is
- * not the way to detect them. You can however detect their presence if you use the ISA Plug & Play
- * interface, because the DMA controller system node will list I/O ports in the 0x400-0x4FF range. */
-/* FIXME: Just like the other libraries, add a 8237_pnp.lib file that ISA PnP aware programs can compile in
- * to detect by PnP and gain access to the extended registers. */
-int probe_8237() {
- int i;
-
- probe_dos();
- detect_windows();
-#if TARGET_MSDOS == 32
- dos_ltp_probe(); /* needed for DMA transfer code */
-#endif
-
- d8237_flags = 0;
- /* test primary DMA controller */
- for (i=0;i < 4;) {
- if (d8237_read_base_lo16(i) != 0xFFFFU) break;
- if (d8237_read_count_lo16(i) != 0xFFFFU) break;
- i++;
- }
-
- /* BUGFIX: Apparently, on an old Sharp laptop, it's quite possible after cold boot
- * for ALL 4 DMA CHANNELS to register as having base == 0xFFFF and count == 0xFFFF
- * which falsely leads our code to believe there's no DMA controller! */
- if (i == 4 && d8237_readwrite_test4(0)) i = 0;
- if (i == 4) return 0; /* if not found, then quit */
- d8237_flags |= D8237_DMA_PRIMARY;
-
- /* are the page registers 8 bits wide, or 4? */
- {
- /* test DMA channel 2's page register, since it's unlikely the floppy controller
- * will be doing anything at this point */
- unsigned char iop = d8237_page_ioport_map_xt[2],orig;
- orig = inp(iop);
- outp(iop,0xFE);
- if (inp(iop) == 0xFE) {
- outp(iop,0x0E);
- if (inp(iop) == 0x0E) {
- d8237_flags |= D8237_DMA_8BIT_PAGE;
- }
- }
- outp(iop,orig);
- }
-
- /* test secondary DMA controller */
- for (i=4;i < 8;) {
- if (d8237_read_base_lo16(i) != 0xFFFFU) break;
- if (d8237_read_count_lo16(i) != 0xFFFFU) break;
- i++;
- }
- if (i == 8 && d8237_readwrite_test4(4)) i = 4;
- if (i != 8) d8237_flags |= D8237_DMA_SECONDARY; /* if found, then say so */
-
- if (d8237_flags & D8237_DMA_SECONDARY) {
- d8237_page_ioport_map = d8237_page_ioport_map_at;
- d8237_channels = 8;
- }
- else {
- d8237_page_ioport_map = d8237_page_ioport_map_xt;
- d8237_channels = 4;
- }
-
- if (d8237_flags & D8237_DMA_8BIT_PAGE)
- d8237_dma_address_bits = 24;
- else
- d8237_dma_address_bits = 20;
-
- d8237_dma_address_mask = (1UL << ((unsigned long)d8237_dma_address_bits)) - 1UL;
- d8237_dma_counter_mask = 0xFFFF;
- d8237_dma_counter_bits = 16;
- return 1;
-}
-
-/* Compatible AT DMA controllers do this weird addressing on channels 4-7 where the
- * lower 16 bits are shifted right 1 bit (while not shifting the page registers).
- * This is the beautiful hack apparently that allows them to transfer WORDs at a time
- * and up to 128KB. Newer Intel DMA controllers have extended registers to select
- * 8/16/32-bit transfers and to enable/disable this shift on a per-channel basis
- * which is why we have the 16bit_ashift bitmask to track that. */
-/* FIXME: So if we shift over 1 bit, what happens to the address when bit 15 is actually set? */
-uint32_t d8237_read_base(unsigned char ch) {
- uint32_t r = d8237_read_base_lo16(ch);
- if (d8237_16bit_ashift & (1<<ch)) r <<= 1UL;
- r |= (uint32_t)inp(d8237_page_ioport_map[ch]) << (uint32_t)16;
- return r;
-}
-
-void d8237_write_base(unsigned char ch,uint32_t o) {
- if (d8237_16bit_ashift & (1<<ch)) {
- d8237_write_base_lo16(ch,o>>1UL);
- outp(d8237_page_ioport_map[ch],o >> 16);
- }
- else {
- d8237_write_base_lo16(ch,o);
- outp(d8237_page_ioport_map[ch],o >> 16);
- }
-}
-
-/* The "count" is BYTES - 1 not BYTES. On compatible AT controllers and newer controllers in
- * compat. mode DMA channels 4-7 transfer 16-bit WORDs at a time and the count is number
- * of WORDS - 1 */
-uint32_t d8237_read_count(unsigned char ch) {
- uint32_t r = (uint32_t)d8237_read_count_lo16(ch) + (uint32_t)1UL;
- if (d8237_16bit_ashift & (1<<ch)) r <<= 1UL;
- return r;
-}
-
-void d8237_write_count(unsigned char ch,uint32_t o) {
- if (d8237_16bit_ashift & (1<<ch)) d8237_write_count_lo16(ch,(o>>1) - (uint32_t)1);
- else d8237_write_count_lo16(ch,o - (uint32_t)1);
-}
-
-void dma_8237_free_buffer(struct dma_8237_allocation *a) {
- if (a != NULL) {
- if (a->lin != NULL) {
-#if TARGET_MSDOS == 32
- if (a->dos_selector != 0) {
- dpmi_free_dos(a->dos_selector);
- a->dos_selector = 0U;
- a->lin = NULL;
- }
- if (a->lin_handle != 0) {
- dpmi_linear_unlock((uint32_t)a->lin,a->length);
- dpmi_linear_free(a->lin_handle);
- a->lin_handle = 0U;
- a->lin = NULL;
- }
- if (a->lin != NULL) {
- dpmi_linear_unlock((uint32_t)a->lin,a->length);
- free(a->lin);
- a->lin = NULL;
- }
-#else
- _ffree(a->lin);
-#endif
- }
- a->lin = NULL;
- a->phys = 0UL;
- a->length = 0UL;
- free(a);
- }
-}
-
-struct dma_8237_allocation *dma_8237_alloc_buffer(uint32_t len) {
- struct dma_8237_allocation *a = malloc(sizeof(struct dma_8237_allocation));
- const unsigned int leeway = 4096;
- /* ^ I will remove this leeway value when DOSBox 0.74 no longer has a fucking panic attack
- * over the DMA pointer getting too close to the 64KB boundary edge [FIXME: I believe I
- * did something else to this code to further resolve that, do we still need this leeway value?] */
- memset(a,0,sizeof(*a));
-
- if (len >= 0xFFF0UL)
- goto fail;
-
- if (a != NULL) {
-#if TARGET_MSDOS == 32
- /* first try high memory, but only if paging is disabled or the DOS library is able to translate linear to physical */
- if (!dos_ltp_info.paging) {
- uint32_t handles[16],handle=0;
- uint32_t patience=16,o;
- uint64_t phys,base;
- int ok=0;
-
- while (!ok && patience-- != 0UL) {
- /* NOTE: If this actually works I wan't to know! */
- a->length = len;
- a->lin = dpmi_linear_alloc(0/*whatever linear addr works*/,len,1/*committed pages*/,&a->lin_handle);
- if (a->lin != NULL) {
- /* wait: make sure we can locate it's physical location and that it's contigious in physical memory */
- dpmi_linear_lock((uint32_t)(a->lin),a->length);
- base = dos_linear_to_phys((uint32_t)(a->lin));
- if (base != DOS_LTP_FAILED && base <= (uint64_t)d8237_dma_address_mask) {
- /* make sure it's contiguous in memory */
- for (o=4096UL;o < a->length;o += 4096UL) {
- phys = dos_linear_to_phys((uint32_t)(a->lin) + o);
- if (phys == DOS_LTP_FAILED) break;
- if (phys != (base+o)) break;
- if (phys > (uint64_t)d8237_dma_address_mask) break;
- /* if we crossed a DMA boundary, then abort */
- if (((phys+leeway)&0xFFFF0000UL) != (base&0xFFFF0000UL)) break;
- }
-
- if (o >= a->length) {
- a->phys = base;
- ok = 1;
- break;
- }
- }
-
- /* not worthy, unlock and free later */
- dpmi_linear_unlock((uint32_t)(a->lin),a->length);
- handles[handle++] = a->lin_handle;
- a->lin_handle = 0UL;
- a->lin = NULL;
- }
- else {
- a->lin_handle = 0UL;
- break;
- }
- }
-
- while (handle > 0)
- dpmi_linear_free(handles[--handle]);
- }
-
- /* Yeah, that DPMI 1.x call hardly works. But we can malloc() and see if it ends up as DMA-able.
- Note that this won't work with any paging-like system like EMM386.EXE or Windows
- DOS Box, but we can work around that by allocating the buffer in DOS where the
- programs remap and translate DMA */
- if (!dos_ltp_info.paging) {
- void *handles[16];
- uint32_t handle=0;
- uint32_t base,patience=16;
- int ok=0;
-
- while (!ok && patience-- != 0UL) {
- a->length = len;
- a->lin = malloc(len);
- if (a->lin != NULL) {
- base = (uint32_t)(a->lin);
- if ((base&0xFFFF0000) == ((base+len-1)&0xFFFF0000)) {
- a->phys = base; /* OK */
- }
- else {
- /* not worthy, unlock and free later */
- handles[handle++] = a->lin;
- a->lin = NULL;
- }
- }
- else {
- break;
- }
- }
-
- while (handle > 0)
- free(handles[--handle]);
- }
-
- /* if that failed, try DOS memory, but only if it's mapped 1:1 or we're assured DMA is translated along with the remapping */
- if (a->lin == NULL && (!dos_ltp_info.dos_remap || dos_ltp_info.dma_dos_xlate)) {
- uint16_t handles[16],handle=0;
- uint32_t patience=16;
- int ok=0;
-
- a->lin_handle = 0UL;
- while (!ok && patience-- != 0UL) {
- a->length = len;
- a->lin = dpmi_alloc_dos(a->length,&a->dos_selector);
- if (a->lin != NULL) {
- a->phys = (uint32_t)(a->lin);
- /* if it crosses a DMA boundary then fail */
- if ((a->phys&0xFFFF0000UL) != ((a->phys+a->length+leeway)&0xFFFF0000UL)) {
- ok = 0;
- }
- else {
- ok = 1;
- }
- }
-
- if (ok) break;
- handles[handle++] = a->dos_selector;
- a->dos_selector = 0U;
- a->lin = NULL;
- }
-
- while (handle > 0)
- dpmi_free_dos(handles[--handle]);
- }
-
- if (a->lin == NULL) goto fail;
-#else
- a->lin = _fmalloc(len);
- if (a->lin == NULL) goto fail;
- a->phys = ((uint32_t)FP_SEG(a->lin) << 4UL) + FP_OFF(a->lin);
- a->length = len;
-
- /* if it crosses a DMA 64KB boundary, then we have to try again */
- if ((a->phys & 0xFFFF0000ULL) != ((a->phys + len + leeway) & 0xFFFF0000UL)) {
- unsigned char FAR *s2 = _fmalloc(len);
- if (s2 == NULL) goto fail;
- _ffree(a->lin);
- a->lin = s2;
- a->phys = ((uint32_t)FP_SEG(a->lin) << 4UL) + FP_OFF(a->lin);
- /* if it crosses again, then obviously memory is too fragmented */
- if ((a->phys & 0xFFFF0000ULL) != ((a->phys + len + leeway) & 0xFFFF0000UL))
- goto fail;
- }
-#endif
- }
-
- return a;
-fail:
- if (a != NULL) {
-#if TARGET_MSDOS == 32
- if (a->lin_handle) {
- dpmi_linear_free(a->lin_handle);
- a->lin_handle = 0UL;
- a->lin = NULL;
- }
- if (a->dos_selector) {
- dpmi_free_dos(a->dos_selector);
- a->dos_selector = 0U;
- a->lin = NULL;
- }
- if (a->lin != NULL) {
- free(a->lin);
- a->lin = NULL;
- }
-#else
- if (a->lin) _ffree(a->lin);
- a->lin = NULL;
-#endif
- free(a);
- }
-
- return NULL;
-}
-
-uint16_t d8237_read_count_lo16(unsigned char ch) {
- unsigned int flags = get_cpu_flags();
- uint16_t r,r2,patience=32;
-
- /* The DMA controller as emulated by DOSBox and on real hardware does not guarantee latching the count while reading.
- * it can change between reading the upper and lower bytes. so we need to do this loop to read a coherent value. */
- _cli();
- d8237_reset_flipflop(ch);
- r2 = d8237_read_count_lo16_direct_ncli(ch);
- do {
- r = r2;
- r2 = d8237_read_count_lo16_direct_ncli(ch);
- /* the counter must be decreasing! */
- if ((r&0xFF00) != (r2&0xFF00)) continue;
- if (r == 0xFFFF) break; /* if at terminal count, then break now */
- if (r2 > r) continue;
- break;
- } while (--patience != 0U);
- _sti_if_flags(flags);
-
- return r2;
-}
-
+++ /dev/null
-/* 8237.h
- *
- * Intel 8237 DMA controller library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-/* WARNING: As usual for performance reasons this library generally does not
- * enable/disable interrupts (cli/sti). To avoid contention with
- * interrupt handlers the calling program should do that. */
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* primary DMA controller present (0x00-0x0F) */
-#define D8237_DMA_PRIMARY 0x01
-/* secondary DMA controller present (0xC0-0xDF) */
-#define D8237_DMA_SECONDARY 0x02
-/* EISA/PCI controller extended registers present (0x400-0x4FF) */
-#define D8237_DMA_EISA_EXT 0x04
-/* Intel 82374 EISA DMA controller */
-#define D8237_DMA_82374 0x08
-/* Intel 82357 EISA DMA controller */
-#define D8237_DMA_82357 0x10
-/* page registers are 8 bits wide */
-#define D8237_DMA_8BIT_PAGE 0x20
-
-/* registers _R_ = read _W_ = write _RW = r/w */
-#define D8237_REG_R_STATUS 0x08
-#define D8237_REG_W_COMMAND 0x08
-#define D8237_REG_W_REQUEST 0x09
-#define D8237_REG_W_SINGLE_MASK 0x0A
-#define D8237_REG_W_WRITE_MODE 0x0B
-#define D8237_REG_W_CLEAR_FLIPFLOP 0x0C
-#define D8237_REG_R_TEMPORARY 0x0D
-#define D8237_REG_W_MASTER_CLEAR 0x0D
-#define D8237_REG_W_CLEAR_MASK 0x0E
-#define D8237_REG_W_WRITE_ALL_MASK 0x0F
-
-/* command register bits */
-#define D8237_CMDR_MEM_TO_MEM_ENABLE 0x01
-#define D8237_CMDR_CH0_ADDR_HOLD_ENABLE 0x02
-#define D8237_CMDR_DISABLE_CONTROLLER 0x04
-#define D8237_CMDR_COMPRESSED_TIMING 0x08
-#define D8237_CMDR_ROTATING_PRIORITY 0x10
-#define D8237_CMDR_EXT_WRITE_SELECTION 0x20
-#define D8237_CMDR_DREQ_SENSE_ACTIVE_LOW 0x40
-#define D8237_CMDR_DACK_SENSE_ACTIVE_HIGH 0x80
-
-/* mask register */
-/* bits 0-1 = which channel to set
- * bit 2 = 1=mask channel 0=unmask channel */
-#define D8237_MASK_CHANNEL(x) ((x)&3)
-#define D8237_MASK_SET 0x04
-
-/* mode register */
-#define D8237_MODER_CHANNEL(x) ((x)&3)
-#define D8237_MODER_TRANSFER(x) (((x)&3) << 2)
-#define D8237_MODER_AUTOINIT 0x10
-#define D8237_MODER_ADDR_DEC 0x20
-#define D8237_MODER_MODESEL(x) (((x)&3) << 6)
-
-#define D8237_MODER_XFER_VERIFY 0
-#define D8237_MODER_XFER_WRITE 1
-#define D8237_MODER_XFER_READ 2
-
-#define D8237_MODER_MODESEL_DEMAND 0
-#define D8237_MODER_MODESEL_SINGLE 1
-#define D8237_MODER_MODESEL_BLOCK 2
-#define D8237_MODER_MODESEL_CASCADE 3
-
-/* request register */
-#define D8237_REQR_CHANNEL(x) ((x)&3)
-#define D8237_REQR_SET 0x04
-
-/* status register */
-#define D8237_STATUS_TC(x) (0x01 << ((x)&3))
-#define D8237_STATUS_REQ(x) (0x10 << ((x)&3))
-
-extern unsigned char d8237_flags;
-extern unsigned char d8237_dma_address_bits;
-extern unsigned char d8237_dma_counter_bits;
-extern uint32_t d8237_dma_address_mask;
-extern uint32_t d8237_dma_counter_mask;
-extern unsigned char *d8237_page_ioport_map;
-extern unsigned char d8237_page_ioport_map_xt[8];
-extern unsigned char d8237_page_ioport_map_at[8];
-extern unsigned char d8237_16bit_ashift;
-extern unsigned char d8237_channels;
-
-static inline unsigned char d8237_ioport(unsigned char ch,unsigned char reg) {
- if (ch & 4) return 0xC0+(reg<<1);
- else return 0x00+reg;
-}
-
-static inline unsigned char d8237_page_ioport(unsigned char ch) {
- return d8237_page_ioport_map[ch];
-}
-
-/*============*/
-static inline void d8237_reset_flipflop_ncli(unsigned char ch) {
- /* NOTE TO SELF: This code used to write the port, then read it. Based on some ancient 386SX laptop
- * I have who's DMA controller demands it, apparently. But then VirtualBox seems
- * to mis-emulate THAT and leave the flip-flop in the wrong state, causing erratic
- * DMA readings in the Sound Blaster program. Putting it in this order fixes it. */
- inp(d8237_ioport(ch,0xC));
- outp(d8237_ioport(ch,0xC),0x00); /* A3-0=1100 IOR=0 IOW=1 -> clear byte pointer flip/flop */
-}
-
-static inline void d8237_reset_flipflop(unsigned char ch) {
- unsigned int flags = get_cpu_flags();
- _cli();
- d8237_reset_flipflop_ncli(ch);
- _sti_if_flags(flags);
-}
-
-/*============*/
-static inline uint16_t d8237_read_base_lo16_ncli(unsigned char ch) {
- unsigned char iop = d8237_ioport(ch,(ch&3)*2);
- uint16_t r;
-
- d8237_reset_flipflop_ncli(ch);
- r = (uint16_t)inp(iop);
- r |= (uint16_t)inp(iop) << 8U;
- return r;
-}
-
-static inline uint16_t d8237_read_base_lo16(unsigned char ch) {
- unsigned int flags = get_cpu_flags();
- uint16_t x;
- _cli();
- x = d8237_read_base_lo16_ncli(ch);
- _sti_if_flags(flags);
- return x;
-}
-
-/*============*/
-static inline uint16_t d8237_read_count_lo16_direct_ncli(unsigned char ch) {
- unsigned char iop = d8237_ioport(ch,((ch&3)*2) + 1);
- uint16_t r;
-
- d8237_reset_flipflop_ncli(ch);
- r = (uint16_t)inp(iop);
- r |= (uint16_t)inp(iop) << 8U;
- return r;
-}
-
-static inline uint16_t d8237_read_count_lo16_direct(unsigned char ch) {
- unsigned int flags = get_cpu_flags();
- uint16_t x;
- _cli();
- x = d8237_read_count_lo16_direct_ncli(ch);
- _sti_if_flags(flags);
- return x;
-}
-
-/*============*/
-static inline void d8237_write_base_lo16_ncli(unsigned char ch,uint16_t o) {
- unsigned char iop = d8237_ioport(ch,(ch&3)*2);
- d8237_reset_flipflop_ncli(ch);
- outp(iop,o);
- outp(iop,o >> 8);
-}
-
-static inline void d8237_write_base_lo16(unsigned char ch,uint16_t o) {
- unsigned int flags = get_cpu_flags();
- _cli();
- d8237_write_base_lo16_ncli(ch,o);
- _sti_if_flags(flags);
-}
-
-/*============*/
-static inline void d8237_write_count_lo16_ncli(unsigned char ch,uint16_t o) {
- unsigned char iop = d8237_ioport(ch,((ch&3)*2) + 1);
- d8237_reset_flipflop_ncli(ch);
- outp(iop,o);
- outp(iop,o >> 8);
-}
-
-static inline void d8237_write_count_lo16(unsigned char ch,uint16_t o) {
- unsigned int flags = get_cpu_flags();
- _cli();
- d8237_write_count_lo16_ncli(ch,o);
- _sti_if_flags(flags);
-}
-
-/*============*/
-int probe_8237();
-uint32_t d8237_read_base(unsigned char ch);
-void d8237_write_base(unsigned char ch,uint32_t o);
-uint32_t d8237_read_count(unsigned char ch);
-void d8237_write_count(unsigned char ch,uint32_t o);
-uint16_t d8237_read_count_lo16(unsigned char ch);
-
-struct dma_8237_allocation {
- unsigned char FAR* lin; /* linear (program accessible pointer) */
- /* 16-bit real mode: _fmalloc()'d buffer */
- /* 32-bit prot mode: dpmi_alloc_dos() in DOS memory, or else allocated linear memory that has been locked and verified sequential in memory */
- uint32_t phys; /* physical memory address */
- uint32_t length; /* length of the buffer */
-#if TARGET_MSDOS == 32
- uint16_t dos_selector; /* if allocated by dpmi_alloc_dos() (nonzero) this is the selector */
- uint32_t lin_handle; /* if allocated by alloc linear handle, memory handle */
-#endif
-};
-
-void dma_8237_free_buffer(struct dma_8237_allocation *a);
-struct dma_8237_allocation *dma_8237_alloc_buffer(uint32_t len);
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_8237_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = 8237.c
-OBJS = $(SUBDIR)$(HPS)8237.obj
-
-$(HW_8237_LIB): $(OBJS)
- wlib -q -b -c $(HW_8237_LIB) -+$(SUBDIR)$(HPS)8237.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_8237_LIB) .symbolic
-
-exe: .symbolic
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_8237_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-#error YOU SHOULD NOT BE COMPILING THIS SOURCE FILE
+++ /dev/null
-/* 8250.c
- *
- * 8250/16450/16550/16750 serial port UART library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * On PCs that have them, the UART is usually a 8250/16450/16550 or compatible chip,
- * or it is emulated on modern hardware to act like one. At a basic programming level
- * the UART is very simple to talk to.
- *
- * The best way to play with this code, is to obtain a null-modem cable, connect two
- * PCs together, and run this program on either end. On most PC hardware, this code
- * should be able to run at a full baud rate sending and receiving without issues.
- *
- * For newer (post 486) systems with PnP serial ports and PnP aware programs, this
- * library offers a PnP aware additional library that can be linked to. For some
- * late 1990's hardware, the PnP awareness is required to correctly identify the
- * IRQ associated with the device, such as on older Toshiba laptops that emulate
- * a serial port using the IR infared device on the back. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8250/8250.h>
-#include <hw/dos/doswin.h>
-
-const char *type_8250_strs[TYPE_8250_MAX] = {
- "8250",
- "16450",
- "16550",
- "16550A",
- "16750"
-};
-
-const uint16_t standard_8250_ports[STANDARD_8250_PORT_COUNT] = {0x3F8,0x2F8,0x3E8,0x2E8};
-uint16_t base_8250_port[MAX_8250_PORTS];
-struct info_8250 info_8250_port[MAX_8250_PORTS];
-unsigned int base_8250_ports;
-unsigned char bios_8250_ports;
-char use_8250_int=0;
-char inited_8250=0;
-
-int already_got_8250_port(uint16_t port) {
- unsigned int i;
-
- for (i=0;i < (unsigned int)base_8250_ports;i++) {
- if (base_8250_port[i] == port)
- return 1;
- }
-
- return 0;
-}
-
-uint16_t get_8250_bios_port(unsigned int index) {
- if (index >= (unsigned int)bios_8250_ports)
- return 0;
-
-#if TARGET_MSDOS == 32
- return *((uint16_t*)(0x400 + (index*2)));
-#else
- return *((uint16_t far*)MK_FP(0x40,index*2));
-#endif
-}
-
-int init_8250() {
- if (!inited_8250) {
- uint16_t eqw;
-
- memset(base_8250_port,0,sizeof(base_8250_port));
- base_8250_ports = 0;
- bios_8250_ports = 0;
- inited_8250 = 1;
-
- /* read the BIOS equipment word[11-9]. how many serial ports? */
-#if TARGET_MSDOS == 32
- eqw = *((uint16_t*)(0x400 + 0x10));
-#else
- eqw = *((uint16_t far*)MK_FP(0x40,0x10));
-#endif
- bios_8250_ports = (eqw >> 9) & 7;
- if (bios_8250_ports > 4) bios_8250_ports = 4;
- }
-
- return 1;
-}
-
-/* ISA PnP version. The program calling us does the work of scanning BIOS device nodes and ISA PnP device isolation,
- * then presents us with the IRQ and port number. We take the caller's word for it. If for any reason the caller
- * did not find the IRQ, it should pass irq == -1 */
-int add_pnp_8250(uint16_t port,int irq) {
- unsigned char ier,dlab1,dlab2,c,fcr;
- struct info_8250 *inf;
-
- if (already_got_8250_port(port))
- return 0;
- if (base_8250_full())
- return 0;
-
- inf = &info_8250_port[base_8250_ports];
- inf->type = TYPE_8250_IS_8250;
- inf->port = port;
- inf->irq = irq;
- if (windows_mode == WINDOWS_NONE || windows_mode == WINDOWS_REAL) {
- /* in real-mode DOS we can play with the UART to our heart's content. so we play with the
- * DLAB select and interrupt enable registers to detect the UART in a manner non-destructive
- * to the hardware state. */
-
- /* switch registers 0+1 back to RX/TX and interrupt enable, and then test the Interrupt Enable register */
- _cli();
- outp(port+3,inp(port+3) & 0x7F);
- if (inp(port+3) == 0xFF) { _sti(); return 0; }
- ier = inp(port+1);
- outp(port+1,0);
- if (inp(port+1) == 0xFF) { _sti(); return 0; }
- outp(port+1,ier);
- if ((inp(port+1) & 0xF) != (ier & 0xF)) { _sti(); return 0; }
- /* then switch 0+1 to DLAB (divisor registers) and see if values differ from what we read the first time */
- outp(port+3,inp(port+3) | 0x80);
- dlab1 = inp(port+0);
- dlab2 = inp(port+1);
- outp(port+0,ier ^ 0xAA);
- outp(port+1,ier ^ 0x55);
- if (inp(port+1) == ier || inp(port+0) != (ier ^ 0xAA) || inp(port+1) != (ier ^ 0x55)) {
- outp(port+0,dlab1);
- outp(port+1,dlab2);
- outp(port+3,inp(port+3) & 0x7F);
- _sti();
- return 0;
- }
- outp(port+0,dlab1);
- outp(port+1,dlab2);
- outp(port+3,inp(port+3) & 0x7F);
-
- /* now figure out what type */
- fcr = inp(port+2);
- outp(port+2,0xE7); /* write FCR */
- c = inp(port+2); /* read IIR */
- if (c & 0x40) { /* if FIFO */
- if (c & 0x80) {
- if (c & 0x20) inf->type = TYPE_8250_IS_16750;
- else inf->type = TYPE_8250_IS_16550A;
- }
- else {
- inf->type = TYPE_8250_IS_16550;
- }
- }
- else {
- unsigned char oscratch = inp(port+7);
-
- /* no FIFO. try the scratch register */
- outp(port+7,0x55);
- if (inp(port+7) == 0x55) {
- outp(port+7,0xAA);
- if (inp(port+7) == 0xAA) {
- outp(port+7,0x00);
- if (inp(port+7) == 0x00) {
- inf->type = TYPE_8250_IS_16450;
- }
- }
- }
-
- outp(port+7,oscratch);
- }
-
- outp(port+2,fcr);
- _sti();
- }
- else {
- unsigned int i;
-
- /* if we were to actually do our self-test in a VM, Windows would mistakingly assume we
- * were trying to use it and would allocate the port. we're just enumerating at this point.
- * play it safe and assume it works if the port is listed as one of the BIOS ports.
- * we also don't use interrupts. */
- for (i=0;i < bios_8250_ports && port != get_8250_bios_port(i);) i++;
- if (i >= bios_8250_ports) return 0;
- }
-
- base_8250_port[base_8250_ports++] = port;
- return 1;
-}
-
-/* this is used to probe for ports in standard locations, when we really don't know if it's there */
-int probe_8250(uint16_t port) {
- unsigned char ier,dlab1,dlab2,c,fcr;
- struct info_8250 *inf;
-
- if (already_got_8250_port(port))
- return 0;
- if (base_8250_full())
- return 0;
-
- inf = &info_8250_port[base_8250_ports];
- inf->type = TYPE_8250_IS_8250;
- inf->port = port;
- inf->irq = -1;
- if (windows_mode == WINDOWS_NONE || windows_mode == WINDOWS_REAL) {
- /* in real-mode DOS we can play with the UART to our heart's content. so we play with the
- * DLAB select and interrupt enable registers to detect the UART in a manner non-destructive
- * to the hardware state. */
-
- /* there's no way to autodetect the COM port's IRQ, we have to guess */
- if (port == 0x3F8 || port == 0x3E8)
- inf->irq = 4;
- else if (port == 0x2F8 || port == 0x2E8)
- inf->irq = 3;
-
- /* switch registers 0+1 back to RX/TX and interrupt enable, and then test the Interrupt Enable register */
- _cli();
- outp(port+3,inp(port+3) & 0x7F);
- if (inp(port+3) == 0xFF) { _sti(); return 0; }
- ier = inp(port+1);
- outp(port+1,0);
- if (inp(port+1) == 0xFF) { _sti(); return 0; }
- outp(port+1,ier);
- if ((inp(port+1) & 0xF) != (ier & 0xF)) { _sti(); return 0; }
- /* then switch 0+1 to DLAB (divisor registers) and see if values differ from what we read the first time */
- outp(port+3,inp(port+3) | 0x80);
- dlab1 = inp(port+0);
- dlab2 = inp(port+1);
- outp(port+0,ier ^ 0xAA);
- outp(port+1,ier ^ 0x55);
- if (inp(port+1) == ier || inp(port+0) != (ier ^ 0xAA) || inp(port+1) != (ier ^ 0x55)) {
- outp(port+0,dlab1);
- outp(port+1,dlab2);
- outp(port+3,inp(port+3) & 0x7F);
- _sti();
- return 0;
- }
- outp(port+0,dlab1);
- outp(port+1,dlab2);
- outp(port+3,inp(port+3) & 0x7F);
-
- /* now figure out what type */
- fcr = inp(port+2);
- outp(port+2,0xE7); /* write FCR */
- c = inp(port+2); /* read IIR */
- if (c & 0x40) { /* if FIFO */
- if (c & 0x80) {
- if (c & 0x20) inf->type = TYPE_8250_IS_16750;
- else inf->type = TYPE_8250_IS_16550A;
- }
- else {
- inf->type = TYPE_8250_IS_16550;
- }
- }
- else {
- unsigned char oscratch = inp(port+7);
-
- /* no FIFO. try the scratch register */
- outp(port+7,0x55);
- if (inp(port+7) == 0x55) {
- outp(port+7,0xAA);
- if (inp(port+7) == 0xAA) {
- outp(port+7,0x00);
- if (inp(port+7) == 0x00) {
- inf->type = TYPE_8250_IS_16450;
- }
- }
- }
-
- outp(port+7,oscratch);
- }
-
- outp(port+2,fcr);
- _sti();
- }
- else {
- unsigned int i;
-
- /* if we were to actually do our self-test in a VM, Windows would mistakingly assume we
- * were trying to use it and would allocate the port. we're just enumerating at this point.
- * play it safe and assume it works if the port is listed as one of the BIOS ports.
- * we also don't use interrupts. */
- for (i=0;i < bios_8250_ports && port != get_8250_bios_port(i);) i++;
- if (i >= bios_8250_ports) return 0;
- }
-
- base_8250_port[base_8250_ports++] = port;
- return 1;
-}
-
-void uart_8250_enable_interrupt(struct info_8250 *uart,uint8_t mask) {
- uint8_t c;
-
- outp(uart->port+PORT_8250_LCR,inp(uart->port+PORT_8250_LCR) & 0x7F);
-
- /* the mask is written as-is to the IER. we assume the DLAB latch == 0 */
- outp(uart->port+PORT_8250_IER,mask);
-
- /* on PC platforms, we also have to diddle with the AUX 2 line (FIXME: why?) */
- c = inp(uart->port+PORT_8250_MCR);
- if (mask != 0) c |= 8; /* AUX 2 output line */
- else c &= ~8;
- outp(uart->port+PORT_8250_MCR,c);
-}
-
-void uart_8250_disable_FIFO(struct info_8250 *uart) {
- if (uart->type <= TYPE_8250_IS_16550) return;
- outp(uart->port+PORT_8250_FCR,7); /* enable and flush */
- outp(uart->port+PORT_8250_FCR,0); /* then disable */
-}
-
-void uart_8250_set_FIFO(struct info_8250 *uart,uint8_t flags) {
- if (uart->type <= TYPE_8250_IS_16550) return;
- outp(uart->port+PORT_8250_FCR,flags | 7);
- outp(uart->port+PORT_8250_FCR,flags);
-}
-
-void uart_8250_set_baudrate(struct info_8250 *uart,uint16_t dlab) {
- uint8_t c;
-
- /* enable access to the divisor */
- c = inp(uart->port+PORT_8250_LCR);
- outp(uart->port+PORT_8250_LCR,c | 0x80);
- /* set rate */
- outp(uart->port+PORT_8250_DIV_LO,dlab);
- outp(uart->port+PORT_8250_DIV_HI,dlab >> 8);
- /* disable access to the divisor */
- outp(uart->port+PORT_8250_LCR,c & 0x7F);
-}
-
-uint16_t uart_8250_baud_to_divisor(struct info_8250 *uart,unsigned long rate) {
- if (rate == 0) return 0;
- return (uint16_t)(115200UL / rate);
-}
-
-unsigned long uart_8250_divisor_to_baud(struct info_8250 *uart,uint16_t rate) {
- if (rate == 0) return 1;
- return (unsigned long)(115200UL / (unsigned long)rate);
-}
-
-void uart_8250_get_config(struct info_8250 *uart,unsigned long *baud,unsigned char *bits,unsigned char *stop_bits,unsigned char *parity) {
- uint16_t dlab;
- uint8_t c = inp(uart->port+PORT_8250_LCR);
- *bits = (c & 3) + 5;
- *stop_bits = (c & 4) ? 2 : 1;
- *parity = (c >> 3) & 7;
-
- /* then switch on DLAB to get divisor */
- outp(uart->port+PORT_8250_LCR,c | 0x80);
-
- /* read back divisor */
- dlab = inp(uart->port+PORT_8250_DIV_LO);
- dlab |= (uint16_t)inp(uart->port+PORT_8250_DIV_HI) << 8;
-
- /* then switch off DLAB */
- outp(uart->port+PORT_8250_LCR,c & 0x7F);
-
- *baud = uart_8250_divisor_to_baud(uart,dlab);
-}
-
-const char *type_8250_parity(unsigned char parity) {
- if (parity & 1) {
- switch (parity >> 1) {
- case 0: return "odd parity";
- case 1: return "even parity";
- case 2: return "odd sticky parity";
- case 3: return "even sticky parity";
- };
- }
-
- return "no parity";
-}
-
-void uart_toggle_xmit_ien(struct info_8250 *uart) {
- /* apparently if the XMIT buffer is empty, you can trigger
- * another TX empty interrupt event by toggling bit 2 in
- * the IER register. */
- unsigned char c = inp(uart->port+PORT_8250_IER);
- outp(uart->port+PORT_8250_IER,c & ~(1 << 2));
- outp(uart->port+PORT_8250_IER,c);
-}
-
+++ /dev/null
-/* 8250.h
- *
- * 8250/16450/16550/16750 serial port UART library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-/* WARNING: As usual for performance reasons this library generally does not
- * enable/disable interrupts (cli/sti). To avoid contention with
- * interrupt handlers the calling program should do that. */
-
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#define MAX_8250_PORTS 8
-
-#define STANDARD_8250_PORT_COUNT 4
-
-#define PORT_8250_IO 0
-#define PORT_8250_IER 1
-#define PORT_8250_IIR 2
-#define PORT_8250_FCR 2
-#define PORT_8250_LCR 3
-#define PORT_8250_MCR 4
-#define PORT_8250_LSR 5
-#define PORT_8250_MSR 6
-#define PORT_8250_SCRATCH 7
-#define PORT_8250_DIV_LO 0
-#define PORT_8250_DIV_HI 1
-
-/* Line control register bits */
-#define UART_8250_LCR_8BIT (3 << 0)
-#define UART_8250_LCR_PARITY (1 << 3)
-#define UART_8250_LCR_PARITY_EVEN (1 << 4)
-/* set this bit to make register offsets 0&1 the divisor latch */
-#define UART_8250_LCR_DLAB (1 << 7)
-
-/* FIFO control register bits */
-#define UART_8250_FCR_FIFO_ENABLE (1 << 0)
-#define UART_8250_FCR_RCV_FIFO_RESET (1 << 1)
-#define UART_8250_FCR_XMIT_FIFO_RESET (1 << 2)
-#define UART_8250_FCR_DMA_MODE_SELECT (1 << 3)
-
-/* 16750 only */
-#define UART_8250_FCR_64BYTE_FIFO (1 << 5)
-
-#define UART_8250_FCR_RCV_THRESHHOLD_MASK (3 << 6)
-#define UART_8250_FCR_RCV_THRESHHOLD_SHIFT (6)
-/* known threshholds (non-64 byte mode)
- 0 = 1 byte
- 1 = 4 bytes
- 2 = 8 bytes
- 3 = 14 bytes
- known threshholds (64-byte mode)
- 0 = 1 byte
- 1 = 16 bytes
- 2 = 32 bytes
- 3 = 56 bytes */
-
-enum {
- TYPE_8250_IS_8250=0,
- TYPE_8250_IS_16450,
- TYPE_8250_IS_16550,
- TYPE_8250_IS_16550A,
- TYPE_8250_IS_16750,
- TYPE_8250_MAX
-};
-
-struct info_8250 {
- uint8_t type;
- uint16_t port;
- int8_t irq;
-};
-
-extern const char* type_8250_strs[TYPE_8250_MAX];
-extern const uint16_t standard_8250_ports[STANDARD_8250_PORT_COUNT];
-extern uint16_t base_8250_port[MAX_8250_PORTS];
-extern struct info_8250 info_8250_port[MAX_8250_PORTS];
-extern unsigned int base_8250_ports;
-extern unsigned char bios_8250_ports;
-extern char use_8250_int;
-extern char inited_8250;
-
-#define type_8250_to_str(x) type_8250_strs[x]
-#define base_8250_full() (base_8250_ports >= MAX_8250_PORTS)
-
-static inline void uart_8250_set_MCR(struct info_8250 *uart,uint8_t mcr) {
- outp(uart->port+PORT_8250_MCR,mcr);
-}
-
-static inline uint8_t uart_8250_read_MCR(struct info_8250 *uart) {
- return inp(uart->port+PORT_8250_MCR);
-}
-
-static inline uint8_t uart_8250_read_MSR(struct info_8250 *uart) {
- return inp(uart->port+PORT_8250_MSR);
-}
-
-static inline void uart_8250_set_line_control(struct info_8250 *uart,uint8_t lcr) {
- outp(uart->port+PORT_8250_LCR,lcr);
-}
-
-/* NTS: This function is only slightly affected by the FIFO functions, FCR bit 3 (so called "DMA" mode).
- * When "mode 0" FCR bit 3 == 0, this will signal (1) when any amount of data is waiting in the FIFO.
- * When "mode 1" FCR bit 3 == 1, this will signal (1) when the number of bytes in the FIFO exceeds a threshhold, or a timeout has occured */
-static inline int uart_8250_can_read(struct info_8250 *uart) {
- return (inp(uart->port+PORT_8250_LSR) & (1 << 0)) ? 1 : 0; /*if LSR says receive buffer is ready, then yes we can read */
-}
-
-/* WARNING: The caller is expected to call uart_8250_can_read() first before calling this function */
-static inline uint8_t uart_8250_read(struct info_8250 *uart) {
- return inp(uart->port+PORT_8250_IO);
-}
-
-/* NTS: This function is only slightly affected by FIFO FCR bit 3 (so called "DMA" mode).
- * When "mode 0" FCR bit 3 == 0, this will signal (1) when the FIFO is empty or (on non-FIFO UARTs) the "holding register" is ready to accept another byte.
- * That does mean though that following the traditional transmission model you will only maintain at most 1 byte in the XMIT FIFO, which is kind of wasteful.
- * When "mode 1" FCR bit 3 == 1, this will signal (1) when there is room in the FIFO to write another data byte. This function returns 0 when the XMIT FIFO is full */
-static inline int uart_8250_can_write(struct info_8250 *uart) {
- return (inp(uart->port+PORT_8250_LSR) & (1 << 5)) ? 1 : 0; /*if LSR says transmit buffer is empty, then yes we can write */
-}
-
-/* WARNING: The caller is expected to call uart_8250_can_write() first before calling this function */
-static inline void uart_8250_write(struct info_8250 *uart,uint8_t c) {
- outp(uart->port+PORT_8250_IO,c);
-}
-
-int init_8250();
-int probe_8250(uint16_t port);
-int add_pnp_8250(uint16_t port,int irq);
-int already_got_8250_port(uint16_t port);
-uint16_t get_8250_bios_port(unsigned int index);
-void uart_toggle_xmit_ien(struct info_8250 *uart);
-const char *type_8250_parity(unsigned char parity);
-void uart_8250_disable_FIFO(struct info_8250 *uart);
-void uart_8250_set_FIFO(struct info_8250 *uart,uint8_t flags);
-void uart_8250_set_baudrate(struct info_8250 *uart,uint16_t dlab);
-void uart_8250_enable_interrupt(struct info_8250 *uart,uint8_t mask);
-uint16_t uart_8250_baud_to_divisor(struct info_8250 *uart,unsigned long rate);
-unsigned long uart_8250_divisor_to_baud(struct info_8250 *uart,uint16_t rate);
-void uart_8250_get_config(struct info_8250 *uart,unsigned long *baud,unsigned char *bits,unsigned char *stop_bits,unsigned char *parity);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8250/8250.h>
-#include <hw/isapnp/isapnp.h>
-
-int is_rs232_or_compat_pnp_device(struct isa_pnp_device_node far *devn) {
- char id[9];
-
- if (devn->type_code[0] == 7 && devn->type_code[1] == 0)
- return 1;
-
- /* and then there are known devices that act like RS-232 but do not list themselves as RS-232 */
- isa_pnp_product_id_to_str(id,devn->product_id);
-
- /* Toshiba Satellite Pro 465CDX: The IR port is a 0x07,0x80 ("other" communications device)
- * when in fact it looks and acts like a UART on IO port 0x3E8 IRQ 9. Identifies itself
- * as "TOS7009" (TODO: The PnP BIOS also announces something at 0x3E0, is that related to this?).
- * UART notes: For the most part you can treat it like a serial port BUT there is one catch
- * that is related to IR transmission: both computers cannot send bytes at the
- * same time. If you do, the light interferes and both computers end up receiving
- * gibberish. In some cases, it can throw off the bit clock and make the remaining
- * valid data also gibberish. The only way to resolve the issue it seems, is to
- * temporarily stop transmitting and give each IR port a chance to reset themselves. */
- if (devn->type_code[0] == 7 && devn->type_code[1] == 0x80 && !memcmp(id,"TOS7009",7))
- return 1;
-
- return 0;
-}
-
+++ /dev/null
-
-#include <hw/isapnp/isapnp.h>
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-#include <conio.h>
-
-int is_rs232_or_compat_pnp_device(struct isa_pnp_device_node far *devn);
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_8250_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = 8250.c
-OBJS = $(SUBDIR)$(HPS)8250.obj
-OBJSPNP = $(SUBDIR)$(HPS)8250pnp.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-TESTPNP_EXE = $(SUBDIR)$(HPS)testpnp.exe
-
-$(HW_8250_LIB): $(OBJS)
- wlib -q -b -c $(HW_8250_LIB) -+$(SUBDIR)$(HPS)8250.obj
-
-$(HW_8250PNP_LIB): $(OBJSPNP)
- wlib -q -b -c $(HW_8250PNP_LIB) -+$(SUBDIR)$(HPS)8250pnp.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_8250_LIB) $(HW_8250PNP_LIB) .symbolic
-
-exe: $(TEST_EXE) $(TESTPNP_EXE) .symbolic
-
-$(TEST_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENCIES) $(HW_8250_LIB) $(HW_8250_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp1.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_8250_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp1.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(TESTPNP_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENCIES) $(HW_8250_LIB) $(HW_8250_LIB_DEPENDENCIES) $(HW_8250PNP_LIB) $(HW_8250PNP_LIB_DEPENDENCIES) $(HW_8250PBP_LIB_DEPENDENCIES) $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(SUBDIR)$(HPS)testpnp.obj
- %write tmp2.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)testpnp.obj $(HW_8250_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_ISAPNP_LIB_WLINK_LIBRARIES) $(HW_8250PNP_LIB_WLINK_LIBRARIES) name $(TESTPNP_EXE)
- @wlink @tmp2.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_8250_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* test.c
- *
- * 8250/16450/16550/16750 serial port UART test program.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-/* TODO: - Can you transform the IRQ buffering code into some kind of C object that the program can allocate as needed (including what size buffer) so that
- * such IRQ enabled code is easily usable in other programming projects?
- * - See how well this works on that Saber laptop where the trackball is a serial device on COM2.
- * - Add code to show you the state of the line and modem status registers, and twiddle them too.
- * - Does this program actually work on... say... the IBM PC/XT you have sitting in the corner?
- * - How about that ancient 286 laptop you have? The 386 one? The Compaq elite? */
-
-/* Warnings regarding this code: The order of operations involved in enabling interrupts is
- * very important! The 8250/16450/16550A/etc UARTs in PC hardware are just so goddamn finicky
- * about getting interrupts to fire like they're supposed to that if you change the order of
- * I/O port operations (even if to a more intuitive order) you will probably break UART
- * interrupt support on many configurations.
- *
- * I must explain why the code enables interrupts the way it does in the specific order:
- * 1. At the very start, the IRQ is unmasked ahead of time (prior to main loop)
- * 2. The user hits '6' to enable interrupts
- * 3. The code sends a specific EOI to the programmable interrupt controller. If we don't do this,
- * the Programmable Interrupt Controller may fail to send interrupts in the event the UART
- * was already holding the IRQ line high and interrupts will not happen
- * 4. We set all lower 4 bits of the Interrupt Enable register of the UART so that we're notified
- * when (1) data is available (2) the trasmitter buffer is empty (and waiting for more)
- * (3 & 4) any change in the line or modem status registers
- * 5. Experience tells me that if for any reason the UART had events pending, but was interrupted
- * for any reason, it might not fire any futher interrupts until someone reads the IIR and
- * services each register appropriately. So the UART is never serviced because the IRQ is never
- * fired, and the IRQ is never fired because the UART is never serviced. Forcibly read and discard
- * all "events" from the UART to clear out that queue and get the UART firing off interrupts once
- * again
- *
- * Again: if you change the order of operations there, you will produce code that for one reason or
- * another fail to enable UART interrupts on some computers, and will happen to work on other
- * computers. Follow the above order strictly, and interrupts will fire like they are supposed to. */
-
-/* Test scenarios.
- *
- * DB-9 port = Device is a UART with an externally visible 9-pin D-shell connector
- * DB-25 port= Device is a UART with an externally visible 25-pin D-shell connector
- * Int modem = Device is an internal modem emulating a UART
- * IRDA = Device is an infared port pretending to be a UART
- * Emulated = If platform involves an emulator, the UART is emulated by the software
- * If the platform is actual hardware, then the BIOS or host OS traps I/O to emulate a UART
- *
- * Scenario I/O works Bi-dir Up to UART loop Type Notes
- * Poll Interrupt ectional baud Poll Interrupt
- * --------------------------------------------------------------------------------------------------
- * Microsoft Virtual PC 2007
- * - real & protected mode Y Y Y 115200 N N Emulated Everything works, except loopback is improperly
- * emulated. What is actually received is the last byte
- * received, not the one we sent out.
- * * Actual transfer speed is limited by the mechanism used to emulate. If using NT pipes like \\.\pipe\dostest the fake UART
- * will stall until that pipe can be written by Virtual PC.
- * * Works with both traditional and ISA Plug & Play versions of the test program.
- * * Prior versions of these comments complained about the Real-mode copy running erratically and crashing.
- * It was discovered the CPU detection code was calling a far routine as if near and the incorrect stack
- * return caused the erratic behavior (as well as solid hangs on other configurations). Since the fix was
- * applied VirtualBox now runs our code flawlessly.
- *
- * Oracle VirtualBox 4.0.4
- * - real & protected ver Y Y Y 115200 Y Y Emulated Everything works fine. VirtualBox's UART emulation
- * is very tolerant of errors, perhaps even deceptively
- * tolerant compared to actual hardware.
- * * Works with traditional program. VirtualBox does not emulate ISA Plug & Play.
- *
- * Toshiba Satellite Pro 465CDX laptop
- * - With COM1 (0x3F8) Y Y Y 115200 Y ? DB-9 port Works fine.
- * - With COM2 (0x2F8) Y Y ? ? Y ? Int modem Communication works at any baud, Hayes compatible
- * - With COM3 (0x3E8) Y Y N 115200 Y ? IRDA Toshiba's BIOS puts this on IRQ 9. The port and IRQ
- * will only be detected properly by the ISA PnP version.
- * The traditional version will mis-detect the port IRQ
- * as 4.
- *
- * Bidirectional communications are impossible over IRDA.
- * If both ends transmit one byte simultaneously the
- * bits collide and each end receives gibberish.
- * Perfect transmission is only possible if each end
- * takes turns transmitting and receiving.
- * * DOS extender problem (dos32a): When we enable and hook the UART IRQ the DOS extender
- * crashes back to DOS with "Invalid TSS" exception (INT 0x0A). This makes the 32-bit
- * protected mode version unusable on Toshiba hardware unless polling is involved.
- * For interrupt-enabled testing, you must use the real-mode version.
- *
- * Toshiba Libretto laptop
- * - With COM1 (0x3F8) Y Y Y 115200 Y ? DB-9 port Actual communication not verified. The port is only
- * available through the docking station, which I do not
- * have.
- * - With COM2 (0x2F8) Y Y N 115200 Y ? IRDA Bidirectional communications are not possible. Each end
- * must take turns transmitting and receiving, or else
- * data becomes corrupt in transmission.
- * * DOS extender problem (dos32a): When we enable and hook the UART IRQ the DOS extender
- * crashes back to DOS with "Invalid TSS" exception (INT 0x0A). This makes the 32-bit
- * protected mode version unusable on Toshiba hardware unless polling is involved.
- * For interrupt-enabled testing, you must use the real-mode version.
- *
- * Compaq Elite laptop
- * - With COM1 (0x3F8) Y Y Y 115200 Y ? DB-9 port
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h>
-#include <hw/8259/8259.h>
-#include <hw/8250/8250.h>
-#include <hw/dos/doswin.h>
-
-#if defined(ISAPNP)
-#include <hw/8250/8250pnp.h>
-#include <hw/isapnp/isapnp.h>
-#endif
-
-/* global variable: the uart object */
-static struct info_8250 *uart = NULL;
-
-/* IRQ transfer buffers. Used by interrupt handler to store incoming data. Non-interrupt code should disable interrupts before accessing */
-#define IRQ_BUFFER_SIZE 512
-
-static unsigned char irq_buffer[IRQ_BUFFER_SIZE];
-static unsigned int irq_buffer_i=0,irq_buffer_o=0;
-
-static unsigned char irq_bufferout[IRQ_BUFFER_SIZE];
-static unsigned int irq_bufferout_i=0,irq_bufferout_o=0;
-
-static void irq_buffer_reset() {
- _cli();
- irq_buffer_i = irq_buffer_o = 0;
- irq_bufferout_i = irq_bufferout_o = 0;
- _sti();
-}
-
-/* take any IRQ buffered output and send it.
- * must be called with interrupts disabled.
- * may be called from the IRQ handler. */
-static void irq_uart_xmit_bufferout(struct info_8250 *uart) {
- unsigned char c;
-
- if (irq_bufferout_o != irq_bufferout_i) {
- /* then send it */
- while (uart_8250_can_write(uart) && irq_bufferout_o != irq_bufferout_i) {
- c = irq_bufferout[irq_bufferout_o++];
- if (irq_bufferout_o >= IRQ_BUFFER_SIZE) irq_bufferout_o = 0;
- outp(uart->port+PORT_8250_IO,c);
- }
- }
-}
-
-static void irq_uart_recv_buffer(struct info_8250 *uart) {
- unsigned char c;
-
- while (uart_8250_can_read(uart)) {
- c = inp(uart->port+PORT_8250_IO);
- if ((irq_buffer_i+1)%IRQ_BUFFER_SIZE != irq_buffer_o) {
- irq_buffer[irq_buffer_i++] = c;
- if (irq_buffer_i >= IRQ_BUFFER_SIZE) irq_buffer_i = 0;
- }
- }
-}
-
-static int irq_bufferout_count() {
- int x = irq_bufferout_i - irq_bufferout_o;
- if (x < 0) x += IRQ_BUFFER_SIZE;
- return x;
-}
-
-/* NOTE: You're supposed to call this function with interrupts disabled,
- * or from within an interrupt handler in response to the UART's IRQ signal. */
-static void irq_uart_handle_iir(struct info_8250 *uart) {
- unsigned char reason,c,patience = 8;
-
-#if TARGET_MSDOS == 32
- (*((unsigned short*)0xB8010))++;
-#else
- (*((unsigned short far*)MK_FP(0xB800,0x0010)))++;
-#endif
-
- /* why the interrupt? */
- /* NOTE: we loop a maximum of 8 times in case the UART we're talking to happens
- * to be some cheap knockoff chipset that never clears the IIR register
- * when all events are read */
- /* if there was actually an interrupt, then handle it. loop until all interrupt conditions are depleted */
- while (((reason=inp(uart->port+PORT_8250_IIR)&7)&1) == 0) {
- reason >>= 1;
-#if TARGET_MSDOS == 32
- (*((unsigned short*)0xB8000))++;
-#else
- (*((unsigned short far*)MK_FP(0xB800,0x0000)))++;
-#endif
-
- if (reason == 3) { /* line status */
-#if TARGET_MSDOS == 32
- (*((unsigned short*)0xB8008))++;
-#else
- (*((unsigned short far*)MK_FP(0xB800,0x0008)))++;
-#endif
-
- c = inp(uart->port+PORT_8250_LSR);
- /* do what you will with this info */
- }
- else if (reason == 0) { /* modem status */
-#if TARGET_MSDOS == 32
- (*((unsigned short*)0xB8006))++;
-#else
- (*((unsigned short far*)MK_FP(0xB800,0x0006)))++;
-#endif
-
- c = inp(uart->port+PORT_8250_MSR);
- /* do what you will with this info */
- }
- else if (reason == 2) { /* data avail */
-#if TARGET_MSDOS == 32
- (*((unsigned short*)0xB8002))++;
-#else
- (*((unsigned short far*)MK_FP(0xB800,0x0002)))++;
-#endif
-
- irq_uart_recv_buffer(uart);
- }
- else if (reason == 1) { /* transmit empty */
-#if TARGET_MSDOS == 32
- (*((unsigned short*)0xB8004))++;
-#else
- (*((unsigned short far*)MK_FP(0xB800,0x0004)))++;
-#endif
-
- irq_uart_xmit_bufferout(uart);
- }
-
- if (--patience == 0) {
-#if TARGET_MSDOS == 32
- (*((unsigned short*)0xB800A))++;
-#else
- (*((unsigned short far*)MK_FP(0xB800,0x000A)))++;
-#endif
- break;
- }
- }
-}
-
-static void (interrupt *old_irq)() = NULL;
-static void interrupt uart_irq() {
- /* clear interrupts, just in case. NTS: the nature of interrupt handlers
- * on the x86 platform (IF in EFLAGS) ensures interrupts will be reenabled on exit */
- _cli();
- irq_uart_handle_iir(uart);
-
- /* ack PIC */
- if (uart->irq >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
-}
-
-static void change_config(struct info_8250 *uart) {
- int done=0,c;
- uint8_t by,t2;
-
- while (!done) {
- {
- unsigned long baud=0;
- unsigned char bits=0,stop_bits=0,parity=0;
- uart_8250_get_config(uart,&baud,&bits,&stop_bits,&parity);
- printf("State: %lu baud %u-bit %u stop bits %s\n",baud,bits,stop_bits,type_8250_parity(parity));
- printf("1/!. Baud rate inc/dec 2/@. Bits inc/dec 3. Stop bits 4. Parity\n");
- printf("? "); fflush(stdout);
- }
-
- c = getch();
- printf("\n");
- if (c == 27) {
- done=1;
- break;
- }
- else if (c == '1' || c == '!') {
- unsigned long rate = 9600;
- printf("new rate? "); fflush(stdout);
- scanf("%lu",&rate);
- uart_8250_set_baudrate(uart,uart_8250_baud_to_divisor(uart,rate));
- }
- else if (c == '2' || c == '@') {
- by = inp(uart->port+PORT_8250_LCR);
- if (c == '2') by = (by & (~3)) | (((by & 3) + 3) & 3);
- else by = (by & (~3)) | (((by & 3) + 1) & 3);
- outp(uart->port+PORT_8250_LCR,by);
- }
- else if (c == '3' || c == '#') {
- by = inp(uart->port+PORT_8250_LCR);
- by ^= 4;
- outp(uart->port+PORT_8250_LCR,by);
- }
- else if (c == '4' || c == '$') {
- by = inp(uart->port+PORT_8250_LCR);
- t2 = (by >> 3) & 7;
- if (t2 == 0) t2 = 1;
- else if (t2 == 1) t2 = 3;
- else if (t2 >= 3) t2 += 2;
- if (t2 >= 8) t2 = 0;
- by &= ~(7 << 3);
- by |= t2 << 3;
- outp(uart->port+PORT_8250_LCR,by);
- }
- }
-}
-
-static void config_fifo(struct info_8250 *uart) {
- uint8_t fcr=0;
- int done=0,c;
-
- if (uart->type <= TYPE_8250_IS_16550) {
- printf("Your UART (as far as I know) does not have a FIFO\n");
- return;
- }
-
- while (!done) {
- printf("FCR: Enable=%u mode=%u 64byte=%u recv_trigger_level=%u\n",
- (fcr & 1) ? 1 : 0,
- (fcr & 8) ? 1 : 0,
- (fcr & 32) ? 1 : 0,
- fcr >> 6);
- printf("1. Flush & enable/disable 2. Mode 3. 64byte 4. Level\n");
- printf("? "); fflush(stdout);
-
- c = getch();
- printf("\n");
- if (c == 27) {
- done=1;
- break;
- }
- else if (c == '1') {
- fcr ^= 1;
- uart_8250_set_FIFO(uart,fcr);
- }
- else if (c == '2') {
- fcr ^= 1 << 3;
- uart_8250_set_FIFO(uart,fcr);
- }
- else if (c == '3') {
- fcr ^= 1 << 5;
- uart_8250_set_FIFO(uart,fcr);
- }
- else if (c == '4') {
- fcr += 1 << 6;
- uart_8250_set_FIFO(uart,fcr);
- }
- }
-}
-
-void irq_bufferout_write(unsigned char c) {
- _cli();
- while (((irq_bufferout_i+1)%IRQ_BUFFER_SIZE) == irq_bufferout_o) {
- /* try to force transmit interrupt that gets the character out the door */
- uart_toggle_xmit_ien(uart);
- _sti();
- /* IODELAY during interrupt enable. Give the UART's interrupt a chance to interrupt the CPU */
- inp(uart->port+PORT_8250_MCR); /* iodelay */
- inp(uart->port+PORT_8250_MCR); /* iodelay */
- inp(uart->port+PORT_8250_MCR); /* iodelay */
- inp(uart->port+PORT_8250_MCR); /* iodelay */
- _cli();
- }
-
- /* put it in the buffer */
- irq_bufferout[irq_bufferout_i++] = c;
- if (irq_bufferout_i >= IRQ_BUFFER_SIZE) irq_bufferout_i = 0;
- if (irq_bufferout_count() == 1) uart_toggle_xmit_ien(uart);
- _sti();
-}
-
-static void show_console(struct info_8250 *uart) {
- static const char *msg = "Testing testing 1... 2... 3... 01234567890123456789.\r\n"
- "The big dog jumped the shark or something like that.\r\n";
- unsigned char pc=0,seqmatch=0,xmitseq=0,xmitbyte=0;
- const size_t msg_len = strlen(msg);
- unsigned int patience;
- char stuck_xmit=0;
- int c;
-
- printf("Incoming data will be printed out, and data you type will xmit (port=%X)\n",uart->port);
- printf("Tap ESC twice to exit. '~' = type out a predefined message.\n");
- printf("SHIFT + ~ to rapidly transmit the message.\n");
- printf("Type CTRL+A to initiate sequential byte test.\n");
-
- if (use_8250_int) irq_buffer_reset();
-
- while (1) {
- if (kbhit()) {
- c = getch();
- if (c == 27) {
- c = getch();
- if (c == 27) break;
- }
- if (c == '`') {
- stuck_xmit = !stuck_xmit;
- }
- else if (c == 1) { /* CTRL+S */
- xmitseq = !xmitseq;
- }
- else if (c == '~') {
- const char *p = msg;
- while (*p != 0) {
- c = *p++;
- if (use_8250_int) {
- irq_bufferout_write(c);
- }
- else {
- while (!uart_8250_can_write(uart));
- uart_8250_write(uart,(uint8_t)c);
- }
- }
- }
- else if (c == 13) {
- if (use_8250_int) {
- irq_bufferout_write(13);
- irq_bufferout_write(10);
- }
- else {
- while (!uart_8250_can_write(uart));
- uart_8250_write(uart,13);
- while (!uart_8250_can_write(uart));
- uart_8250_write(uart,10);
- }
- printf("\n");
- }
- else if (c == 10) {
- /* ignore */
- }
- else {
- if (use_8250_int) {
- irq_bufferout_write(c);
- }
- else {
- while (!uart_8250_can_write(uart));
- uart_8250_write(uart,(uint8_t)c);
- }
- fwrite(&c,1,1,stdout); fflush(stdout);
- }
- }
-
- if (use_8250_int) {
- int sm=0;
- /* the interrupt handler takes care of reading the data in (in bursts, if necessary).
- * our job is to follow the buffer. Note we have a "patience" parameter to break out
- * of the loop in cases where fast continious transmission prevents us from ever
- * emptying the buffer entirely. */
- _cli();
- patience = msg_len;
- while (patience-- != 0 && irq_buffer_o != irq_buffer_i) {
- c = irq_buffer[irq_buffer_o++];
- if (irq_buffer_o >= IRQ_BUFFER_SIZE) irq_buffer_o = 0;
- _sti();
-
- if (seqmatch >= 16) {
- if (((pc+1)&0xFF) != c) {
- if (sm++ == 0)
- printf("Sequential byte error %u -> %u\n",pc,c);
- }
- else if (c == 0) {
- printf(":)"); fflush(stdout);
- }
- }
- else {
- if (c == 13) {
- printf("\n");
- }
- else {
- fwrite(&c,1,1,stdout); fflush(stdout);
- }
- }
-
- if (((pc+1)&0xFF) == c) {
- if (seqmatch < 255) seqmatch++;
- }
- else if (seqmatch > 0) {
- seqmatch--;
- }
- pc = c;
- }
- _sti();
- }
- else {
- while (uart_8250_can_read(uart)) {
- c = uart_8250_read(uart);
- if (seqmatch >= 16) {
- if (((pc+1)&0xFF) != c) {
- printf("Sequential byte error %u -> %u\n",pc,c);
- }
- else if (c == 0) {
- printf(":)"); fflush(stdout);
- }
- }
- else {
- if (c == 13) {
- printf("\n");
- }
- else {
- fwrite(&c,1,1,stdout); fflush(stdout);
- }
-
- }
-
- if (((pc+1)&0xFF) == c) {
- if (seqmatch < 255) seqmatch++;
- }
- else if (seqmatch > 0) {
- seqmatch--;
- }
- pc = c;
- }
- }
-
- if (xmitseq) {
- unsigned int c = 0;
- for (c=0;c < 0x40;c++) {
- if (use_8250_int) {
- irq_bufferout_write(xmitbyte++);
- }
- else {
- if (!uart_8250_can_write(uart)) break;
- uart_8250_write(uart,xmitbyte++);
- }
- }
- }
- else if (stuck_xmit) {
- const char *p = msg;
- while (*p != 0) {
- c = *p++;
- if (use_8250_int) {
- irq_bufferout_write(c);
- }
- else {
- while (!uart_8250_can_write(uart));
- uart_8250_write(uart,(uint8_t)c);
- }
- }
- }
- }
-
- printf("\nDONE\n");
-}
-
-#ifdef ISAPNP
-static unsigned char devnode_raw[4096];
-
-void pnp_serial_scan() {
- /* most of the time the serial ports are BIOS controlled and on the motherboard.
- * they usually don't even show up in a PnP isolation scan. so we have to use
- * the "get device nodes" functions of the PnP BIOS. */
- {
- struct isa_pnp_device_node far *devn;
- unsigned int ret_ax,nodesize=0xFFFF;
- unsigned char numnodes=0xFF;
- struct isapnp_tag tag;
- unsigned char node;
-
- printf("Enumerating PnP system device nodes...\n");
-
- ret_ax = isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize);
- if (ret_ax == 0 && numnodes != 0xFF && nodesize < sizeof(devnode_raw)) {
- /* NTS: How nodes are enumerated in the PnP BIOS: set node = 0, pass address of node
- * to BIOS. BIOS, if it returns node information, will also overwrite node with
- * the node number of the next node, or with 0xFF if this is the last one.
- * On the last one, stop enumerating. */
- for (node=0;node != 0xFF;) {
- unsigned char far *rsc;
- int port = -1;
- int irq = -1;
-
- /* apparently, start with 0. call updates node to
- * next node number, or 0xFF to signify end */
- ret_ax = isa_pnp_bios_get_sysdev_node(&node,devnode_raw,
- ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW);
-
- if (ret_ax != 0)
- break;
-
- devn = (struct isa_pnp_device_node far*)devnode_raw;
- if (!is_rs232_or_compat_pnp_device(devn))
- continue;
-
- /* there are three config blocks, one after the other.
- * [allocated]
- * [possible]
- * [??]
- * since we're not a configuration utility, we only care about the first one */
- rsc = devnode_raw + sizeof(*devn);
- if (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag)) {
- do {
- if (tag.tag == ISAPNP_TAG_END) /* end tag */
- break;
-
- switch (tag.tag) {
-/*---------------------------------------------------------------------------------*/
-case ISAPNP_TAG_IRQ_FORMAT: {
- struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
- unsigned int i;
- for (i=0;i < 16 && irq < 0;i++) {
- if (x->irq_mask & (1U << (unsigned int)i))
- irq = i;
- }
-} break;
-case ISAPNP_TAG_IO_PORT: {
- struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
- if (x->length >= 8 && port < 0) port = x->min_range;
-} break;
-case ISAPNP_TAG_FIXED_IO_PORT: {
- struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
- if (x->length >= 8 && port < 0) port = x->base;
-} break;
-/*---------------------------------------------------------------------------------*/
- };
- } while (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag));
- }
-
- if (port < 0)
- continue;
-
- if (add_pnp_8250(port,irq))
- printf("Found PnP port @ 0x%03x IRQ %d\n",port,irq);
- }
- }
- }
-}
-#endif
-
-int main() {
- unsigned char msr_redraw = 1;
- unsigned char redraw = 1;
- unsigned char p_msr = 0;
- int i,die,choice;
-
- printf("8250/16450/16550 test program\n");
-#ifdef ISAPNP
- printf("ISA Plug & Play version\n");
-#endif
-
- cpu_probe(); /* ..for the DOS probe routine */
- probe_dos(); /* ..for the Windows detection code */
- detect_windows(); /* Windows virtualizes the COM ports, and we don't want probing to occur to avoid any disruption */
-
- if (!probe_8254()) {
- printf("8254 not found (I need this for time-sensitive portions of the driver)\n");
- return 1;
- }
-
- if (!probe_8259()) {
- printf("8259 not found (I need this for portions of the test involving serial interrupts)\n");
- return 1;
- }
-
- if (!init_8250()) {
- printf("Cannot init 8250 library\n");
- return 1;
- }
-
-#if defined(ISAPNP)
- if (!init_isa_pnp_bios()) {
- printf("Cannot init ISA PnP\n");
- return 1;
- }
- if (find_isa_pnp_bios()) {
- pnp_serial_scan();
- }
- else {
- printf("Warning, ISA PnP BIOS not found\n");
- }
-#else
- printf("%u BIOS I/O ports listed\nThey are: ",(unsigned int)bios_8250_ports);
- for (i=0;i < (int)bios_8250_ports;i++) printf("0x%04x ",get_8250_bios_port(i));
- printf("\n");
-
- printf("Now probing ports: "); fflush(stdout);
- for (i=0;!base_8250_full() && i < (int)bios_8250_ports;i++) {
- const uint16_t port = get_8250_bios_port(i);
- if (port == 0) continue;
- printf("0x%03X ",port); fflush(stdout);
- if (probe_8250(port)) printf("[OK] ");
- }
- if (windows_mode == WINDOWS_NONE || windows_mode == WINDOWS_REAL) {
- /* if we're running under Windows it's likely the kernel is virtualizing the ports. play it safe and
- * stick to the "BIOS" ports that Windows and it's virtualization likely added to the data area */
- for (i=0;!base_8250_full() && i < (int)(sizeof(standard_8250_ports)/sizeof(standard_8250_ports[0]));i++) {
- const uint16_t port = standard_8250_ports[i];
- if (port == 0) continue;
- printf("0x%03X ",port); fflush(stdout);
- if (probe_8250(port)) printf("[OK] ");
- }
- }
- printf("\n");
-#endif
-
- for (i=0;i < base_8250_ports;i++) {
- struct info_8250 *inf = &info_8250_port[i];
- printf("[%u] @ %03X (type %s IRQ %d)\n",i+1,inf->port,type_8250_to_str(inf->type),inf->irq);
- }
- printf("Choice? "); fflush(stdout);
- choice = -1;
- scanf("%d",&choice);
- choice--;
- if (choice < 0 || choice >= base_8250_ports) return 0;
- uart = &info_8250_port[choice];
-
- if (uart->irq != -1) {
- old_irq = _dos_getvect(irq2int(uart->irq));
- _dos_setvect(irq2int(uart->irq),uart_irq);
- if (uart->irq >= 0) {
- p8259_unmask(uart->irq);
- if (uart->irq >= 8) p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
- p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
- }
- }
-
- uart_8250_enable_interrupt(uart,0); /* disable interrupts (set IER=0) */
- uart_8250_disable_FIFO(uart);
- uart_8250_set_MCR(uart,3); /* turn on RTS and DTS */
- uart_8250_set_line_control(uart,UART_8250_LCR_8BIT | UART_8250_LCR_PARITY); /* 8 bit 1 stop bit odd parity */
- uart_8250_set_baudrate(uart,uart_8250_baud_to_divisor(uart,9600));
-
- for (die=0;die == 0;) {
- unsigned char msr = uart_8250_read_MSR(uart);
-
- if (redraw) {
- unsigned long baud=0;
- unsigned char bits=0,stop_bits=0,parity=0;
- unsigned char mcr = uart_8250_read_MCR(uart);
-
- redraw = 0;
- msr_redraw = 1;
-
- uart_8250_get_config(uart,&baud,&bits,&stop_bits,&parity);
- printf("\x0D");
- printf("State: %lu baud %u-bit %u stop bits %s DTR=%u RTS=%u LOOP=%u\n",baud,bits,stop_bits,type_8250_parity(parity),
- (mcr & 1) ? 1 : 0/*DTR*/,
- (mcr & 2) ? 1 : 0/*RTS*/,
- (mcr & 16) ? 1 : 0/*LOOP*/);
- printf("1. Change config 2. Toggle DTR 3. Toggle RTS 4. Show on console\n");
- printf("5. Config FIFO ");
- if (use_8250_int) printf("6. To poll IO ");
- else printf("6. To int IO ");
- printf("7. Toggle LOOP ");
- printf("\n");
- }
-
- if ((msr ^ p_msr) & 0xF0) msr_redraw = 1;
- p_msr = msr;
-
- if (msr_redraw) {
- msr_redraw = 0;
- printf( "\x0D"
- "CTS=%u DSR=%u RI=%u CD=%u ? ",
- (msr & 16) ? 1 : 0,
- (msr & 32) ? 1 : 0,
- (msr & 64) ? 1 : 0,
- (msr & 128) ? 1 : 0);
- fflush(stdout);
- }
-
- if (kbhit()) {
- choice = getch();
- if (choice == 27) {
- die++;
- break;
- }
- else if (choice == '1') {
- change_config(uart);
- redraw = 1;
- }
- else if (choice == '2') {
- uart_8250_set_MCR(uart,uart_8250_read_MCR(uart) ^ 1);
- redraw = 1;
- }
- else if (choice == '3') {
- uart_8250_set_MCR(uart,uart_8250_read_MCR(uart) ^ 2);
- redraw = 1;
- }
- else if (choice == '7') {
- uart_8250_set_MCR(uart,uart_8250_read_MCR(uart) ^ 16);
- redraw = 1;
- }
- else if (choice == '4') {
- show_console(uart);
- redraw = 1;
- }
- else if (choice == '5') {
- config_fifo(uart);
- redraw = 1;
- }
- else if (choice == '6') {
- /* NTS: Apparently a lot of hardware has problems with just turning on interrupts.
- * So do everything we can to fucking whip the UART into shape. Drain & reset
- * it's FIFO. Clear all interrupt events. Unmask the IRQ. Enable all interrupt
- * events. What ever it fucking takes */
- _cli();
-
- /* ACK the IRQ to ensure the PIC will send more. Doing this resolves a bug on
- * a Toshiba 465CDX and IBM NetVista where enabling interrupts would seem to
- * "hang" the machine (when in fact it was just the PIC not firing interrupts
- * and therefore preventing the keyboard and timer from having their interrupts
- * serviced) */
- if (uart->irq >= 8) p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
- p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
- redraw = 1;
-
- use_8250_int = !use_8250_int;
- if (use_8250_int) uart_8250_enable_interrupt(uart,0xF);
- else uart_8250_enable_interrupt(uart,0x0);
- for (i=0;i < 256 && (inp(uart->port+PORT_8250_IIR) & 1) == 0;i++) {
- inp(uart->port);
- inp(uart->port+PORT_8250_MSR);
- inp(uart->port+PORT_8250_MCR);
- inp(uart->port+PORT_8250_LSR);
- inp(uart->port+PORT_8250_IIR);
- inp(uart->port+PORT_8250_IER);
- }
- if (i == 256) printf("Warning: Unable to clear UART interrupt conditions\n");
- _sti();
- }
- }
- }
-
- uart_8250_enable_interrupt(uart,0); /* disable interrupts (set IER=0) */
- uart_8250_set_MCR(uart,0); /* RTS/DTR and aux lines off */
- uart_8250_disable_FIFO(uart);
- uart_8250_set_line_control(uart,UART_8250_LCR_8BIT | UART_8250_LCR_PARITY); /* 8 bit 1 stop bit odd parity */
- uart_8250_set_baudrate(uart,uart_8250_baud_to_divisor(uart,9600));
-
- if (uart->irq != -1) {
- _dos_setvect(irq2int(uart->irq),old_irq);
- if (uart->irq >= 0) p8259_mask(uart->irq);
- }
-
- return 0;
-}
-
+++ /dev/null
-/* I'm sorry */
-#define ISAPNP
-#include "test.c"
-
+++ /dev/null
-/* 8254.c
- *
- * 8254 programmable interrupt timer control library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * The 8254 Programmable Interrupt Timer is used on the PC platform for
- * several purposes. 3 Timers are provided, which are used as:
- *
- * Timer 0 - System timer. This is tied to IRQ 0 and under normal operation
- * provides the usual IRQ 0 18.2 ticks per second. DOS programs that
- * need higher resolution reprogram this timer to get it.
- *
- * Timer 1 - Misc, varies. On older PC hardware this was tied to DRAM refresh.
- * Modern hardware cycles it for whatever purpose. Don't assume it's function.
- *
- * Timer 2 - PC Speaker. This timer is configured to run as a square wave and it's
- * output is gated through the 8042 before going directly to a speaker in the
- * PC's computer case. When used, this timer allows your program to generate
- * audible beeps.
- *
- * On modern hardware this chip is either integrated into the core motherboard chipset or
- * emulated for backwards compatibility.
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/8254/8254.h>
-
-uint32_t t8254_counter[3] = {0x10000,0x10000,0x10000};
-int8_t probed_8254_result = -1;
-
-int probe_8254() {
- if (probed_8254_result >= 0)
- return (int)probed_8254_result;
-
- /* NTS: Reading port 0x43 does nothing. Intel's datasheet even mentions this in one of the tables.
- * Actual hardware experience tells me some motherboards DO return something but the correct
- * response (as seen in emulators in DOSBox) is to ignore, returning 0xFF */
- {
- /* read timer 0 and see if it comes back non-0xFF */
- /* NTS: We MUST use the read_8254 function to read it in order. The previous
- * version of this code read it byte-wise. For some reason it seems,
- * some emulators including DOSBox don't take that well and they fail
- * to reset the MSB/LSB flip-flop. When that happens our timer counter
- * readings come out byte-swapped and we cannot provide proper timing
- * and sleep routines. Symptoms: A DOS program using our timing code
- * would have proper timing only on every other run. */
- unsigned int patience = 128,cc;
- unsigned short c;
- do {
- c = read_8254(0);
- if (c == 0xFFFF) c = read_8254(0);
- if (c != 0xFFFF) break;
- for (cc=0;cc != 0xFFFFU;) cc++; /* delay */
- } while (patience-- > 0);
-
- if (c == 0xFF)
- return (probed_8254_result=0);
- }
-
- return (probed_8254_result=1);
-}
-
-unsigned long t8254_us2ticks(unsigned long a) {
- /* FIXME: can you write a version that doesn't require 64-bit integers? */
- uint64_t b;
- if (a == 0) return 0;
- b = (uint64_t)a * (uint64_t)T8254_REF_CLOCK_HZ;
- return (unsigned long)(b / 1000000ULL);
-}
-
-unsigned long t8254_us2ticksr(unsigned long a,unsigned long *rem) {
- /* FIXME: can you write a version that doesn't require 64-bit integers? */
- uint64_t b;
- if (a == 0) return 0;
- b = (uint64_t)a * (uint64_t)T8254_REF_CLOCK_HZ;
- *rem = (unsigned long)(b % 1000000ULL);
- return (unsigned long)(b / 1000000ULL);
-}
-
-void t8254_wait(unsigned long ticks) {
- uint16_t dec;
- t8254_time_t pr,cr;
- if (ticks <= 1) return;
- ticks--;
- cr = read_8254(0);
- do {
- pr = cr;
- cr = read_8254(0);
- if (cr > pr)
- dec = (pr + (uint16_t)t8254_counter[0] - cr);
- else
- dec = (pr - cr);
-
- ticks -= dec;
- } while ((signed long)ticks >= 0L);
-}
-
+++ /dev/null
-/* 8254.h
- *
- * 8254 programmable interrupt timer control library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-#ifndef __HW_8254_8254_H
-#define __HW_8254_8254_H
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* WARNING: When calling these functions it is recommended that you disable interrupts
- * during the programming procedure. In MS-DOS mode there is nothing to stop
- * the BIOS from trying to use the 8254 chip at the same time you are. It is
- * entirely possible that it might read values back during an interrupt. If
- * you do not watch for that, you will get erroneous results from these
- * routines. Use hw/cpu.h _cli() and _sti() functions.
- *
- * In contrast, it is extremely rare for interrupt handlers to mess with the
- * PC speaker gate port (and even if they do, the worst that can happen is
- * our code overrides what the IRQ is trying to do) */
-
-#define PC_SPEAKER_GATE 0x61
-
-/* 1.19318MHz from which the counter values divide down from */
-#define T8254_REF_CLOCK_HZ 1193180
-
-#define T8254_IRQ 0
-
-#define T8254_PORT(x) ((x) + 0x40)
-#define T8254_TIMER_PORT(x) T8254_PORT(x)
-#define T8254_CONTROL_PORT T8254_PORT(3)
-
-#define T8254_MODE_0_INT_ON_TERMINAL_COUNT 0
-#define T8254_MODE_1_HARDWARE_RETRIGGERABLE_ONE_SHOT 1
-#define T8254_MODE_2_RATE_GENERATOR 2
-#define T8254_MODE_3_SQUARE_WAVE_MODE 3
-#define T8254_MODE_4_SOFTWARE_TRIGGERED_STROBE 4
-#define T8254_MODE_5_HARDWARE_TRIGGERED_STROBE 5
-
-#define T8254_READBACK_COUNT 0x20
-#define T8254_READBACK_STATUS 0x10
-#define T8254_READBACK_TIMER_2 0x08
-#define T8254_READBACK_TIMER_1 0x04
-#define T8254_READBACK_TIMER_0 0x02
-#define T8254_READBACK_ALL 0x3E
-
-/* this represents one counter value in the 8254/8253 chipset library, including the
- * value the chip reloads on finishing countdown.
- * NTS: In 8254 hardware, a value of 0 is treated as 65536 because the chip decrements
- * THEN checks against zero. This allows the rate to drop as low as
- * 1193180 / 65536 = 18.20648Hz on PC hardware */
-typedef uint16_t t8254_time_t;
-
-/* the 8254 (NOT 8253!) has a command that allows us to read the status and counter
- * value of one or more latches (though contemporary hardware fails to emulate multi-
- * counter latching from one command!). The status allows us to know what the counter
- * was programmed as, the output of the counter at the time, and whether a new counter
- * value was being loaded. The t8254_readback_t structure is used to read this info */
-struct t8254_readback_entry_t {
- unsigned char status;
- t8254_time_t count;
-};
-
-struct t8254_readback_t {
- struct t8254_readback_entry_t timer[3];
-};
-
-extern uint32_t t8254_counter[3];
-extern int8_t probed_8254_result;
-
-int probe_8254();
-void readback_8254(unsigned char what,struct t8254_readback_t *t); /* WARNING: 8254 only, will not work on 8253 chips in original PC/XT hardware */
-unsigned long t8254_us2ticks(unsigned long a);
-unsigned long t8254_us2ticksr(unsigned long a,unsigned long *rem);
-void t8254_wait(unsigned long ticks);
-
-static inline t8254_time_t read_8254_ncli(unsigned char timer) {
- t8254_time_t x;
-
- if (timer > 2) return 0;
- outp(T8254_CONTROL_PORT,(timer << 6) | (0 << 4) | 0); /* latch counter N, counter latch read */
- x = (t8254_time_t)inp(T8254_TIMER_PORT(timer));
- x |= (t8254_time_t)inp(T8254_TIMER_PORT(timer)) << 8U;
- return x;
-}
-
-static inline t8254_time_t read_8254(unsigned char timer) {
- unsigned int flags;
- t8254_time_t x;
-
- flags = get_cpu_flags();
- x = read_8254_ncli(timer);
- _sti_if_flags(flags);
- return x;
-}
-
-/* NTS: At the hardware level, count == 0 is equivalent to programming 0x10000 into it.
- * t8254_time_t is a 16-bit integer, and we write 16 bits, so 0 and 0x10000 is
- * the same thing to us anyway */
-static inline void write_8254_ncli(unsigned char timer,t8254_time_t count,unsigned char mode) {
- if (timer > 2) return;
- outp(T8254_CONTROL_PORT,(timer << 6) | (3 << 4) | (mode << 1)); /* set new time */
- outp(T8254_TIMER_PORT(timer),count);
- outp(T8254_TIMER_PORT(timer),count >> 8);
- /* for our own timing code, keep track of what that count was. we can't read it back from H/W anyway */
- t8254_counter[timer] = (count == 0 ? 0x10000 : count);
-}
-
-static inline void write_8254(unsigned char timer,t8254_time_t count,unsigned char mode) {
- unsigned int flags;
-
- flags = get_cpu_flags();
- write_8254_ncli(timer,count,mode);
- _sti_if_flags(flags);
-}
-
-static inline unsigned char t8254_pc_speaker_read_gate() {
- return inp(PC_SPEAKER_GATE) & 3;
-}
-
-static inline void t8254_pc_speaker_set_gate(unsigned char m) {
- unsigned char x;
-
- x = inp(PC_SPEAKER_GATE);
- x = (x & ~0x3) | (m & 3);
- outp(PC_SPEAKER_GATE,x);
-}
-
-static inline void write_8254_system_timer(t8254_time_t max) {
- write_8254(0,max,T8254_MODE_2_RATE_GENERATOR);
-}
-
-static inline void write_8254_pc_speaker(t8254_time_t max) {
- write_8254(2,max,T8254_MODE_3_SQUARE_WAVE_MODE);
-}
-
-#endif /* __HW_8254_8254_H */
-
+++ /dev/null
-/* 8254.c
- *
- * 8254 programmable interrupt timer control library.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * The 8254 Programmable Interrupt Timer is used on the PC platform for
- * several purposes. 3 Timers are provided, which are used as:
- *
- * Timer 0 - System timer. This is tied to IRQ 0 and under normal operation
- * provides the usual IRQ 0 18.2 ticks per second. DOS programs that
- * need higher resolution reprogram this timer to get it.
- *
- * Timer 1 - Misc, varies. On older PC hardware this was tied to DRAM refresh.
- * Modern hardware cycles it for whatever purpose. Don't assume it's function.
- *
- * Timer 2 - PC Speaker. This timer is configured to run as a square wave and it's
- * output is gated through the 8042 before going directly to a speaker in the
- * PC's computer case. When used, this timer allows your program to generate
- * audible beeps.
- *
- * On modern hardware this chip is either integrated into the core motherboard chipset or
- * emulated for backwards compatibility.
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/8254/8254.h>
-
-void readback_8254(unsigned char what,struct t8254_readback_t *t) {
- t8254_time_t x;
- unsigned int i;
-
- if (what & 0x30) { /* if anything to readback */
- unsigned int cpu_flags = get_cpu_flags();
-
- _cli(); /* do not interrupt me */
- for (i=0;i <= 2;i++) {
- if (what & (T8254_READBACK_TIMER_0 << i)) { /* if asked to read back the timer... */
- /* NTS: Intel docs say we're supposed to be able to latch multiple counters in one I/O command then read them back,
- * but that doesn't seem to be 100% reliable on actual hardware or in most emulators (DOSBox only allows the
- * one read them unlatches them all). So just latch one at a time and read. */
- outp(T8254_CONTROL_PORT,0xC0 | ((what & 0x30) ^ 0x30) | (T8254_READBACK_TIMER_0 << i)); /* read-back command D5=COUNT D4=STATUS D3=COUNTER 2 D2=COUNTER 1 D1=COUNTER 0 */
- if (what & T8254_READBACK_STATUS) {
- t->timer[i].status = inp(T8254_TIMER_PORT(i));
- }
-
- if (what & T8254_READBACK_COUNT) {
- x = (t8254_time_t)inp(T8254_TIMER_PORT(i));
- x |= (t8254_time_t)inp(T8254_TIMER_PORT(i)) << 8;
- t->timer[i].count = x;
- }
- }
- }
-
- /* restore caller's IF bit */
- _sti_if_flags(cpu_flags);
- }
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ lib REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_8254_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = 8254.c
-OBJS = $(SUBDIR)$(HPS)8254.obj $(SUBDIR)$(HPS)8254rd.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_8254_LIB): $(OBJS)
- wlib -q -b -c $(HW_8254_LIB) -+$(SUBDIR)$(HPS)8254.obj -+$(SUBDIR)$(HPS)8254rd.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_8254_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_8254_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_8254_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-Program notes:\r
-\r
-Award BIOS on Pentium PIIX3 motherboard:\r
- - The BIOS is stupid with interrupts when any one IRQ is hooked without\r
- calling back to the BIOS. When DOS extenders are involved (32-bit)\r
- hooking IRQ 0 in this manner somehow prevents the BIOS from servicing\r
- the keyboard (IRQ 1) even though the program has left it untouched.\r
-\r
- If you run the 32-bit version of this program and your keyboard does\r
- not respond, that's why.\r
-\r
+++ /dev/null
-/* test.c
- *
- * 8254 programmable interrupt timer test program.
- * (C) 2008-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-/* NTS: As of 2011/02/27 the 8254 routines no longer do cli/sti for us, we are expected
- * to do them ourself. This is for performance reasons as well as for sanity reasons
- * should we ever need to use the subroutines from within an interrupt handler */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/8254/8254.h>
-
-static volatile unsigned int counter = 0;
-static unsigned int speaker_rate = T8254_REF_CLOCK_HZ / 400; /* 400Hz */
-static unsigned int max = 0xFFFF;
-
-void (__interrupt __far *prev_irq0)() = NULL;
-static void __interrupt __far irq0() {
- counter++;
- outp(0x20,0x20);
-}
-
-#if TARGET_MSDOS == 32
-/* 32-bit DOS flat mode doesn't impose restrictions */
-unsigned char tmp[238617];
-#else
-/* we're probably limited by 16-bit real mode and near pointers */
-unsigned char tmp[32768];
-#endif
-
-void pulse_width_test() {
- int fd;
- unsigned char cc;
- unsigned int play;
- unsigned char plan_b=0;
- unsigned int patience = 10000;
-
- _cli();
- write_8254_system_timer(0xFFFF); /* BUGFIX: Personal experience tells me BIOSes would fail reading the floppy if the IRQ 0 timer isn't ticking along at 18Hz */
- _sti();
-
- fd = open("..\\test1_22.wav",O_RDONLY|O_BINARY);
- if (fd < 0) fd = open("test1_22.wav",O_RDONLY|O_BINARY);
- if (fd < 0) {
- fprintf(stderr,"Cannot open test WAV\n");
- return;
- }
- lseek(fd,44,SEEK_SET);
- read(fd,tmp,sizeof(tmp));
- for (play=0;play < sizeof(tmp);play++) tmp[play] = (((tmp[play]) * 53) / 255) + 1; /* add "noise" to dither */
- close(fd);
-
- /* set timer 0 to 54 ticks (1.191MHz / 54 ~ 22050Hz) */
- _cli();
- t8254_pc_speaker_set_gate(0);
- write_8254_pc_speaker(1);
- write_8254_system_timer(54);
- _sti();
-
- _cli();
- {
- outp(T8254_CONTROL_PORT,(0 << 6) | (0 << 4) | 0); /* latch counter N, counter latch read */
- do {
- if (--patience == 1) break;
- cc = inp(T8254_TIMER_PORT(0));
- inp(T8254_TIMER_PORT(0));
- } while (cc < (54/2));
- do {
- if (--patience == 0) break;
- cc = inp(T8254_TIMER_PORT(0));
- inp(T8254_TIMER_PORT(0));
- } while (cc >= (54/2));
- if (patience <= 2) {
- write_8254_system_timer(0xFFFF); /* BUGFIX: on very old slow machines, the 54-count tick can easily cause the printf() below to absolutely CRAWL... */
- _sti();
- fprintf(stderr,"Oops! Either your CPU is too fast or the timer countdown trick doesn't work.\n");
- _cli();
- write_8254_system_timer(54);
- plan_b = 1;
- }
- }
- _sti();
-
- while (1) {
- if (kbhit()) {
- int c = getch();
- if (c == 27) break;
- }
-
- if (plan_b) {
- /* run with interrupts enabled, use IRQ0 to know when to tick */
- _cli();
- counter = 0;
- t8254_pc_speaker_set_gate(3);
- for (play=0;play < sizeof(tmp);) {
- outp(T8254_CONTROL_PORT,(2 << 6) | (1 << 4) | (T8254_MODE_0_INT_ON_TERMINAL_COUNT << 1)); /* MODE 0, low byte only, counter 2 */
- outp(T8254_TIMER_PORT(2),tmp[play]);
- _sti();
- while (counter == 0);
- _cli();
- play += counter;
- counter = 0;
- }
- _sti();
- }
- else {
- _cli();
- t8254_pc_speaker_set_gate(3);
- outp(T8254_CONTROL_PORT,(0 << 6) | (0 << 4) | 0); /* latch counter N, counter latch read */
- for (play=0;play < sizeof(tmp);play++) {
- outp(T8254_CONTROL_PORT,(2 << 6) | (1 << 4) | (T8254_MODE_0_INT_ON_TERMINAL_COUNT << 1)); /* MODE 0, low byte only, counter 2 */
- outp(T8254_TIMER_PORT(2),tmp[play]);
-
- do {
- cc = inp(T8254_TIMER_PORT(0));
- inp(T8254_TIMER_PORT(0));
- } while (cc < (54/2));
-
- do {
- cc = inp(T8254_TIMER_PORT(0));
- inp(T8254_TIMER_PORT(0));
- } while (cc >= (54/2));
- }
- _sti();
- }
- }
-
- t8254_pc_speaker_set_gate(0);
-}
-
-int main() {
- struct t8254_readback_t readback;
- t8254_time_t tick[3];
- unsigned int i;
-
- printf("8254 library test program\n");
- if (!probe_8254()) {
- printf("Chip not present. Your computer might be 2010-era hardware that dropped support for it.\n");
- return 1;
- }
-
- prev_irq0 = _dos_getvect(T8254_IRQ+0x08);
- _dos_setvect(T8254_IRQ+0x8,irq0);
-
- _cli();
- write_8254_pc_speaker(speaker_rate);
- write_8254_system_timer(max);
- _sti();
-
- while (1) {
- if (kbhit()) {
- int c = getch();
- if (c == 27)
- break;
- else if (c == '-') {
- max -= 80;
- if (max > (0xFFFF-80))
- max = 0xFFFF;
-
- _cli();
- write_8254_system_timer(max);
- _sti();
- }
- else if (c == '=') {
- max += 110;
- if (max < 110 || max > (0xFFFF-110))
- max = 0xFFFF;
-
- _cli();
- write_8254_system_timer(max);
- _sti();
- }
- /* play with timer 2 and the PC speaker gate */
- else if (c == 'p') {
- unsigned char on = (t8254_pc_speaker_read_gate() != 0) ? 1 : 0;
- if (on) t8254_pc_speaker_set_gate(0);
- else t8254_pc_speaker_set_gate(3);
- }
- else if (c == '[') {
- speaker_rate += 110;
- if (speaker_rate > (0xFFFF-110) || speaker_rate < 110)
- speaker_rate = 0xFFFF;
-
- write_8254_pc_speaker(speaker_rate);
- }
- else if (c == ']') {
- speaker_rate -= 110;
- if (speaker_rate > (0xFFFF-110))
- speaker_rate = 0;
-
- write_8254_pc_speaker(speaker_rate);
- }
- else if (c == 'w') {
- printf("\n");
- pulse_width_test();
- _cli();
- write_8254_system_timer(max);
- _sti();
- printf("\n");
- }
- else if (c == 'z') {
- /* sleep-wait loop test */
- unsigned long delay_ticks;
- unsigned long z;
- unsigned int c,cmax;
-
- printf("\nDelay interval in us? ");
- z = 1000000; scanf("%lu",&z);
-
- delay_ticks = t8254_us2ticks(z);
- printf(" %lu = %lu ticks\n",z,delay_ticks);
-
- if (delay_ticks == 0UL) cmax = T8254_REF_CLOCK_HZ / 20;
- else cmax = T8254_REF_CLOCK_HZ / 20 / delay_ticks;
- if (cmax == 0) cmax = 1;
-
- write_8254_pc_speaker(T8254_REF_CLOCK_HZ / 400); /* tick as fast as possible */
- while (1) {
- if (kbhit()) {
- if (getch() == 27) break;
- }
-
- for (c=0;c < cmax;c++) {
- t8254_pc_speaker_set_gate(3);
- t8254_wait(delay_ticks);
- t8254_pc_speaker_set_gate(0);
- t8254_wait(delay_ticks);
- }
- }
- }
- else if (c == 'd') {
- printf("\n \nDetail mode, hit 'd' again to exit: [WARNING: 8254 only]\n");
- while (1) {
- if (kbhit()) {
- int c = getch();
- if (c == 'd') {
- break;
- }
- }
-
- _cli();
- readback_8254(T8254_READBACK_ALL,&readback);
- _sti();
- printf("\x0D");
- for (i=0;i <= 2;i++) {
- printf("[%u] stat=%02x count=%04x ",i,
- readback.timer[i].status,
- readback.timer[i].count);
- }
- fflush(stdout);
- }
- printf("\n");
- }
- }
-
- for (i=0;i <= 2;i++) tick[i] = read_8254(i);
- printf("\x0D %04x %04x %04x max=%04x count=%04x",tick[0],tick[1],tick[2],max,counter);
- fflush(stdout);
- }
- printf("\n");
-
- _cli();
- write_8254_pc_speaker(0);
- t8254_pc_speaker_set_gate(0);
- _dos_setvect(T8254_IRQ+0x8,prev_irq0);
- _sti();
-
- write_8254_system_timer(0xFFFF); /* restore normal function to prevent BIOS from going crazy */
- return 0;
-}
-
+++ /dev/null
--fr=nul -fo=dos386f/.obj -i=.. -i../.. -e=2 -zq -mf -d0 -bt=dos -oilrtfm -wx -fp3 -3r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=386 -DMMODE=f -q 8254rd.c
+++ /dev/null
-/* 8259.c
- *
- * 8259 programmable interrupt controller library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * In PC hardware the 8259 is responsible for taking IRQ signals off the ISA bus, prioritizing
- * them, and interrupting the CPU to service the interrupts. The chip includes logic to keep
- * track of what interrupts are pending, active, not yet acknowledged by the CPU, etc. so that
- * the x86 CPU can properly handle them.
- *
- * In mid 1990s hardware the PIC was retained and often connected through a PCI core chipset
- * that routed both ISA and PCI interrupts into it. Some chipsets have additional registers
- * that allow "routing control", to determine whether a particular IRQ is to be associated
- * with a PCI device or the ISA bus.
- *
- * Starting in late 1990s hardware, the APIC (Advanced Programmable Interrupt Controller)
- * appeared on motherboards and was either put alongside with, or replaced, the traditional
- * PIC. But the traditional I/O ports are emulated just the same to ensure compatibility with
- * older software. Even today (in 2012) DOS programs can still communicate with I/O ports
- * 20-21h and A0-A1h to manage interrupts, at least until an APIC aware OS or program takes
- * control.
- */
-
-/* NTS: As of 2011/02/27 the 8254 routines no longer do cli/sti for us, we are expected
- * to do them ourself. This is for performance reasons as well as for sanity reasons
- * should we ever need to use the subroutines from within an interrupt handler */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/8259/8259.h>
-
-unsigned char p8259_slave_present = 0;
-signed char p8259_probed = 0;
-
-void p8259_ICW(unsigned char a,unsigned char b,unsigned char c,unsigned char d) {
- outp(p8259_irq_to_base_port(c,0),a | 0x10); /* D4 == 1 */
- outp(p8259_irq_to_base_port(c,1),b);
- outp(p8259_irq_to_base_port(c,1),c);
- if (a & 1) outp(p8259_irq_to_base_port(c,1),d);
-}
-
-/* NTS: bit 7 is set if there was an interrupt */
-/* WARNING: This code crashes DOSBox 0.74 with "PIC poll not handled" error message */
-unsigned char p8259_poll(unsigned char c) {
- /* issue poll command to read and ack an interrupt */
- p8259_OCW3(c,0x0C); /* OCW3 = POLL=1 SMM=0 RR=0 */
- return inp(p8259_irq_to_base_port(c,0));
-}
-
-int probe_8259() {
- unsigned char om,cm,c2;
- unsigned int flags;
-
- if (p8259_probed < 0)
- return (int)p8259_probed;
-
- /* don't let the BIOS fiddle with the mask during
- the test. Fixes: Pentium machine where 1 out of
- 100 times programs fail with "cannot init PIC" */
- flags = get_cpu_flags(); _cli();
- om = p8259_read_mask(0);
- p8259_write_mask(0,0xFF);
- cm = p8259_read_mask(0);
- p8259_write_mask(0,0x00);
- c2 = p8259_read_mask(0);
- p8259_write_mask(0,om);
- set_cpu_flags(flags);
-
- if (cm != 0xFF || c2 != 0x00)
- return (p8259_probed=0);
-
- /* is a slave present too? */
- flags = get_cpu_flags(); _cli();
- om = p8259_read_mask(8);
- p8259_write_mask(8,0xFF);
- cm = p8259_read_mask(8);
- p8259_write_mask(8,0x00);
- c2 = p8259_read_mask(8);
- p8259_write_mask(8,om);
- set_cpu_flags(flags);
-
- if (cm == 0xFF && c2 == 0x00)
- p8259_slave_present = 1;
-
- return (p8259_probed=1);
-}
-
+++ /dev/null
-/* 8259.h
- *
- * 8259 programmable interrupt controller library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-#ifndef __HW_8259_8259_H
-#define __HW_8259_8259_H
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* PIC hardware register description
- *
- * ICW1 I/O port base + 0 (NTS: bit D4 == 1 when writing this)
- * ICW2 I/O port base + 1
- * ICW3 I/O port base + 1
- * ICW4 I/O port base + 1
- *
- * OCW1 R/W interrupt mask register. setting the bit masks the interrupt. Use I/O port base + 0
- * OCW2 R/? EOI and rotate command opcodes (NTS: bit D3-4 == 0). I/O port base + 1
- * OCW3 R/? poll/read/etc command opcodes (NTS: bit D3-4 == 1) I/O port base + 1
- *
- */
-/* PIC library warning:
- *
- * For performance and sanity reasons this code does NOT mask interrupts during the function. You are
- * expected to wrap your calls with cli/sti functions. Though it is unlikely, leaving interrupts enabled
- * while doing this can cause problems in case the BIOS fiddles with the PIC during an IRQ */
-
-#define P8259_MASTER_DATA 0x20
-#define P8259_MASTER_MASK 0x21
-
-#define P8259_SLAVE_DATA 0xA0
-#define P8259_SLAVE_MASK 0xA1
-
-/* OCW2 command bits. For most commands you are expected to OR the low 3 bits with the IRQ for the command to take effect on */
-#define P8259_OCW2_ROTATE_AUTO_EOI_CLEAR (0U << 5U)
-#define P8259_OCW2_NON_SPECIFIC_EOI (1U << 5U)
-#define P8259_OCW2_NO_OP (2U << 5U)
-#define P8259_OCW2_SPECIFIC_EOI (3U << 5U)
-#define P8259_OCW2_ROTATE_AUTO_EOI_SET (4U << 5U)
-#define P8259_OCW2_ROTATE_NON_SPECIFIC_EOI (5U << 5U)
-#define P8259_OCW2_SET_PRIORITY (6U << 5U)
-#define P8259_OCW2_ROTATE_SPECIFIC_EOI (7U << 5U)
-
-#define P8259_MASK_BIT(x) (1U << ((x)&7U))
-
-extern unsigned char p8259_slave_present;
-
-/* c = IRQ which = I/O port */
-static inline unsigned char p8259_irq_to_base_port(unsigned char c,unsigned char which) {
- return ((c & 8) ? P8259_SLAVE_DATA : P8259_MASTER_DATA) + which;
-}
-
-/* c = IRQ. */
-static inline unsigned char p8259_read_mask(unsigned char c) { /* mask register AKA OCW1 */
- outp(p8259_irq_to_base_port(c,0),P8259_OCW2_NO_OP); /* issue NO-OP to make sure the PIC is ready to accept OCW1 */
- return inp(p8259_irq_to_base_port(c,1)); /* mask register */
-}
-
-static inline void p8259_write_mask(unsigned char c,unsigned char m) { /* mask register AKA OCW1 */
- outp(p8259_irq_to_base_port(c,0),P8259_OCW2_NO_OP); /* issue NO-OP to make sure the PIC is ready to accept OCW1 */
- outp(p8259_irq_to_base_port(c,1),m); /* write mask register */
-}
-
-static inline void p8259_OCW2(unsigned char c,unsigned char w) {
- outp(p8259_irq_to_base_port(c,0),w & 0xE7); /* D3-4 == 0 */
-}
-
-static inline void p8259_OCW3(unsigned char c,unsigned char w) {
- outp(p8259_irq_to_base_port(c,0),(w & 0xE7) | 0x08); /* D3-4 == 1 */
-}
-
-static inline unsigned char p8259_read_IRR(unsigned char c) {
- p8259_OCW3(c,0x02); /* OCW3 = read register command RR=1 RIS=0 */
- return inp(p8259_irq_to_base_port(c,0)); /* mask register */
-}
-
-static inline unsigned char p8259_read_ISR(unsigned char c) {
- p8259_OCW3(c,0x03); /* OCW3 = read register command RR=1 RIS=1 */
- return inp(p8259_irq_to_base_port(c,0)); /* mask register */
-}
-
-static inline unsigned char irq2int(unsigned char c) {
- c &= 0xF;
- if (c & 8) return c-8+0x70;
- return c+0x08;
-}
-
-static inline void p8259_unmask(unsigned char c) {
- unsigned char m = p8259_read_mask(c);
- p8259_write_mask(c,m & ~(1 << (c&7)));
-}
-
-static inline void p8259_mask(unsigned char c) {
- unsigned char m = p8259_read_mask(c);
- p8259_write_mask(c,m | (1 << (c&7)));
-}
-
-static inline unsigned char p8259_is_masked(unsigned char c) {
- return (p8259_read_mask(c) & (1 << (c&7)));
-}
-
-void p8259_ICW(unsigned char a,unsigned char b,unsigned char c,unsigned char d);
-unsigned char p8259_poll(unsigned char c);
-int probe_8259();
-
-#endif /* __HW_8259_8259_H */
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ lib REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_8259_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = 8259.c
-OBJS = $(SUBDIR)$(HPS)8259.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_8259_LIB): $(OBJS)
- wlib -q -b -c $(HW_8259_LIB) -+$(SUBDIR)$(HPS)8259.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_8259_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_8259_LIB) $(SUBDIR)$(HPS)test.obj
- $(LINKER) -q $(LDFLAGS) -fe=$(TEST_EXE) $(SUBDIR)$(HPS)test.obj $(HW_8259_LIB)
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_8259_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-Program notes:\r
-\r
-- Award BIOS on Pentium PIIX3 motherboard:\r
-\r
- The ISR/IRR test will usually not show anything due to the strange\r
- way the BIOS services interrupts.\r
-\r
+++ /dev/null
-/* test.c
- *
- * 8259 programmable interrupt controller test program.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-/* NTS: As of 2011/02/27 the 8254 routines no longer do cli/sti for us, we are expected
- * to do them ourself. This is for performance reasons as well as for sanity reasons
- * should we ever need to use the subroutines from within an interrupt handler */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/8259/8259.h>
-
-void polltest() {
- unsigned char ann[128],anni,cc;
- int pat;
-
- printf("Polling test. Interrupts that occur will be announced. Hit ESC to exit.\n");
- while (1) {
- _cli();
- anni = 0;
- pat = 3200;
- do {
- cc = p8259_poll(0);
- if (cc & 0x80) {
- ann[anni++] = cc & 7;
- if (anni >= sizeof(anni)) break;
- }
- else {
- break;
- }
-
- cc = p8259_poll(8);
- if (cc & 0x80) {
- ann[anni++] = (cc & 7) + 8;
- if (anni >= sizeof(anni)) break;
- }
- else {
- break;
- }
- } while (--pat != 0);
- _sti();
-
- /* we ate interrupts, so we need to reissue them */
- for (cc=0;cc < anni;cc++) {
- union REGS regs;
- switch (ann[cc]) {
- case 0: just_int86(0x08,®s,®s); break;
- case 1: just_int86(0x09,®s,®s); break;
- case 2: just_int86(0x0A,®s,®s); break;
- case 3: just_int86(0x0B,®s,®s); break;
- case 4: just_int86(0x0C,®s,®s); break;
- case 5: just_int86(0x0D,®s,®s); break;
- case 6: just_int86(0x0E,®s,®s); break;
- case 7: just_int86(0x0F,®s,®s); break;
-
- case 8: just_int86(0x70,®s,®s); break;
- case 9: just_int86(0x71,®s,®s); break;
- case 10: just_int86(0x72,®s,®s); break;
- case 11: just_int86(0x73,®s,®s); break;
- case 12: just_int86(0x74,®s,®s); break;
- case 13: just_int86(0x75,®s,®s); break;
- case 14: just_int86(0x76,®s,®s); break;
- case 15: just_int86(0x77,®s,®s); break;
- };
- }
-
- /* print them out */
- if (anni != 0) {
- for (cc=0;cc < anni;cc++) printf("%u ",ann[cc]);
- printf("\n");
- }
-
- if (kbhit()) {
- if (getch() == 27)
- break;
- }
- }
-}
-
-void irrisr() {
- unsigned short irr,isr;
-
- printf("Reading IRR/ISR hit ESC to quit\n");
- while (1) {
- if (kbhit()) {
- if (getch() == 27)
- break;
- }
-
- _cli();
- do {
- irr = p8259_read_IRR(0);
- irr |= p8259_read_IRR(8) << 8;
- isr = p8259_read_ISR(0);
- isr |= p8259_read_ISR(8) << 8;
- } while ((irr|isr) == 0);
- _sti();
-
- if ((irr|isr) != 0) printf("IRR=%04x ISR=%04x\n",irr,isr);
- }
-}
-
-int main() {
- int c;
-
- printf("8259 test program\n");
- if (!probe_8259()) {
- printf("There does not appear to be a PIC on your system\n");
- return 1;
- }
- printf("Slave PIC: %s\n",p8259_slave_present ? "yes" : "no");
-
- while (1) {
- printf(" 1: 8259 poll test\n");
- printf(" 2: 8259 IRR/ISR\n");
- printf("ESC: quit\n");
-
- c = getch();
- if (c == '1') {
- polltest();
- }
- else if (c == '2') {
- irrisr();
- }
- else if (c == 27) {
- break;
- }
- }
-
- return 0;
-}
-
+++ /dev/null
--fr=nul -fo=dos386f/.obj -i=.. -i../.. -e=2 -zq -mf -d0 -bt=dos -oilrtfm -wx -fp3 -3r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=386 -DMMODE=f -q 8259.c
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-/* acpi.c
- *
- * ACPI BIOS interface library.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * Modern PCs (since about 1999) have a BIOS that implements the ACPI BIOS standard.
- * This code allows your DOS program to detect the ACPI BIOS, locate the tables, and
- * make use of the ACPI BIOS. */
-/* TODO: When can we begin to incorporate an AML interpreter? */
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/cpu/cpu.h>
-#include <hw/acpi/acpi.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-#include <hw/flatreal/flatreal.h>
-
-unsigned char acpi_use_rsdt_32 = 0;
-uint32_t acpi_rsdp_location = 0;
-struct acpi_rsdp_descriptor* acpi_rsdp = NULL;
-uint32_t acpi_rsdt_location = 0; /* or XSDT (TODO: will become acpi_memaddr_t) */
-struct acpi_rsdt_header* acpi_rsdt = NULL; /* RSDT or XSDT */
-unsigned char acpi_probe_result = 0;
-unsigned char acpi_probed = 0;
-
-uint32_t acpi_mem_readd(acpi_memaddr_t m) {
-#if TARGET_MSDOS == 32
- /* 32-bit flat mode code does not yet have 64-bit address access, limited to 4GB */
- if ((m+3ULL) & (~0xFFFFFFFFULL))
- return ~0UL;
-
- /* if no paging, then we can just typecast the pointer and be done with it */
- if (!dos_ltp_info.paging)
- return *((volatile uint32_t*)((uint32_t)m));
-
- /* TODO: DPMI physical mem mapping method? */
- /* TODO: VCPI tricks? */
-
- return ~0UL;
-#else
- /* 16-bit real mode code does not yet have 64-bit address access, limited to 4GB */
- if ((m+3ULL) & (~0xFFFFFFFFULL))
- return ~0UL;
-
- return flatrealmode_readd((uint32_t)m);
-#endif
-}
-
-void acpi_mem_writed(acpi_memaddr_t m,uint32_t d) {
-#if TARGET_MSDOS == 32
- /* 32-bit flat mode code does not yet have 64-bit address access, limited to 4GB */
- if ((m+3ULL) & (~0xFFFFFFFFULL))
- return;
-
- /* if no paging, then we can just typecast the pointer and be done with it */
- if (!dos_ltp_info.paging)
- *((volatile uint32_t*)((uint32_t)m)) = d;
-
- /* TODO: DPMI physical mem mapping method? */
- /* TODO: VCPI tricks? */
-#else
- /* 16-bit real mode code does not yet have 64-bit address access, limited to 4GB */
- if ((m+3ULL) & (~0xFFFFFFFFULL))
- return;
-
- flatrealmode_writed((uint32_t)m,d);
-#endif
-}
-
-void acpi_free() {
- if (acpi_rsdp != NULL) free(acpi_rsdp);
- acpi_rsdp = NULL;
- if (acpi_rsdt != NULL) free(acpi_rsdt);
- acpi_rsdt = NULL;
-}
-
-int acpi_probe_scan(uint32_t start,uint32_t end) {
- uint32_t a = start & (~0xFUL);
- unsigned int i,len;
- unsigned char sum;
- char buf[36];
-
- acpi_free();
- for (;(a+0xFUL) < end;a += 0x10UL) {
- ((uint32_t*)buf)[0] = acpi_mem_readd(a+0x0UL);
- ((uint32_t*)buf)[1] = acpi_mem_readd(a+0x4UL);
- if (memcmp(buf,"RSD PTR ",8) == 0) {
- ((uint32_t*)buf)[2] = acpi_mem_readd(a+0x8UL);
- ((uint32_t*)buf)[3] = acpi_mem_readd(a+0xCUL);
- ((uint32_t*)buf)[4] = acpi_mem_readd(a+0x10UL);
- /* == 20 bytes */
- for (sum=0,i=0;i < 20;i++) sum += buf[i];
- if (sum == 0) {
- /* found it */
- acpi_rsdp_location = a;
-
- /* consider it v2.0 or higher if the extended checksum works out,
- * else patch our copy to say v1.0 */
- ((uint32_t*)buf)[5] = acpi_mem_readd(a+0x14UL);
- ((uint32_t*)buf)[6] = acpi_mem_readd(a+0x18UL);
- ((uint32_t*)buf)[7] = acpi_mem_readd(a+0x1CUL);
- ((uint32_t*)buf)[8] = acpi_mem_readd(a+0x20UL);
- len = (int)(((uint32_t*)buf)[5]);
- if (buf[15]/*revision*/ != 0 && ((uint32_t*)buf)[5] >= 33 && ((uint32_t*)buf)[5] <= 255) {
- /* == 36 bytes */
- for (sum=0,i=0;i < min(len,36);i++) sum += buf[i];
- for (;i < len;i++) sum += acpi_mem_readb(a+i);
-
- if (sum == 0) {
- }
- else {
- fprintf(stderr,"ACPI v2.0 checksum fail\n");
- buf[15] = 0; /* patch to rev 0 */
- }
- }
- else {
- buf[15] = 0;
- }
-
- if (buf[15] == 0) {
- ((uint32_t*)buf)[5] = 20; /* length 20 */
- len = 20;
- }
-
- if (len >= 20) {
- acpi_rsdp = malloc(len);
- if (acpi_rsdp != NULL)
- memcpy(acpi_rsdp,buf,min(len,36));
- }
-
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-int acpi_probe_rsdt_check(acpi_memaddr_t a,uint32_t expect,uint32_t *length) {
- unsigned char sum=0;
- unsigned long i,len;
- uint32_t tmp;
-
- tmp = acpi_mem_readd(a);
- if (expect != 0UL && expect != tmp) return 0;
-
- len = (unsigned long)acpi_mem_readd(a+4); /* Length field */
- if (len < 36 || len >= (1UL << 20ULL)) return 0;
-
- for (i=0;i < (len & (~3UL));i += 4) {
- tmp = acpi_mem_readd(a + (acpi_memaddr_t)i);
- sum += (unsigned char)((tmp >> 0UL) & 0xFFUL);
- sum += (unsigned char)((tmp >> 8UL) & 0xFFUL);
- sum += (unsigned char)((tmp >> 16UL) & 0xFFUL);
- sum += (unsigned char)((tmp >> 24UL) & 0xFFUL);
- }
- if (len & 3UL) {
- tmp = acpi_mem_readd(a + (acpi_memaddr_t)i);
- sum += (unsigned char)((tmp >> 0UL) & 0xFFUL);
- if ((len & 3UL) >= 1UL) sum += (unsigned char)((tmp >> 8UL) & 0xFFUL);
- if ((len & 3UL) >= 2UL) sum += (unsigned char)((tmp >> 16UL) & 0xFFUL);
- if ((len & 3UL) == 3UL) sum += (unsigned char)((tmp >> 24UL) & 0xFFUL);
- }
-
- *length = (uint32_t)len;
- return (sum == 0x00);
-}
-
-void acpi_memcpy_from_phys(void *dst,acpi_memaddr_t src,uint32_t len) {
- while (len >= 4UL) {
- *((uint32_t*)dst) = acpi_mem_readd(src);
- dst = (void*)((char*)dst + 4);
- src += 4ULL;
- len -= 4UL;
- }
- if (len > 0UL) {
- uint32_t tmp = acpi_mem_readd(src);
- assert(len < 4UL);
- memcpy(dst,&tmp,(size_t)len);
- }
-}
-
-void acpi_probe_rsdt() {
- uint32_t len = 0;
-
- if (acpi_rsdt != NULL)
- return;
-
- acpi_rsdt_location = 0;
-
- /* TODO: Remove 4GB limit when this code *CAN* reach above 4GB */
- if (acpi_rsdp->revision != 0 && acpi_rsdp->xsdt_address != 0ULL &&
- acpi_rsdp->xsdt_address < 0x100000000ULL && !acpi_use_rsdt_32) {
- if (acpi_probe_rsdt_check(acpi_rsdp->xsdt_address,0x54445358UL,&len)) /* XSDT */
- acpi_rsdt_location = (uint32_t)(acpi_rsdp->xsdt_address);
- }
-
- if (acpi_rsdt_location == 0 && acpi_rsdp->rsdt_address != 0UL) {
- if (acpi_probe_rsdt_check(acpi_rsdp->rsdt_address,0x54445352UL,&len)) /* RSDT */
- acpi_rsdt_location = (uint32_t)(acpi_rsdp->rsdt_address);
- }
-
- if (acpi_rsdt_location != 0ULL && len >= 36UL && len <= 32768UL) {
- acpi_rsdt = malloc(len);
- if (acpi_rsdt != NULL) acpi_memcpy_from_phys((void*)acpi_rsdt,acpi_rsdt_location,len);
- }
-}
-
-int acpi_probe_ebda() {
- /* the RDSP can exist in the extended BIOS data area, or in the 0xE0000-0xFFFFF range */
- uint16_t sg;
- int ret = 0;
-
-#if TARGET_MSDOS == 32
- sg = *((uint16_t*)(0x40E));
-#else
- sg = *((uint16_t far*)MK_FP(0x40,0x0E));
-#endif
-
- if (sg >= 0x60 && sg < 0xA000)
- ret = acpi_probe_scan((uint32_t)sg << 4UL,((uint32_t)sg << 4UL) + 0x3FF);
-
- if (ret == 0) ret = acpi_probe_scan(0xE0000UL,0xFFFFFUL);
- if (ret == 0) return 0;
- acpi_probe_rsdt();
- return 1;
-}
-
-int acpi_probe() {
- if (acpi_probed)
- return acpi_probe_result;
-
- acpi_probed=1;
- if (acpi_probe_ebda())
- return (acpi_probe_result=1);
-
- return (acpi_probe_result=0);
-}
-
-unsigned long acpi_rsdt_entries() {
- if (acpi_rsdt == NULL) return 0UL;
- if (acpi_rsdt->length < 36UL) return 0UL;
- if (acpi_rsdt_is_xsdt())
- return (unsigned long)((acpi_rsdt->length-36UL)/8UL);
- else
- return (unsigned long)((acpi_rsdt->length-36UL)/4UL);
-}
-
-acpi_memaddr_t acpi_rsdt_entry(unsigned long idx) {
- if (idx >= 0x40000000UL) return 0ULL;
- if (acpi_rsdt_is_xsdt()) {
- if (((idx*8UL)+36UL) >= acpi_rsdt->length) return 0ULL;
- return ((uint64_t*)((char*)acpi_rsdt + 36))[idx];
- }
- else {
- if (((idx*4UL)+36UL) >= acpi_rsdt->length) return 0ULL;
- return ((uint32_t*)((char*)acpi_rsdt + 36))[idx];
- }
-}
-
+++ /dev/null
-/* acpi.h
- *
- * ACPI BIOS interface library.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- */
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-typedef uint64_t acpi_memaddr_t;
-
-#pragma pack(push,1)
-struct acpi_rsdp_descriptor_v1 { /* ACPI RSDP v1.0 descriptor */
- char signature[8];
- uint8_t checksum;
- char OEM_id[6];
- uint8_t revision;
- uint32_t rsdt_address;
-}; /* == 20 bytes */
-
-struct acpi_rsdp_descriptor_v2 { /* ACPI RSDP v2.0 descriptor */
- /* v1.0 */
- char signature[8];
- uint8_t checksum;
- char OEM_id[6];
- uint8_t revision;
- uint32_t rsdt_address;
- /* v2.0 */
- uint32_t length;
- uint64_t xsdt_address;
- uint8_t extended_checksum;
- uint8_t reserved[3];
-}; /* == 36 bytes */
-
-struct acpi_rsdt_header {
- char signature[4];
- uint32_t length;
- uint8_t revision;
- uint8_t checksum;
- char OEM_id[6];
- char OEM_table_id[8];
- uint32_t OEM_revision;
- uint32_t creator_id;
- uint32_t creator_revision;
-}; /* == 36 bytes */
-
-struct acpi_mcfg_header { /* PCI Express MCFG table */
- char signature[4];
- uint32_t length;
- uint8_t revision;
- uint8_t checksum;
- char OEM_id[6];
- char OEM_table_id[8];
- uint32_t OEM_revision;
- uint32_t creator_id;
- uint32_t creator_revision;
- /* MCFG specific */
- uint64_t _reserved_;
- /* configuration entries follow, one per range of busses */
-}; /* == 44 bytes */
-
-struct acpi_mcfg_entry {
- uint64_t base_address;
- uint16_t pci_segment_group_number;
- unsigned char start_pci_bus_number;
- unsigned char end_pci_bus_number;
- uint32_t _reserved_;
-}; /* == 16 bytes */
-
-#define acpi_rsdp_descriptor acpi_rsdp_descriptor_v2
-#pragma pack(pop)
-
-#define acpi_rsdt_is_xsdt() (*((uint32_t*)(acpi_rsdt->signature)) == 0x54445358UL)
-
-/* rather than copypasta code, let's just map 32-bit reads and typecast down */
-#define acpi_mem_readw(m) ((uint16_t)acpi_mem_readd(m))
-#define acpi_mem_readb(m) ((uint8_t)acpi_mem_readd(m))
-
-/* rather than copypasta code, let's just map 32-bit writes and typecast down */
-#define acpi_mem_writew(m,d) acpi_mem_writed(m,(uint16_t)(d))
-#define acpi_mem_writeb(m,d) acpi_mem_writed(m,(uint8_t)(d))
-
-extern unsigned char acpi_use_rsdt_32;
-extern uint32_t acpi_rsdp_location;
-extern struct acpi_rsdp_descriptor* acpi_rsdp;
-extern uint32_t acpi_rsdt_location;
-extern struct acpi_rsdt_header* acpi_rsdt; /* RSDT or XSDT */
-
-int acpi_probe();
-void acpi_free();
-int acpi_probe_ebda();
-void acpi_probe_rsdt();
-unsigned long acpi_rsdt_entries();
-uint32_t acpi_mem_readd(acpi_memaddr_t m);
-int acpi_probe_scan(uint32_t start,uint32_t end);
-void acpi_mem_writed(acpi_memaddr_t m,uint32_t d);
-acpi_memaddr_t acpi_rsdt_entry(unsigned long idx);
-void acpi_memcpy_from_phys(void *dst,acpi_memaddr_t src,uint32_t len);
-int acpi_probe_rsdt_check(acpi_memaddr_t a,uint32_t expect,uint32_t *length);
-
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_ACPI_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = acpi.c
-OBJS = $(SUBDIR)$(HPS)acpi.obj $(SUBDIR)$(HPS)acpi.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_ACPI_LIB): $(OBJS)
- wlib -q -b -c $(HW_ACPI_LIB) -+$(SUBDIR)$(HPS)acpi.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_ACPI_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_ACPI_LIB) $(HW_ACPI_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(HW_FLATREAL_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_ACPI_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* test.c
- *
- * ACPI BIOS interface test program.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/cpu/cpu.h>
-#include <hw/acpi/acpi.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-#include <hw/flatreal/flatreal.h>
-#include <hw/dos/doswin.h>
-
-static void help() {
- fprintf(stderr,"Test [options]\n");
- fprintf(stderr," /32 Use 32-bit RSDT\n");
-}
-
-int main(int argc,char **argv) {
- struct acpi_rsdt_header sdth;
- acpi_memaddr_t addr;
- unsigned long i,max;
- uint32_t tmp32,tmplen;
- char tmp[32];
-
- for (i=1;i < (unsigned long)argc;) {
- const char *a = argv[(unsigned int)(i++)];
-
- if (*a == '-' || *a == '/') {
- do { a++; } while (*a == '-' || *a == '/');
-
- if (!strcmp(a,"?") || !strcmp(a,"h") || !strcmp(a,"help")) {
- help();
- return 1;
- }
- else if (!strcmp(a,"32")) {
- acpi_use_rsdt_32 = 1;
- }
- else {
- fprintf(stderr,"Unknown switch '%s'\n",a);
- help();
- return 1;
- }
- }
- else {
- fprintf(stderr,"Unknown arg '%s'\n",a);
- help();
- return 1;
- }
- }
-
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!probe_8259()) {
- printf("Cannot init 8259 PIC\n");
- return 1;
- }
- cpu_probe();
- probe_dos();
- detect_windows();
-#if TARGET_MSDOS == 32
- probe_dpmi();
- dos_ltp_probe();
-#endif
-
-#if TARGET_MSDOS == 16
- if (!flatrealmode_setup(FLATREALMODE_4GB)) {
- printf("Unable to set up flat real mode (needed for 16-bit builds)\n");
- printf("Most ACPI functions require access to the full 4GB range.\n");
- return 1;
- }
-#endif
-
- if (!acpi_probe()) {
- printf("ACPI BIOS not found\n");
- return 1;
- }
- assert(acpi_rsdp != NULL);
- printf("ACPI %u.0 structure at 0x%05lX\n",acpi_rsdp->revision+1,(unsigned long)acpi_rsdp_location);
-
- memcpy(tmp,(char*)(&(acpi_rsdp->OEM_id)),6); tmp[6]=0;
- printf("ACPI OEM ID '%s', RSDT address (32-bit) 0x%08lX Length %lu\n",tmp,
- (unsigned long)(acpi_rsdp->rsdt_address),
- (unsigned long)(acpi_rsdp->length));
- if (acpi_rsdp->revision != 0)
- printf(" XSDT address (64-bit) 0x%016llX\n",
- (unsigned long long)(acpi_rsdp->xsdt_address));
-
- printf("Chosen RSDT/XSDT at 0x%08llX\n",(unsigned long long)acpi_rsdt_location);
-
- if (acpi_rsdt != NULL) {
- memcpy(tmp,(void*)(acpi_rsdt->signature),4); tmp[4] = 0;
- printf(" '%s': len=%lu rev=%u\n",tmp,(unsigned long)acpi_rsdt->length,
- acpi_rsdt->revision);
-
- memcpy(tmp,(void*)(acpi_rsdt->OEM_id),6); tmp[6] = 0;
- printf(" OEM id: '%s'\n",tmp);
-
- memcpy(tmp,(void*)(acpi_rsdt->OEM_table_id),8); tmp[8] = 0;
- printf(" OEM table id: '%s' rev %lu\n",tmp,
- (unsigned long)acpi_rsdt->OEM_revision);
-
- memcpy(tmp,(void*)(&(acpi_rsdt->creator_id)),4); tmp[4] = 0;
- printf(" Creator: '%s' rev %lu\n",tmp,
- (unsigned long)acpi_rsdt->creator_revision);
- }
-
- max = acpi_rsdt_entries();
- if (acpi_rsdt_is_xsdt()) {
- printf("Showing XSDT, %lu entries\n",max);
- }
- else {
- printf("Showing RSDT, %lu entries\n",max);
- }
-
- for (i=0;i < max;i++) {
- addr = acpi_rsdt_entry(i);
- printf(" [%lu] 0x%08llX ",i,(unsigned long long)addr);
- if (addr != 0ULL) {
- tmp32 = acpi_mem_readd(addr);
- tmplen = 0;
-
- memcpy(tmp,&tmp32,4); tmp[4] = 0;
- if (acpi_probe_rsdt_check(addr,tmp32,&tmplen)) {
- acpi_memcpy_from_phys(&sdth,addr,sizeof(struct acpi_rsdt_header));
-
- printf("'%s' len=0x%lX rev=%u ",tmp,(unsigned long)tmplen,sdth.revision);
-
- memcpy(tmp,&sdth.OEM_id,6); tmp[6] = 0;
- printf("OEM id: '%s'\n",tmp);
-
- memcpy(tmp,&sdth.OEM_table_id,8); tmp[8] = 0;
- printf("OEM table id: '%s' rev %u ",tmp,sdth.OEM_revision);
-
- memcpy(tmp,&sdth.creator_id,4); tmp[4] = 0;
- printf("Creator id: '%s' rev %u",tmp,sdth.creator_revision);
-
- if (!memcmp(sdth.signature,"MCFG",4)) {
- struct acpi_mcfg_entry entry;
- uint64_t o = addr + 44;
- unsigned int count;
-
- printf("\nPCI Express map:");
- assert(sizeof(struct acpi_mcfg_entry) == 16);
- count = (unsigned int)(tmplen / sizeof(struct acpi_mcfg_entry));
- while (count != 0) {
- acpi_memcpy_from_phys(&entry,o,sizeof(struct acpi_mcfg_entry));
- o += sizeof(struct acpi_mcfg_entry);
-
- /* Some bioses I test against seem to return enough for 3 but fill in only 1? */
- if (entry.base_address != 0ULL || entry.start_pci_bus_number != 0 || entry.end_pci_bus_number != 0) {
- uint64_t sz;
-
- if (entry.start_pci_bus_number > entry.end_pci_bus_number)
- entry.start_pci_bus_number = entry.end_pci_bus_number;
-
- sz = (((unsigned long long)(entry.end_pci_bus_number - entry.start_pci_bus_number)) + 1ULL) << 20ULL;
- printf("\n @0x%08llX-0x%08llX seg=%u bus=%u-%u",
- (unsigned long long)entry.base_address,
- (unsigned long long)(entry.base_address + sz - 1ULL),
- (unsigned int)entry.pci_segment_group_number,
- (unsigned int)entry.start_pci_bus_number,
- (unsigned int)entry.end_pci_bus_number);
- }
-
- count--;
- }
- }
- }
- else {
- printf("'%s' check failed",tmp);
- }
- }
- printf("\n");
- }
-
- acpi_free();
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-/* adlib.c
- *
- * Adlib OPL2/OPL3 FM synthesizer chipset controller library.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * On most Sound Blaster compatible cards all the way up to the late 1990s, a
- * Yamaha OPL2 or OPL3 chipset exists (or may be emulated on PCI cards) that
- * responds to ports 388h-389h. Through these I/O ports you control the FM
- * synthesizer engine. On some cards, a second OPL2 may exist at 38A-38Bh,
- * and on ISA PnP cards, the OPL3 may be located at 38C-38Dh if software
- * configured. */
-/* TODO: ISA PnP complementary library */
-/* TODO: Modifications to the library to support OPL2/OPL3 chipsets at I/O ports
- * other than 388h */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/adlib/adlib.h>
-
-unsigned short adlib_voice_to_op_opl2[9] = {0x00,0x01,0x02, 0x08,0x09,0x0A, 0x10,0x11,0x12};
-/* NTS: There is a HOWTO out there stating that the registers line up 0,1,2,6,7,8,... == WRONG! */
-unsigned short adlib_voice_to_op_opl3[18] = {0x00,0x01,0x02, 0x08,0x09,0x0A, 0x10,0x11,0x12, 0x100,0x101,0x102, 0x108,0x109,0x10A, 0x110,0x111,0x112};
-unsigned short* adlib_voice_to_op = adlib_voice_to_op_opl2;
-
-struct adlib_reg_bd adlib_reg_bd;
-struct adlib_fm_channel adlib_fm[ADLIB_FM_VOICES];
-int adlib_fm_voices = 0;
-unsigned char adlib_flags = 0;
-
-struct adlib_fm_channel adlib_fm_preset_violin_opl3 = {
- .mod = {0, 1, 1, 1, 1, 1, 42, 6, 1, 1, 4, 0,
- 3, 456, 1, 1, 1, 1, 4, 0, 5},
- .car = {0, 1, 1, 1, 1, 1, 63, 4, 1, 1, 4, 0,
- 3, 456, 1, 1, 1, 1, 0, 0, 2}
-};
-
-struct adlib_fm_channel adlib_fm_preset_violin_opl2 = {
- .mod = {0, 1, 1, 1, 1, 1, 42, 6, 1, 1, 4, 0,
- 3, 456, 1, 1, 1, 1, 2, 0, 1},
- .car = {0, 1, 1, 1, 1, 1, 63, 4, 1, 1, 4, 0,
- 3, 456, 1, 1, 1, 1, 0, 0, 2}
-};
-
-struct adlib_fm_channel adlib_fm_preset_piano = {
- .mod = {0, 0, 1, 1, 1, 1, 42, 10, 4, 2, 3, 0,
- 4, 456, 1, 1, 1, 1, 4, 0, 0},
- .car = {0, 0, 1, 1, 1, 1, 63, 10, 1, 8, 3, 0,
- 4, 456, 1, 1, 1, 1, 0, 0, 0}
-};
-
-struct adlib_fm_channel adlib_fm_preset_harpsichord = {
- .mod = {0, 0, 1, 1, 1, 1, 42, 10, 3, 2, 3, 0,
- 4, 456, 1, 1, 1, 1, 2, 0, 3},
- .car = {0, 0, 1, 1, 1, 1, 63, 10, 5, 3, 3, 0,
- 4, 456, 1, 1, 1, 1, 0, 0, 3}
-};
-
-/* NTS: adjust the modulator total level value to vary between muted (27) and open (47) with
- * further adjustment if you want to mimick the change in sound when you blow harder */
-struct adlib_fm_channel adlib_fm_preset_horn = {
- .mod = {0, 0, 1, 0, 1, 0, 47, 6, 1, 1, 7, 0,
- 4, 514, 1, 1, 1, 1, 0, 0, 0},
- .car = {0, 0, 1, 0, 1, 0, 47, 8, 2, 2, 7, 0,
- 4, 456, 1, 1, 1, 1, 0, 0, 0}
-};
-
-struct adlib_fm_channel adlib_fm_preset_deep_bass_drum = {
- .mod = {0, 0, 0, 0, 1, 0, 13, 7, 1, 0, 1, 0,
- 2, 456, 1, 1, 1, 1, 7, 0, 1},
- .car = {0, 0, 1, 1, 1, 1, 63, 15, 2, 6, 1, 0,
- 2, 456, 1, 1, 1, 1, 0, 0, 0}
-};
-
-/* NTS: You can simulate hitting software or harder by adjusting the modulator total volume
- * as well as raising or lowering the frequency */
-struct adlib_fm_channel adlib_fm_preset_small_drum = {
- .mod = {0, 0, 0, 1, 1, 1, 54, 15, 10, 15, 15, 0,
- 3, 456, 1, 1, 1, 1, 1, 0, 0},
- .car = {0, 0, 1, 1, 1, 1, 63, 15, 7, 15, 15, 0,
- 3, 456, 1, 1, 1, 1, 1, 0, 0}
-};
-
-unsigned char adlib_read(unsigned short i) {
- unsigned char c;
- outp(ADLIB_IO_INDEX+((i>>8)*2),(unsigned char)i);
- adlib_wait();
- c = inp(ADLIB_IO_DATA+((i>>8)*2));
- adlib_wait();
- return c;
-}
-
-void adlib_write(unsigned short i,unsigned char d) {
- outp(ADLIB_IO_INDEX+((i>>8)*2),(unsigned char)i);
- adlib_wait();
- outp(ADLIB_IO_DATA+((i>>8)*2),d);
- adlib_wait();
-}
-
-/* TODO: adlib_write_imm_1() and adlib_write_imm_2()
- * this would allow DOS programs to use this ADLIB library from within
- * an interrupt routine */
-
-int probe_adlib(unsigned char sec) {
- unsigned char a,b,retry=3;
- unsigned short bas = sec ? 0x100 : 0;
-
- /* this code uses the 8254 for timing */
- if (!probe_8254())
- return 1;
-
- do {
- adlib_write(0x04+bas,0x60); /* reset both timers */
- adlib_write(0x04+bas,0x80); /* enable interrupts */
- a = adlib_status(sec);
- adlib_write(0x02+bas,0xFF); /* timer 1 */
- adlib_write(0x04+bas,0x21); /* start timer 1 */
- t8254_wait(t8254_us2ticks(100));
- b = adlib_status(sec);
- adlib_write(0x04+bas,0x60); /* reset both timers */
- adlib_write(0x04+bas,0x00); /* disable interrupts */
-
- if ((a&0xE0) == 0x00 && (b&0xE0) == 0xC0)
- return 1;
-
- } while (--retry != 0);
-
- return 0;
-}
-
-int init_adlib() {
- adlib_flags = 0;
- if (!probe_adlib(0))
- return 0;
-
- adlib_write(0x01,0x20); /* enable waveform select */
- adlib_voice_to_op = adlib_voice_to_op_opl2;
- adlib_fm_voices = 9;
-
- if (probe_adlib(1)) {
- adlib_fm_voices = 18;
- adlib_flags = ADLIB_FM_DUAL_OPL2;
- }
- else {
- /* NTS: "unofficial" method of detecting OPL3 */
- if ((adlib_status(0) & 0x06) == 0) {
- adlib_fm_voices = 18;
- adlib_flags = ADLIB_FM_OPL3;
- adlib_voice_to_op = adlib_voice_to_op_opl3;
-
- /* init like an OPL3 */
- adlib_write(0x105,0x01); /* set OPL3 bit */
- probe_adlib(0);
- adlib_write(0x104,0x00); /* disable any 4op connections */
- }
- }
-
- return 1;
-}
-
-void shutdown_adlib_opl3() {
- if (adlib_flags & ADLIB_FM_OPL3) {
- adlib_write(0x105,0x00); /* clear OPL3 bit */
- probe_adlib(0);
- adlib_fm_voices = 9;
- adlib_voice_to_op = adlib_voice_to_op_opl2;
- adlib_flags &= ~ADLIB_FM_OPL3;
- }
-}
-
-void shutdown_adlib() {
- shutdown_adlib_opl3();
-}
-
-void adlib_update_group20(unsigned int op,struct adlib_fm_operator *f) {
- adlib_write(0x20+op, (f->am << 7) |
- (f->vibrato << 6) |
- (f->sustain << 5) |
- (f->key_scaling_rate << 4) |
- (f->mod_multiple << 0));
-}
-
-void adlib_update_group40(unsigned int op,struct adlib_fm_operator *f) {
- adlib_write(0x40+op, (f->level_key_scale << 6) |
- ((f->total_level^63) << 0));
-}
-
-void adlib_update_group60(unsigned int op,struct adlib_fm_operator *f) {
- adlib_write(0x60+op, (f->attack_rate << 4) |
- (f->decay_rate << 0));
-}
-
-void adlib_update_group80(unsigned int op,struct adlib_fm_operator *f) {
- adlib_write(0x80+op, (f->sustain_level << 4) |
- (f->release_rate << 0));
-}
-
-void adlib_update_groupA0(unsigned int channel,struct adlib_fm_channel *ch) {
- struct adlib_fm_operator *f = &ch->mod;
- unsigned int x = (channel >= 9) ? 0x100 : 0;
- adlib_write(0xA0+(channel%9)+x, f->f_number);
- adlib_write(0xB0+(channel%9)+x, (f->key_on << 5) |
- (f->octave << 2) |
- (f->f_number >> 8));
-}
-
-void adlib_update_groupC0(unsigned int channel,struct adlib_fm_channel *ch) {
- struct adlib_fm_operator *f = &ch->mod;
- unsigned int x = (channel >= 9) ? 0x100 : 0;
- adlib_write(0xC0+(channel%9)+x, (f->feedback << 1) |
- (f->connection << 0) |
- (f->ch_d << 7) |
- (f->ch_c << 6) |
- (f->ch_b << 5) |
- (f->ch_a << 4));
-}
-
-void adlib_update_groupE0(unsigned int op,struct adlib_fm_operator *f) {
- adlib_write(0xE0+op, (f->waveform << 0));
-}
-
-void adlib_update_operator(unsigned int op,struct adlib_fm_operator *f) {
- adlib_update_group20(op,f);
- adlib_update_group40(op,f);
- adlib_update_group60(op,f);
- adlib_update_group80(op,f);
- adlib_update_groupE0(op,f);
-}
-
-void adlib_update_bd(struct adlib_reg_bd *b) {
- adlib_write(0xBD, (b->am_depth << 7) |
- (b->vibrato_depth << 6) |
- (b->rythm_enable << 5) |
- (b->bass_drum_on << 4) |
- (b->snare_drum_on << 3) |
- (b->tom_tom_on << 2) |
- (b->cymbal_on << 1) |
- (b->hi_hat_on << 0));
-}
-
-void adlib_apply_all() {
- struct adlib_fm_operator *f;
- unsigned short op;
- int ch;
-
- for (ch=0;ch < adlib_fm_voices;ch++) {
- f = &adlib_fm[ch].mod; op = adlib_voice_to_op[ch]; adlib_update_operator(op,f);
- f = &adlib_fm[ch].car; op = adlib_voice_to_op[ch]+3; adlib_update_operator(op,f);
- adlib_update_groupA0(ch,&adlib_fm[ch]);
- adlib_update_groupC0(ch,&adlib_fm[ch]);
- }
- adlib_update_bd(&adlib_reg_bd);
-}
-
-double adlib_fm_op_to_freq(struct adlib_fm_operator *f) {
- unsigned long t = (unsigned long)f->f_number * 49716UL;
- return (double)t / (1UL << (20UL - (unsigned long)f->octave));
-}
-
-void adlib_freq_to_fm_op(struct adlib_fm_operator *f,double freq) {
- unsigned long l;
-
- freq *= (1UL << (20UL - (unsigned long)f->octave));
- l = (unsigned long)freq / 49716UL;
- f->octave = 4;
- while (l > 1023UL) {
- f->octave++;
- l >>= 1UL;
- }
- while (l != 0UL && l < 256UL) {
- f->octave--;
- l <<= 1UL;
- }
- f->f_number = l;
-}
-
+++ /dev/null
-/* adlib.h
- *
- * Adlib OPL2/OPL3 FM synthesizer chipset controller library.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#define ADLIB_FM_VOICES 18
-
-#define ADLIB_IO_INDEX 0x388
-#define ADLIB_IO_STATUS 0x388
-#define ADLIB_IO_DATA 0x389
-
-#define ADLIB_IO_INDEX2 0x38A
-#define ADLIB_IO_STATUS2 0x38A
-#define ADLIB_IO_DATA2 0x38B
-
-/* Adlib status */
-#define ADLIB_STATUS_TIMERS_EXPIRED 0x80
-#define ADLIB_STATUS_TIMER1_EXPIRED 0x40
-#define ADLIB_STATUS_TIMER2_EXPIRED 0x20
-
-enum {
- ADLIB_FM_DUAL_OPL2=0x01,
- ADLIB_FM_OPL3=0x02
-};
-
-struct adlib_fm_operator {
- /* 0x20-0x3F */
- uint8_t am:1; /* bit 7: Apply amplitude modulation */
- uint8_t vibrato:1; /* bit 6: Apply vibrato */
- uint8_t sustain:1; /* bit 5: maintain sustain level */
- uint8_t key_scaling_rate:1; /* bit 4: increase ADSR enevelope speed as pitch increases */
- uint8_t mod_multiple:4; /* bits 0-3: modulator multiple (1=voice frequency, 2=one octave above) */
- /* 0x40-0x5F */
- uint8_t level_key_scale:2; /* bits 7-6: decrease volume as frequency rises (0=none 1=1.5dB/8ve 2=3dB/8ve 3=6dB/8ve) */
- uint8_t total_level:6; /* bits 5-0: total output level (for sanity's sake, we maintain here as 0=silent 0x3F=full even though hardware is opposite) */
- /* 0x60-0x7F */
- uint8_t attack_rate:4; /* bits 7-4: attack rate */
- uint8_t decay_rate:4; /* bits 3-0: decay rate */
- /* 0x80-0x9F */
- uint8_t sustain_level:4; /* bits 7-4: sustain level */
- uint8_t release_rate:4; /* bits 3-0: release rate */
- /* 0xA0-0xBF */
- uint16_t key_on:1; /* bit 5: voice the channel */
- uint16_t octave:3; /* bits 4-2: octave */
- uint16_t f_number:10; /* bits 1-0, then bits 7-0: F-number (frequency) */
- /* 0xC0-0xCF */
- uint8_t ch_a:1; /* bit 4: OPL3: Channel A output */
- uint8_t ch_b:1; /* bit 5: OPL3: Channel B output */
- uint8_t ch_c:1; /* bit 6: OPL3: Channel C output */
- uint8_t ch_d:1; /* bit 7: OPL3: Channel D output */
- uint8_t feedback:3; /* bits 3-1: feedback strength */
- uint8_t connection:1; /* bit 0: connection (operator 1 and 2 independent if set) */
- /* 0xE0-0xFF */
- uint8_t waveform:3; /* bits 1-0: which waveform to use */
-};
-
-struct adlib_fm_channel {
- struct adlib_fm_operator mod,car;
-};
-
-struct adlib_reg_bd {
- uint8_t am_depth:1;
- uint8_t vibrato_depth:1;
- uint8_t rythm_enable:1;
- uint8_t bass_drum_on:1;
- uint8_t snare_drum_on:1;
- uint8_t tom_tom_on:1;
- uint8_t cymbal_on:1;
- uint8_t hi_hat_on:1;
-};
-
-int init_adlib();
-void shutdown_adlib();
-void shutdown_adlib_opl3();
-int probe_adlib(unsigned char sec);
-unsigned char adlib_read(unsigned short i);
-void adlib_write(unsigned short i,unsigned char d);
-void adlib_update_group20(unsigned int op,struct adlib_fm_operator *f);
-void adlib_update_group40(unsigned int op,struct adlib_fm_operator *f);
-void adlib_update_group60(unsigned int op,struct adlib_fm_operator *f);
-void adlib_update_group80(unsigned int op,struct adlib_fm_operator *f);
-void adlib_update_groupA0(unsigned int channel,struct adlib_fm_channel *ch);
-void adlib_update_groupC0(unsigned int channel,struct adlib_fm_channel *ch);
-void adlib_update_groupE0(unsigned int op,struct adlib_fm_operator *f);
-void adlib_update_operator(unsigned int op,struct adlib_fm_operator *f);
-void adlib_freq_to_fm_op(struct adlib_fm_operator *f,double freq);
-double adlib_fm_op_to_freq(struct adlib_fm_operator *f);
-void adlib_update_bd(struct adlib_reg_bd *b);
-void adlib_apply_all();
-
-extern unsigned short adlib_voice_to_op_opl2[9];
-extern unsigned short adlib_voice_to_op_opl3[18];
-extern unsigned short* adlib_voice_to_op;
-
-extern struct adlib_reg_bd adlib_reg_bd;
-extern struct adlib_fm_channel adlib_fm[ADLIB_FM_VOICES];
-extern int adlib_fm_voices;
-extern unsigned char adlib_flags;
-
-extern struct adlib_fm_channel adlib_fm_preset_deep_bass_drum;
-extern struct adlib_fm_channel adlib_fm_preset_violin_opl3;
-extern struct adlib_fm_channel adlib_fm_preset_violin_opl2;
-extern struct adlib_fm_channel adlib_fm_preset_harpsichord;
-extern struct adlib_fm_channel adlib_fm_preset_small_drum;
-extern struct adlib_fm_channel adlib_fm_preset_piano;
-extern struct adlib_fm_channel adlib_fm_preset_horn;
-
-/* NTS: I have a Creative CT1350B card where we really do have to wait at least
- * 33us per I/O access, because the OPL2 chip on it really is that slow.
- *
- * Peior to this fix, the adlib code would often fail on a real CT1350B
- * (unless run just after the Sound Blaster test program) and even if it
- * did run, only about 1/3rd of the voices would work. Upping the delay
- * to 40us for OPL3 and 100us for OPL2 resolved these issues. */
-static inline void adlib_wait() {
- t8254_wait(t8254_us2ticks((adlib_flags & ADLIB_FM_OPL3) ? 40 : 100));
-}
-
-static inline unsigned char adlib_status(unsigned char which) {
- adlib_wait();
- return inp(ADLIB_IO_STATUS+(which*2));
-}
-
-static inline unsigned char adlib_status_imm(unsigned char which) {
- return inp(ADLIB_IO_STATUS+(which*2));
-}
-
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_ADLIB_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = adlib.c
-OBJS = $(SUBDIR)$(HPS)adlib.obj $(SUBDIR)$(HPS)adlib.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-MIDI_EXE = $(SUBDIR)$(HPS)midi.exe
-
-$(HW_ADLIB_LIB): $(OBJS)
- wlib -q -b -c $(HW_ADLIB_LIB) -+$(SUBDIR)$(HPS)adlib.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_ADLIB_LIB) .symbolic
-
-exe: $(TEST_EXE) $(MIDI_EXE) .symbolic
-
-$(TEST_EXE): $(HW_ADLIB_LIB) $(HW_ADLIB_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_ADLIB_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(MIDI_EXE): $(HW_ADLIB_LIB) $(HW_ADLIB_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)midi.obj $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)midi.obj $(HW_ADLIB_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(MIDI_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_ADLIB_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* midi.c
- *
- * Adlib OPL2/OPL3 FM synthesizer chipset test program.
- * Play MIDI file using the OPLx synthesizer (well, poorly anyway)
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h>
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/adlib/adlib.h>
-
-/* one per OPL channel */
-struct midi_note {
- unsigned char note_number;
- unsigned char note_velocity;
- unsigned char note_track; /* from what MIDI track */
- unsigned char note_channel; /* from what MIDI channel */
- unsigned int busy:1; /* if occupied */
-};
-
-struct midi_channel {
- unsigned char program;
-};
-
-struct midi_track {
- /* track data, raw */
- unsigned char* raw; /* raw data base */
- unsigned char* fence; /* raw data end (last byte + 1) */
- unsigned char* read; /* raw data read ptr */
- /* state */
- unsigned long us_per_quarter_note; /* Microseconds per quarter note (def 120 BPM) */
- unsigned long us_tick_cnt_mtpq; /* Microseconds advanced (up to 10000 us or one unit at 100Hz) x ticks per quarter note */
- unsigned long wait;
- unsigned char last_status; /* MIDI last status byte */
- unsigned int eof:1; /* we hit the end of the track */
-};
-
-#define MIDI_MAX_CHANNELS 16
-#define MIDI_MAX_TRACKS 64
-
-struct midi_note midi_notes[ADLIB_FM_VOICES];
-struct midi_channel midi_ch[MIDI_MAX_CHANNELS];
-struct midi_track midi_trk[MIDI_MAX_TRACKS];
-static unsigned int midi_trk_count=0;
-static volatile unsigned char midi_playing=0;
-
-/* MIDI params. Nobody ever said it was a straightforward standard!
- * NTS: These are for reading reference. Internally we convert everything to 100Hz time base. */
-static unsigned int ticks_per_quarter_note=0; /* "Ticks per beat" */
-
-static void (interrupt *old_irq0)();
-static volatile unsigned long irq0_ticks=0;
-static volatile unsigned int irq0_cnt=0,irq0_add=0,irq0_max=0;
-
-#if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
-static inline unsigned long farptr2phys(unsigned char far *p) { /* take 16:16 pointer convert to physical memory address */
- return ((unsigned long)FP_SEG(p) << 4UL) + ((unsigned long)FP_OFF(p));
-}
-#endif
-
-static inline unsigned char midi_trk_read(struct midi_track *t) {
- unsigned char c;
-
- /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
- if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence) {
- t->eof = 1;
- return 0xFF;
- }
-
- c = *(t->read);
-#if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
- if (FP_OFF(t->read) >= 0xF) /* 16:16 far pointer aware (NTS: Programs reassigning this pointer MUST normalize the FAR pointer) */
- t->read = MK_FP(FP_SEG(t->read)+0x1,0);
- else
- t->read++;
-#else
- t->read++;
-#endif
- return c;
-}
-
-void midi_trk_end(struct midi_track *t) {
- t->wait = ~0UL;
- t->read = t->fence;
-}
-
-void midi_trk_skip(struct midi_track *t,unsigned long len) {
- unsigned long rem;
-
- /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
- if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence)
- return;
-
- if (len > 0xFFF0UL) {
- midi_trk_end(t);
- return;
- }
-#if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
- {
- unsigned long tt;
-
- tt = farptr2phys(t->read);
- rem = farptr2phys(t->fence) - tt;
- if (rem > len) rem = len;
- tt += rem;
- t->read = MK_FP(tt>>4,tt&0xF);
- }
-#else
- rem = (unsigned long)(t->fence - t->read);
- if (len > rem) len = rem;
- t->read += len;
-#endif
-}
-
-static const uint32_t midikeys_freqs[0x80] = {
- 0x00082d01, /* key 0 = 8.17579891564371Hz */
- 0x0008a976, /* key 1 = 8.66195721802725Hz */
- 0x00092d51, /* key 2 = 9.17702399741899Hz */
- 0x0009b904, /* key 3 = 9.72271824131503Hz */
- 0x000a4d05, /* key 4 = 10.3008611535272Hz */
- 0x000ae9d3, /* key 5 = 10.9133822322814Hz */
- 0x000b8ff4, /* key 6 = 11.5623257097386Hz */
- 0x000c3ff6, /* key 7 = 12.2498573744297Hz */
- 0x000cfa70, /* key 8 = 12.9782717993733Hz */
- 0x000dc000, /* key 9 = 13.75Hz */
- 0x000e914f, /* key 10 = 14.5676175474403Hz */
- 0x000f6f11, /* key 11 = 15.4338531642539Hz */
- 0x00105a02, /* key 12 = 16.3515978312874Hz */
- 0x001152ec, /* key 13 = 17.3239144360545Hz */
- 0x00125aa2, /* key 14 = 18.354047994838Hz */
- 0x00137208, /* key 15 = 19.4454364826301Hz */
- 0x00149a0a, /* key 16 = 20.6017223070544Hz */
- 0x0015d3a6, /* key 17 = 21.8267644645627Hz */
- 0x00171fe9, /* key 18 = 23.1246514194771Hz */
- 0x00187fed, /* key 19 = 24.4997147488593Hz */
- 0x0019f4e0, /* key 20 = 25.9565435987466Hz */
- 0x001b8000, /* key 21 = 27.5Hz */
- 0x001d229e, /* key 22 = 29.1352350948806Hz */
- 0x001ede22, /* key 23 = 30.8677063285078Hz */
- 0x0020b404, /* key 24 = 32.7031956625748Hz */
- 0x0022a5d8, /* key 25 = 34.647828872109Hz */
- 0x0024b545, /* key 26 = 36.7080959896759Hz */
- 0x0026e410, /* key 27 = 38.8908729652601Hz */
- 0x00293414, /* key 28 = 41.2034446141087Hz */
- 0x002ba74d, /* key 29 = 43.6535289291255Hz */
- 0x002e3fd2, /* key 30 = 46.2493028389543Hz */
- 0x0030ffda, /* key 31 = 48.9994294977187Hz */
- 0x0033e9c0, /* key 32 = 51.9130871974931Hz */
- 0x00370000, /* key 33 = 55Hz */
- 0x003a453d, /* key 34 = 58.2704701897612Hz */
- 0x003dbc44, /* key 35 = 61.7354126570155Hz */
- 0x00416809, /* key 36 = 65.4063913251497Hz */
- 0x00454bb0, /* key 37 = 69.295657744218Hz */
- 0x00496a8b, /* key 38 = 73.4161919793519Hz */
- 0x004dc820, /* key 39 = 77.7817459305202Hz */
- 0x00526829, /* key 40 = 82.4068892282175Hz */
- 0x00574e9b, /* key 41 = 87.307057858251Hz */
- 0x005c7fa4, /* key 42 = 92.4986056779086Hz */
- 0x0061ffb5, /* key 43 = 97.9988589954373Hz */
- 0x0067d380, /* key 44 = 103.826174394986Hz */
- 0x006e0000, /* key 45 = 110Hz */
- 0x00748a7b, /* key 46 = 116.540940379522Hz */
- 0x007b7888, /* key 47 = 123.470825314031Hz */
- 0x0082d012, /* key 48 = 130.812782650299Hz */
- 0x008a9760, /* key 49 = 138.591315488436Hz */
- 0x0092d517, /* key 50 = 146.832383958704Hz */
- 0x009b9041, /* key 51 = 155.56349186104Hz */
- 0x00a4d053, /* key 52 = 164.813778456435Hz */
- 0x00ae9d36, /* key 53 = 174.614115716502Hz */
- 0x00b8ff49, /* key 54 = 184.997211355817Hz */
- 0x00c3ff6a, /* key 55 = 195.997717990875Hz */
- 0x00cfa700, /* key 56 = 207.652348789973Hz */
- 0x00dc0000, /* key 57 = 220Hz */
- 0x00e914f6, /* key 58 = 233.081880759045Hz */
- 0x00f6f110, /* key 59 = 246.941650628062Hz */
- 0x0105a025, /* key 60 = 261.625565300599Hz */
- 0x01152ec0, /* key 61 = 277.182630976872Hz */
- 0x0125aa2e, /* key 62 = 293.664767917408Hz */
- 0x01372082, /* key 63 = 311.126983722081Hz */
- 0x0149a0a7, /* key 64 = 329.62755691287Hz */
- 0x015d3a6d, /* key 65 = 349.228231433004Hz */
- 0x0171fe92, /* key 66 = 369.994422711634Hz */
- 0x0187fed4, /* key 67 = 391.995435981749Hz */
- 0x019f4e00, /* key 68 = 415.304697579945Hz */
- 0x01b80000, /* key 69 = 440Hz */
- 0x01d229ec, /* key 70 = 466.16376151809Hz */
- 0x01ede220, /* key 71 = 493.883301256124Hz */
- 0x020b404a, /* key 72 = 523.251130601197Hz */
- 0x022a5d81, /* key 73 = 554.365261953744Hz */
- 0x024b545c, /* key 74 = 587.329535834815Hz */
- 0x026e4104, /* key 75 = 622.253967444162Hz */
- 0x0293414f, /* key 76 = 659.25511382574Hz */
- 0x02ba74da, /* key 77 = 698.456462866008Hz */
- 0x02e3fd24, /* key 78 = 739.988845423269Hz */
- 0x030ffda9, /* key 79 = 783.990871963499Hz */
- 0x033e9c01, /* key 80 = 830.60939515989Hz */
- 0x03700000, /* key 81 = 880Hz */
- 0x03a453d8, /* key 82 = 932.32752303618Hz */
- 0x03dbc440, /* key 83 = 987.766602512248Hz */
- 0x04168094, /* key 84 = 1046.50226120239Hz */
- 0x0454bb03, /* key 85 = 1108.73052390749Hz */
- 0x0496a8b8, /* key 86 = 1174.65907166963Hz */
- 0x04dc8208, /* key 87 = 1244.50793488832Hz */
- 0x0526829e, /* key 88 = 1318.51022765148Hz */
- 0x0574e9b5, /* key 89 = 1396.91292573202Hz */
- 0x05c7fa49, /* key 90 = 1479.97769084654Hz */
- 0x061ffb53, /* key 91 = 1567.981743927Hz */
- 0x067d3802, /* key 92 = 1661.21879031978Hz */
- 0x06e00000, /* key 93 = 1760Hz */
- 0x0748a7b1, /* key 94 = 1864.65504607236Hz */
- 0x07b78880, /* key 95 = 1975.5332050245Hz */
- 0x082d0128, /* key 96 = 2093.00452240479Hz */
- 0x08a97607, /* key 97 = 2217.46104781498Hz */
- 0x092d5171, /* key 98 = 2349.31814333926Hz */
- 0x09b90410, /* key 99 = 2489.01586977665Hz */
- 0x0a4d053c, /* key 100 = 2637.02045530296Hz */
- 0x0ae9d36b, /* key 101 = 2793.82585146403Hz */
- 0x0b8ff493, /* key 102 = 2959.95538169308Hz */
- 0x0c3ff6a7, /* key 103 = 3135.96348785399Hz */
- 0x0cfa7005, /* key 104 = 3322.43758063956Hz */
- 0x0dc00000, /* key 105 = 3520Hz */
- 0x0e914f62, /* key 106 = 3729.31009214472Hz */
- 0x0f6f1100, /* key 107 = 3951.06641004899Hz */
- 0x105a0250, /* key 108 = 4186.00904480958Hz */
- 0x1152ec0e, /* key 109 = 4434.92209562995Hz */
- 0x125aa2e3, /* key 110 = 4698.63628667852Hz */
- 0x13720820, /* key 111 = 4978.03173955329Hz */
- 0x149a0a79, /* key 112 = 5274.04091060592Hz */
- 0x15d3a6d6, /* key 113 = 5587.65170292806Hz */
- 0x171fe927, /* key 114 = 5919.91076338615Hz */
- 0x187fed4e, /* key 115 = 6271.92697570799Hz */
- 0x19f4e00a, /* key 116 = 6644.87516127912Hz */
- 0x1b800000, /* key 117 = 7040Hz */
- 0x1d229ec4, /* key 118 = 7458.62018428944Hz */
- 0x1ede2200, /* key 119 = 7902.13282009799Hz */
- 0x20b404a1, /* key 120 = 8372.01808961916Hz */
- 0x22a5d81c, /* key 121 = 8869.84419125991Hz */
- 0x24b545c7, /* key 122 = 9397.27257335704Hz */
- 0x26e41040, /* key 123 = 9956.06347910659Hz */
- 0x293414f2, /* key 124 = 10548.0818212118Hz */
- 0x2ba74dac, /* key 125 = 11175.3034058561Hz */
- 0x2e3fd24f, /* key 126 = 11839.8215267723Hz */
- 0x30ffda9c /* key 127 = 12543.853951416Hz */
-};
-
-static uint32_t midi_note_freq(struct midi_channel *ch,unsigned char key) {
- return midikeys_freqs[key&0x7F];
-}
-
-static struct midi_note *get_fm_note(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char do_alloc) {
- unsigned int tch = (unsigned int)(t - midi_trk); /* pointer math */
- unsigned int ach = (unsigned int)(ch - midi_ch); /* pointer math */
- unsigned int i,freen=~0;
-
- for (i=0;i < ADLIB_FM_VOICES;i++) {
- if (midi_notes[i].busy) {
- if (midi_notes[i].note_channel == ach && midi_notes[i].note_track == tch && midi_notes[i].note_number == key)
- return &midi_notes[i];
- }
- else {
- if (freen == ~0) freen = i;
- }
- }
-
- if (do_alloc && freen != ~0) return &midi_notes[freen];
- return NULL;
-}
-
-static void drop_fm_note(struct midi_channel *ch,unsigned char key) {
- unsigned int ach = (unsigned int)(ch - midi_ch); /* pointer math */
- unsigned int i;
-
- for (i=0;i < ADLIB_FM_VOICES;i++) {
- if (midi_notes[i].busy && midi_notes[i].note_channel == ach) {
- midi_notes[i].busy = 0;
- break;
- }
- }
-}
-
-static inline void on_key_aftertouch(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char vel) {
- struct midi_note *note = get_fm_note(t,ch,key,/*do_alloc*/0);
- uint32_t freq = midi_note_freq(ch,key);
- unsigned int ach;
-
- if (note == NULL) return;
-
- note->busy = 1;
- note->note_number = key;
- note->note_velocity = vel;
- note->note_track = (unsigned int)(t - midi_trk);
- note->note_channel = (unsigned int)(ch - midi_ch);
- ach = (unsigned int)(note - midi_notes); /* which FM channel? */
- adlib_freq_to_fm_op(&adlib_fm[ach].mod,(double)freq / 65536);
- adlib_fm[ach].mod.attack_rate = vel >> 3; /* 0-127 to 0-15 */
- adlib_fm[ach].mod.sustain_level = vel >> 3;
- adlib_fm[ach].mod.key_on = 1;
- adlib_update_groupA0(ach,&adlib_fm[ach]);
-}
-
-static inline void on_key_on(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char vel) {
- struct midi_note *note = get_fm_note(t,ch,key,/*do_alloc*/1);
- uint32_t freq = midi_note_freq(ch,key);
- unsigned int ach;
-
- /* HACK: Ignore percussion */
- if ((ch->program >= 8 && ch->program <= 15)/*Chromatic percussion*/ ||
- (ch->program >= 112 && ch->program <= 119)/*Percussive*/ ||
- ch == &midi_ch[9]/*MIDI channel 10 (DAMN YOU 1-BASED COUNTING)*/)
- return;
-
- if (note == NULL) {
- /* then we'll have to knock one off to make room */
- drop_fm_note(ch,key);
- note = get_fm_note(t,ch,key,1);
- if (note == NULL) return;
- }
-
- note->busy = 1;
- note->note_number = key;
- note->note_velocity = vel;
- note->note_track = (unsigned int)(t - midi_trk);
- note->note_channel = (unsigned int)(ch - midi_ch);
- ach = (unsigned int)(note - midi_notes); /* which FM channel? */
- adlib_freq_to_fm_op(&adlib_fm[ach].mod,(double)freq / 65536);
- adlib_fm[ach].mod.attack_rate = vel >> 3; /* 0-127 to 0-15 */
- adlib_fm[ach].mod.sustain_level = vel >> 3;
- adlib_fm[ach].mod.key_on = 1;
- adlib_update_groupA0(ach,&adlib_fm[ach]);
-}
-
-static inline void on_key_off(struct midi_track *t,struct midi_channel *ch,unsigned char key,unsigned char vel) {
- struct midi_note *note = get_fm_note(t,ch,key,/*do_alloc*/0);
- uint32_t freq = midi_note_freq(ch,key);
- unsigned int ach;
-
- if (note == NULL) return;
-
- note->busy = 0;
- ach = (unsigned int)(note - midi_notes); /* which FM channel? */
- adlib_freq_to_fm_op(&adlib_fm[ach].mod,(double)freq / 65536);
- adlib_fm[ach].mod.attack_rate = vel >> 3; /* 0-127 to 0-15 */
- adlib_fm[ach].mod.sustain_level = vel >> 3;
- adlib_fm[ach].mod.key_on = 0;
- adlib_update_groupA0(ach,&adlib_fm[ach]);
-}
-
-static inline void on_control_change(struct midi_track *t,struct midi_channel *ch,unsigned char num,unsigned char val) {
-}
-
-static inline void on_program_change(struct midi_track *t,struct midi_channel *ch,unsigned char inst) {
- ch->program = inst;
-}
-
-static inline void on_channel_aftertouch(struct midi_track *t,struct midi_channel *ch,unsigned char velocity) {
-}
-
-static inline void on_pitch_bend(struct midi_track *t,struct midi_channel *ch,int bend/*-8192 to 8192*/) {
-}
-
-unsigned long midi_trk_read_delta(struct midi_track *t) {
- unsigned long tc = 0;
- unsigned char c = 0,b;
-
- /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
- if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence)
- return tc;
-
- while (c < 4) {
- b = midi_trk_read(t);
- tc = (tc << 7UL) + (unsigned long)(b&0x7F);
- if (!(b&0x80)) break;
- c++;
- }
-
- return tc;
-}
-
-void midi_tick_track(unsigned int i) {
- struct midi_track *t = midi_trk + i;
- struct midi_channel *ch;
- unsigned char b,c,d;
- int cnt=0;
-
- /* NTS: 16-bit large/compact builds MUST compare pointers as unsigned long to compare FAR pointers correctly! */
- if (t->read == NULL || (unsigned long)t->read >= (unsigned long)t->fence) {
- t->eof = 1;
- return;
- }
-
- t->us_tick_cnt_mtpq += 10000UL * (unsigned long)ticks_per_quarter_note;
- while (t->us_tick_cnt_mtpq >= t->us_per_quarter_note) {
- t->us_tick_cnt_mtpq -= t->us_per_quarter_note;
- cnt++;
-
- while (t->wait == 0) {
- if ((unsigned long)t->read >= (unsigned long)t->fence) {
- t->eof = 1;
- break;
- }
-
- /* read pointer should be pointing at MIDI event bytes, just after the time delay */
- b = midi_trk_read(t);
- if (b&0x80) {
- if (b < 0xF8) {
- if (b >= 0xF0)
- t->last_status = 0;
- else
- t->last_status = b;
- }
- if (b != 0x00 && ((b&0xF8) != 0xF0))
- c = midi_trk_read(t);
- }
- else {
- /* blegh. last status */
- c = b;
- b = t->last_status;
- }
- switch (b>>4) {
- case 0x8: { /* note off */
- d = midi_trk_read(t);
- ch = midi_ch + (b&0xF); /* c=key d=velocity */
- on_key_off(t,ch,c,d);
- } break;
- case 0x9: { /* note on */
- d = midi_trk_read(t);
- ch = midi_ch + (b&0xF); /* c=key d=velocity */
- if (d != 0) on_key_on(t,ch,c,d); /* "A Note On with a velocity of 0 is actually a note off" Bleh, really? */
- else on_key_off(t,ch,c,d);
- } break;
- case 0xA: { /* polyphonic aftertouch */
- d = midi_trk_read(t);
- ch = midi_ch + (b&0xF); /* c=key d=velocity */
- on_key_aftertouch(t,ch,c,d);
- } break;
- case 0xB: { /* control change */
- d = midi_trk_read(t);
- ch = midi_ch + (b&0xF); /* c=key d=velocity */
- on_control_change(t,ch,c,d);
- } break;
- case 0xC: { /* program change */
- on_program_change(t,ch,c); /* c=instrument d=not used */
- } break;
- case 0xD: { /* channel aftertouch */
- on_channel_aftertouch(t,ch,c); /* c=velocity d=not used */
- } break;
- case 0xE: { /* pitch bend */
- d = midi_trk_read(t);
- on_pitch_bend(t,ch,((c&0x7F)|((d&0x7F)<<7))-8192); /* c=LSB d=MSB */
- } break;
- case 0xF: { /* event */
- if (b == 0xFF) {
- if (c == 0x7F) { /* c=type d=len */
- unsigned long len = midi_trk_read_delta(t);
-// fprintf(stderr,"Type 0x7F len=%lu %p/%p/%p\n",len,t->raw,t->read,t->fence);
- if (len < 512UL) {
- /* unknown */
- midi_trk_skip(t,len);
- }
- else {
- midi_trk_end(t);
- }
- }
- else if (c < 0x7F) {
- d = midi_trk_read(t);
-
- if (c == 0x51 && d >= 3) {
- d -= 3;
- t->us_per_quarter_note = ((unsigned long)midi_trk_read(t)<<16UL)+
- ((unsigned long)midi_trk_read(t)<<8UL)+
- ((unsigned long)midi_trk_read(t)<<0UL);
-
- if (1/*TODO: If format 0 or format 1*/) {
- /* Ugh. Unless format 2, the tempo applies to all tracks */
- int j;
-
- for (j=0;j < midi_trk_count;j++) {
- if (j != i) midi_trk[j].us_per_quarter_note =
- t->us_per_quarter_note;
- }
- }
- }
- else {
-// fprintf(stderr,"Type 0x%02x len=%lu %p/%p/%p\n",c,d,t->raw,t->read,t->fence);
- }
-
- midi_trk_skip(t,d);
- }
- else {
- fprintf(stderr,"t=%u Unknown MIDI f message 0x%02x 0x%02x %p/%p/%p\n",i,b,c,t->raw,t->read,t->fence);
- }
- }
- else {
- unsigned long len = midi_trk_read_delta(t);
-// fprintf(stderr,"Sysex len=%lu %p/%p/%p\n",len,t->raw,t->read,t->fence);
- midi_trk_skip(t,len);
- }
- } break;
- default:
- if (b != 0x00) {
- fprintf(stderr,"t=%u Unknown MIDI message 0x%02x at %p/%p/%p\n",i,b,t->raw,t->read,t->fence);
- midi_trk_end(t);
- }
- break;
- };
-
- /* and then read the next event */
- t->wait = midi_trk_read_delta(t);
- }
- if (t->wait != 0) {
- t->wait--;
- }
- }
-}
-
-void adlib_shut_up();
-void midi_reset_tracks();
-void midi_reset_channels();
-
-void midi_tick() {
- if (midi_playing) {
- unsigned int i;
- int eof=0;
-
- for (i=0;i < midi_trk_count;i++) {
- midi_tick_track(i);
- eof += midi_trk[i].eof?1:0;
- }
-
- if (eof >= midi_trk_count) {
- adlib_shut_up();
- midi_reset_tracks();
- midi_reset_channels();
- }
- }
-}
-
-/* WARNING: subroutine call in interrupt handler. make sure you compile with -zu flag for large/compact memory models */
-void interrupt irq0() {
-// midi_tick();
- irq0_ticks++;
- if ((irq0_cnt += irq0_add) >= irq0_max) {
- irq0_cnt -= irq0_max;
- old_irq0();
- }
- else {
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
- }
-}
-
-void adlib_shut_up() {
- int i;
-
- memset(adlib_fm,0,sizeof(adlib_fm));
- memset(&adlib_reg_bd,0,sizeof(adlib_reg_bd));
- for (i=0;i < adlib_fm_voices;i++) {
- struct adlib_fm_operator *f;
- f = &adlib_fm[i].mod;
- f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
- f = &adlib_fm[i].car;
- f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
- }
-
- for (i=0;i < adlib_fm_voices;i++) {
- struct adlib_fm_operator *f;
-
- midi_notes[i].busy = 0;
- midi_notes[i].note_channel = 0;
-
- f = &adlib_fm[i].mod;
- f->mod_multiple = 1;
- f->total_level = 63 - 16;
- f->attack_rate = 15;
- f->decay_rate = 4;
- f->sustain_level = 0;
- f->release_rate = 8;
- f->f_number = 400;
- f->sustain = 1;
- f->octave = 4;
- f->key_on = 0;
-
- f = &adlib_fm[i].car;
- f->mod_multiple = 1;
- f->total_level = 63 - 16;
- f->attack_rate = 15;
- f->decay_rate = 4;
- f->sustain_level = 0;
- f->release_rate = 8;
- f->f_number = 0;
- f->sustain = 1;
- f->octave = 0;
- f->key_on = 0;
- }
-
- adlib_apply_all();
-}
-
-void midi_reset_track(unsigned int i) {
- struct midi_track *t;
-
- if (i >= MIDI_MAX_TRACKS) return;
- t = &midi_trk[i];
- t->eof = 0;
- t->last_status = 0;
- t->us_tick_cnt_mtpq = 0;
- t->us_per_quarter_note = (60000000UL / 120UL); /* 120BPM */
- t->read = midi_trk[i].raw;
- t->wait = midi_trk_read_delta(t); /* and then the read pointer will point at the MIDI event when wait counts down */
-}
-
-void midi_reset_tracks() {
- int i;
-
- for (i=0;i < midi_trk_count;i++)
- midi_reset_track(i);
-}
-
-void midi_reset_channels() {
- int i;
-
- for (i=0;i < MIDI_MAX_CHANNELS;i++) {
- midi_ch[i].program = 0;
- }
-}
-
-int load_midi_file(const char *path) {
- unsigned char tmp[256];
- unsigned int tracks=0;
- unsigned int tracki=0;
- int fd;
-
- fd = open(path,O_RDONLY|O_BINARY);
- if (fd < 0) {
- printf("Failed to load file %s\n",path);
- return 0;
- }
-
- ticks_per_quarter_note = 0;
- while (read(fd,tmp,8) == 8) {
- uint32_t sz;
-
- sz = ((uint32_t)tmp[4] << (uint32_t)24) |
- ((uint32_t)tmp[5] << (uint32_t)16) |
- ((uint32_t)tmp[6] << (uint32_t)8) |
- ((uint32_t)tmp[7] << (uint32_t)0);
- if (!memcmp(tmp,"MThd",4)) {
- unsigned short t,tdiv;
-
- if (sz < 6 || sz > 255) {
- fprintf(stderr,"Invalid MThd size %lu\n",(unsigned long)sz);
- goto err;
- }
- if (read(fd,tmp,(int)sz) != (int)sz) {
- fprintf(stderr,"MThd read error\n");
- goto err;
- }
-
- /* byte 0-1 = format type (0,1 or 2) */
- /* byte 2-3 = number of tracks */
- /* byte 4-5 = time divison */
- t = tmp[1] | (tmp[0] << 8);
- if (t > 1) {
- fprintf(stderr,"MThd type %u not supported\n",t);
- goto err; /* we only take type 0 or 1, don't support 2 */
- }
- tracks = tmp[3] | (tmp[2] << 8);
- if (tracks > MIDI_MAX_TRACKS) {
- fprintf(stderr,"MThd too many (%u) tracks\n",tracks);
- goto err;
- }
- tdiv = tmp[5] | (tmp[4] << 8);
- if (tdiv & 0x8000) {
- fprintf(stderr,"MThd SMPTE time division not supported\n");
- goto err; /* we do not support the SMPTE form */
- }
- if (tdiv == 0) {
- fprintf(stderr,"MThd time division == 0\n");
- goto err;
- }
- ticks_per_quarter_note = tdiv;
- }
- else if (!memcmp(tmp,"MTrk",4)) {
- if (sz == 0UL) continue;
-#if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
- if (sz > (640UL << 10UL)) goto err; /* 640KB */
-#elif TARGET_MSDOS == 32
- if (sz > (1UL << 20UL)) goto err; /* 1MB */
-#else
- if (sz > (60UL << 10UL)) goto err; /* 60KB */
-#endif
- if (tracki >= MIDI_MAX_TRACKS) goto err;
-#if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
- {
- unsigned segv;
-
- /* NTS: _fmalloc() is still limited to 64KB sizes */
- if (_dos_allocmem((unsigned)((sz+15UL)>>4UL),&segv) != 0) goto err;
- midi_trk[tracki].raw = MK_FP(segv,0);
- }
-#else
- midi_trk[tracki].raw = malloc(sz);
-#endif
- if (midi_trk[tracki].raw == NULL) goto err;
- midi_trk[tracki].read = midi_trk[tracki].raw;
-#if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
- {
- unsigned char far *p = midi_trk[tracki].raw;
- unsigned long rem = (unsigned long)sz;
- unsigned long cando;
- unsigned read;
-
- while (rem != 0UL) {
- read = 0;
-
- cando = 0x10000UL - (unsigned long)FP_OFF(p);
- if (cando > rem) cando = rem;
- if (cando > 0xFFFFUL) cando = 0xFFFFUL; /* we're limited to 64KB-1 of reading */
-
- if (_dos_read(fd,p,(unsigned)cando,&read) != 0) goto err;
- if (read != (unsigned)cando) goto err;
-
- rem -= cando;
- if ((((unsigned long)FP_OFF(p))+cando) == 0x10000UL)
- p = MK_FP(FP_SEG(p)+0x1000,0);
- else
- p += (unsigned)cando;
- }
-
- cando = farptr2phys(p);
- midi_trk[tracki].fence = MK_FP(cando>>4,cando&0xF);
- }
-#else
- midi_trk[tracki].fence = midi_trk[tracki].raw + (unsigned)sz;
- if (read(fd,midi_trk[tracki].raw,(unsigned)sz) != (int)sz) goto err;
-#endif
- tracki++;
- }
- else {
- fprintf(stderr,"Unknown MIDI chunk %c%c%c%c\n",tmp[0],tmp[1],tmp[2],tmp[3]);
- goto err;
- }
- }
- if (tracki == 0 || ticks_per_quarter_note == 0) goto err;
- midi_trk_count = tracki;
-
- fprintf(stderr,"Ticks per quarter note: %u\n",ticks_per_quarter_note);
-
- close(fd);
- return 1;
-err:
- close(fd);
- return 0;
-}
-
-int main(int argc,char **argv) {
- unsigned long ptick;
- int i,c;
-
- printf("ADLIB FM test program\n");
- if (argc < 2) {
- printf("You must specify a MIDI file to play\n");
- return 1;
- }
-
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
- if (!init_adlib()) {
- printf("Cannot init library\n");
- return 1;
- }
- if (!probe_8254()) { /* we need the timer to keep time with the music */
- printf("8254 timer not found\n");
- return 1;
- }
-
- for (i=0;i < MIDI_MAX_TRACKS;i++) {
- midi_trk[i].raw = NULL;
- midi_trk[i].read = NULL;
- midi_trk[i].fence = NULL;
- }
-
- if (load_midi_file(argv[1]) == 0) {
- printf("Failed to load MIDI\n");
- return 1;
- }
-
- write_8254_system_timer(T8254_REF_CLOCK_HZ / 100); /* tick faster at 100Hz please */
- irq0_cnt = 0;
- irq0_add = 182;
- irq0_max = 1000; /* about 18.2Hz */
- old_irq0 = _dos_getvect(8);/*IRQ0*/
- _dos_setvect(8,irq0);
-
- adlib_shut_up();
- midi_reset_channels();
- midi_reset_tracks();
- _cli();
- irq0_ticks = ptick = 0;
- _sti();
- midi_playing = 1;
-
- while (1) {
- unsigned long adv;
-
- _cli();
- adv = irq0_ticks - ptick;
- if (adv >= 100UL) adv = 100UL;
- ptick = irq0_ticks;
- _sti();
-
- while (adv != 0) {
- midi_tick();
- adv--;
- }
-
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- }
- }
-
- midi_playing = 0;
- adlib_shut_up();
- shutdown_adlib();
- _dos_setvect(8,old_irq0);
- write_8254_system_timer(0); /* back to normal 18.2Hz */
-
- for (i=0;i < MIDI_MAX_TRACKS;i++) {
- if (midi_trk[i].raw) {
-#if TARGET_MSDOS == 16 && (defined(__LARGE__) || defined(__COMPACT__))
- _dos_freemem(FP_SEG(midi_trk[i].raw)); /* NTS: Because we allocated with _dos_allocmem */
-#else
- free(midi_trk[i].raw);
-#endif
- midi_trk[i].raw = NULL;
- }
- midi_trk[i].fence = NULL;
- midi_trk[i].read = NULL;
- }
-
- return 0;
-}
-
+++ /dev/null
-#!/usr/bin/perl
-#
-# Generate a C array containing uint32_t 16.16 frequencies for all 128 MIDI keys.
-# motivated by what appear to be occasional "glitches" in Watcom C's pow() function.
-# C array is emitted to STDOUT.
-#
-# (C) 2014 Jonathan Campbell
-#
-# Ref C:
-# for (i=0;i < 0x80;i++) {
-# double a = 440.0 * pow(2,((double)(i - 69)) / 12);
-# midi_note_freqs[i] = (uint32_t)(a * 65536UL);
-# }
-my $i,$v,$r;
-
-print "static const uint32_t midikeys_freqs[0x80] = {\n";
-for ($i=0;$i < 0x80;$i++) {
- $v = (($i - 69) / 12); # A4 (440Hz) at key 69, 12 semitones per octave
- $a = 440.0 * (2 ** $v); # 440 * (2 ^ $v)
- print "\t".sprintf("0x%08x",int($a * 65536));
- print "," if ($i < 0x7F);
- print "\t/* key ".$i." = ".$a."Hz */";
- print "\n";
-}
-print "}\n";
-
+++ /dev/null
-Adlib OPL-2/OPL-3 Yamaha FM synthesizer support.
-
-Supports:
- Adlib FM synthesizer @ 0x388
- Sound Blaster FM synth (OPL-2 or OPL-3) @ 0x388
-
-ISA PnP notice: If you have a Sound Blaster 16 PnP installed and this
-program is unable to see the OPL-2/3 synth at 0x388, use the PNPCFG
-utility in the SNDSB Sound Blaster library to assign resources to the
-card. Make sure you assign the OPL port to 0x388.
-
-TODO: This code does not yet support multiple OPL chips, or OPL chips
-residing at an address other than 0x388.
-
+++ /dev/null
-/* test.c
- *
- * Adlib OPL2/OPL3 FM synthesizer chipset test program.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * This test program uses a "text user interface" to allow you to play
- * with the OPL2/OPL3 chipset and it's parameters. Some "instruments"
- * are preset for you if you want to make noise faster.
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/adlib/adlib.h>
-
-static unsigned int musical_scale[18] = {
- 0x1B0, /* E */
- 0x1CA, /* F */
- 0x1E5, /* f# */
- 0x202, /* G */
- 0x220, /* G# */
- 0x241, /* A */
- 0x263, /* A# */
- 0x287, /* B */
- 0x2AE, /* C */
-
- 0x2B0, /* E */
- 0x2CA, /* F */
- 0x2E5, /* f# */
- 0x302, /* G */
- 0x320, /* G# */
- 0x341, /* A */
- 0x363, /* A# */
- 0x387, /* B */
- 0x3AE, /* C */
-};
-
-int main(int argc,char **argv) {
- int i,loop,redraw,c,cc,selector=0,redrawln=0,hselect=0,selectsub=0;
- VGA_ALPHA_PTR vga;
- char tmp[128];
-
- printf("ADLIB FM test program\n");
-
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
- if (!init_adlib()) {
- printf("Cannot init library\n");
- return 1;
- }
-
- int10_setmode(3);
-
- /* for VGA: free up space if needed by going to 80x50 */
- if (adlib_fm_voices > 9)
- vga_bios_set_80x50_text();
-
- memset(adlib_fm,0,sizeof(adlib_fm));
- memset(&adlib_reg_bd,0,sizeof(adlib_reg_bd));
- for (i=0;i < adlib_fm_voices;i++) {
- struct adlib_fm_operator *f;
- f = &adlib_fm[i].mod;
- f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
- f = &adlib_fm[i].car;
- f->ch_a = f->ch_b = f->ch_c = f->ch_d = 1;
- }
-
- for (i=0;i < adlib_fm_voices;i++) {
- struct adlib_fm_operator *f;
-
- f = &adlib_fm[i].mod;
- f->mod_multiple = 1;
- f->total_level = 63 - 16;
- f->attack_rate = 15;
- f->decay_rate = 0;
- f->sustain_level = 7;
- f->release_rate = 7;
- f->f_number = musical_scale[i%18];
- f->octave = 4;
- f->key_on = 0;
-
- f = &adlib_fm[i].car;
- f->mod_multiple = 1;
- f->total_level = 63 - 16;
- f->attack_rate = 15;
- f->decay_rate = 0;
- f->sustain_level = 7;
- f->release_rate = 7;
- f->f_number = 0;
- f->octave = 0;
- f->key_on = 0;
- }
-
- adlib_apply_all();
-
- vga_write_color(0x07);
- vga_clear();
-
- loop=1;
- redraw=1;
- while (loop) {
- if (redraw || redrawln) {
- if (redraw) {
- for (vga=vga_alpha_ram,cc=0;cc < (80*vga_height);cc++) *vga++ = 0x1E00 | 177;
- vga_moveto(0,0);
- vga_write_color(0x1F);
- sprintf(tmp,"Adlib FM, %u-voice %s. Use Z & X to adj F10=PRESET F1=QUIET ",adlib_fm_voices,
- (adlib_flags & ADLIB_FM_OPL3) ? "OPL3" :
- (adlib_flags & ADLIB_FM_DUAL_OPL2) ? "Dual OPL2" : "OPL2");
- vga_write(tmp);
- if (adlib_flags & ADLIB_FM_OPL3) vga_write("F2=OPL3 off ");
- }
-
- if (redrawln || redraw) {
- struct adlib_reg_bd *bd = &adlib_reg_bd;
- static const char *hsel_str[18] = {
- "Amplitude modulatation",
- "Vibrato",
- "Sustain",
- "Key scaling rate",
- "Modulator frequency multiple",
- "Level key scaling",
- "Total level",
- "Attack rate",
- "Decay rate",
- "Sustain level",
- "Release rate",
- "KEY ON",
- "Octave",
- "F-Number",
- "Feedback",
- "Connection (operator 1 -> operator 2)",
- "Waveform",
- "Channel mapping (OPL3)"
- };
-
- vga_write_color(0x1A);
-
- vga_moveto(0,2);
- sprintf(tmp,"AM=%u VB=%u RYTHM=%u BAS=%u SNA=%u TOM=%u CYM=%u HI=%u\n",
- bd->am_depth,
- bd->vibrato_depth,
- bd->rythm_enable,
- bd->bass_drum_on,
- bd->snare_drum_on,
- bd->tom_tom_on,
- bd->cymbal_on,
- bd->hi_hat_on);
- vga_write(tmp);
-
- vga_moveto(0,3);
- vga_write(" ");
- vga_moveto(0,3);
- vga_write(hsel_str[hselect]);
-
- vga_moveto(0,4);
- vga_write_color(hselect == 0 ? 0x70 : 0x1E); vga_write("AM ");
- vga_write_color(hselect == 1 ? 0x70 : 0x1E); vga_write("VB ");
- vga_write_color(hselect == 2 ? 0x70 : 0x1E); vga_write("SUST ");
- vga_write_color(hselect == 3 ? 0x70 : 0x1E); vga_write("KSR ");
- vga_write_color(hselect == 4 ? 0x70 : 0x1E); vga_write("MMUL ");
- vga_write_color(hselect == 5 ? 0x70 : 0x1E); vga_write("LKS ");
- vga_write_color(hselect == 6 ? 0x70 : 0x1E); vga_write("TL ");
- vga_write_color(hselect == 7 ? 0x70 : 0x1E); vga_write("AR ");
- vga_write_color(hselect == 8 ? 0x70 : 0x1E); vga_write("DR ");
- vga_write_color(hselect == 9 ? 0x70 : 0x1E); vga_write("SL ");
- vga_write_color(hselect == 10 ? 0x70 : 0x1E); vga_write("RR ");
- vga_write_color(hselect == 11 ? 0x70 : 0x1E); vga_write("KEY ");
- vga_write_color(hselect == 12 ? 0x70 : 0x1E); vga_write("OCT ");
- vga_write_color(hselect == 13 ? 0x70 : 0x1E); vga_write("FNUM ");
- vga_write_color(hselect == 14 ? 0x70 : 0x1E); vga_write("FEED ");
- vga_write_color(hselect == 15 ? 0x70 : 0x1E); vga_write("CON ");
- vga_write_color(hselect == 16 ? 0x70 : 0x1E); vga_write("WV ");
- vga_write_color(hselect == 17 ? 0x70 : 0x1E); vga_write("ABCD ");
-
- for (i=0;i < adlib_fm_voices;i++) {
- struct adlib_fm_operator *f;
- double freq;
-
- f = &adlib_fm[i].mod;
- vga_moveto(0,5+i*2);
- freq = adlib_fm_op_to_freq(f);
- vga_write_color(i == selector && selectsub == 0 ? 0x70 : 0x1E);
- cc = sprintf(tmp,"%u %u %u %u %-2u %u %-2u %-2u %-2u %-2u %-2u %u %u %-4u %u %u %u %c%c%c%c %u %.1fHz ",
- f->am, f->vibrato, f->sustain, f->key_scaling_rate,
- f->mod_multiple, f->level_key_scale, f->total_level, f->attack_rate,
- f->decay_rate, f->sustain_level, f->release_rate, f->key_on,
- f->octave, f->f_number, f->feedback, f->connection,
- f->waveform, f->ch_a?'*':'-', f->ch_b?'*':'-', f->ch_c?'*':'-',
- f->ch_d?'*':'-', i+1, freq);
- vga_write(tmp);
-
- f = &adlib_fm[i].car;
- vga_moveto(0,5+i*2+1);
- vga_write_color(i == selector && selectsub == 1 ? 0x70 : 0x1E);
- cc = sprintf(tmp,"%u %u %u %u %-2u %u %-2u %-2u %-2u %-2u %-2u %u CAR ",
- f->am, f->vibrato, f->sustain, f->key_scaling_rate,
- f->mod_multiple, f->level_key_scale, f->total_level, f->attack_rate,
- f->decay_rate, f->sustain_level, f->release_rate, f->waveform);
- vga_write(tmp);
- }
- }
-
- redrawln = 0;
- redraw = 0;
- }
-
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- loop = 0;
- }
- else if (c == 0x3B00) { /* F1 */
- for (i=0;i < adlib_fm_voices;i++) {
- adlib_fm[i].mod.key_on = 0;
- adlib_fm[i].car.key_on = 0;
- adlib_update_groupA0(i,&adlib_fm[i]);
- }
- redrawln = 1;
- }
- else if (c == 0x3C00) { /* F2 */
- if (adlib_flags & ADLIB_FM_OPL3) {
- shutdown_adlib_opl3();
- int10_setmode(3);
- redraw = 1;
- }
- }
- else if (c == 0x4400) { /* F10 */
- unsigned short op = adlib_voice_to_op[selector];
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
-
- vga_write("Choose an instrument to load into the channel:\n");
- vga_write(" 1. Violin 2. Piano 3. Harpsichord 4. Horn 5. Deep bass drum\n");
- vga_write(" 6. Small drum \n");
- vga_write_sync();
-
- c = getch();
-
- if (c == '1')
- adlib_fm[selector] =
- (adlib_flags & ADLIB_FM_OPL3 ?
- adlib_fm_preset_violin_opl3 : adlib_fm_preset_violin_opl2);
- else if (c == '2')
- adlib_fm[selector] = adlib_fm_preset_piano;
- else if (c == '3')
- adlib_fm[selector] = adlib_fm_preset_harpsichord;
- else if (c == '4')
- adlib_fm[selector] = adlib_fm_preset_horn;
- else if (c == '5')
- adlib_fm[selector] = adlib_fm_preset_deep_bass_drum;
- else if (c == '6')
- adlib_fm[selector] = adlib_fm_preset_small_drum;
-
- adlib_update_groupA0(selector,&adlib_fm[selector]);
- adlib_update_groupC0(selector,&adlib_fm[selector]);
- adlib_update_operator(op,&adlib_fm[selector].mod);
- adlib_update_operator(op+3,&adlib_fm[selector].car);
-
- redraw = 1;
- }
- else if (c == ' ') {
- adlib_fm[selector].mod.key_on ^= 1;
- adlib_update_groupA0(selector,&adlib_fm[selector]);
- redrawln=1;
- }
- else if (c == 'a') {
- if (hselect == 17) {
- struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_a ^= 1;
- adlib_update_groupC0(selector,&adlib_fm[selector]);
- }
- else {
- adlib_reg_bd.am_depth ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- }
- redrawln = 1;
- }
- else if (c == 'v') {
- adlib_reg_bd.vibrato_depth ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- redrawln = 1;
- }
- else if (c == 'r') {
- adlib_reg_bd.rythm_enable ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- redrawln = 1;
- }
- else if (c == 'b') {
- if (hselect == 17) {
- struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_b ^= 1;
- adlib_update_groupC0(selector,&adlib_fm[selector]);
- }
- else {
- adlib_reg_bd.bass_drum_on ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- }
- redrawln = 1;
- }
- else if (c == 's') {
- adlib_reg_bd.snare_drum_on ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- redrawln = 1;
- }
- else if (c == 't') {
- adlib_reg_bd.tom_tom_on ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- redrawln = 1;
- }
- else if (c == 'c') {
- if (hselect == 17) {
- struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_c ^= 1;
- adlib_update_groupC0(selector,&adlib_fm[selector]);
- }
- else {
- adlib_reg_bd.cymbal_on ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- }
- redrawln = 1;
- }
- else if (c == 'd') {
- if (hselect == 17) {
- struct adlib_fm_operator *f = &adlib_fm[selector].mod; f->ch_d ^= 1;
- adlib_update_groupC0(selector,&adlib_fm[selector]);
- }
- else {
- }
- redrawln = 1;
- }
- else if (c == 'h') {
- adlib_reg_bd.hi_hat_on ^= 1;
- adlib_update_bd(&adlib_reg_bd);
- redrawln = 1;
- }
- else if (c == 'z' || c == 'Z' || c == 'x' || c == 'X') {
- struct adlib_fm_operator *f;
- int dec = tolower(c) == 'z';
- unsigned short operator;
-
- switch (hselect) {
- case 11:selectsub = 0;
- break;
- }
-
- if (selectsub) f = &adlib_fm[selector].car;
- else f = &adlib_fm[selector].mod;
- operator = adlib_voice_to_op[selector] + (selectsub*3);
-
- switch (hselect) {
- case 0: f->am ^= 1; adlib_update_group20(operator,f); break;
- case 11: f->key_on ^= 1; adlib_update_groupA0(selector,&adlib_fm[selector]); break;
- case 1: f->vibrato ^= 1; adlib_update_group20(operator,f); break;
- case 2: f->sustain ^= 1; adlib_update_group20(operator,f); break;
- case 15: f->connection ^= 1; adlib_update_group20(operator,f); break;
- case 3: f->key_scaling_rate ^= 1; adlib_update_group20(operator,f); break;
-
- case 4: if (dec) f->mod_multiple--; else f->mod_multiple++;
- adlib_update_group20(operator,f); break;
- case 5: if (dec) f->level_key_scale--; else f->level_key_scale++;
- adlib_update_group40(operator,f); break;
- case 6: if (dec) f->total_level--; else f->total_level++;
- adlib_update_group40(operator,f); break;
- case 7: if (dec) f->attack_rate--; else f->attack_rate++;
- adlib_update_group60(operator,f); break;
- case 8: if (dec) f->decay_rate--; else f->decay_rate++;
- adlib_update_group60(operator,f); break;
- case 9: if (dec) f->sustain_level--; else f->sustain_level++;
- adlib_update_group80(operator,f); break;
- case 10: if (dec) f->release_rate--; else f->release_rate++;
- adlib_update_group80(operator,f); break;
- case 12: if (dec) f->octave--; else f->octave++;
- adlib_update_groupA0(selector,&adlib_fm[selector]); break;
- case 13: if (dec) f->f_number--; else f->f_number++;
- adlib_update_groupA0(selector,&adlib_fm[selector]); break;
- case 14: if (dec) f->feedback--; else f->feedback++;
- adlib_update_groupC0(selector,&adlib_fm[selector]); break;
- case 16: if (dec) f->waveform--; else f->waveform++;
- adlib_update_groupE0(operator,f); break;
- };
-
- redrawln=1;
- }
- else if (c == 0x4800) {
- if (selectsub && !(hselect >= 11 && hselect <= 15)) {
- selectsub = 0;
- redrawln = 1;
- }
- else if (selector > 0) {
- selectsub = !(hselect >= 11 && hselect <= 15);
- selector--;
- redrawln = 1;
- }
- }
- else if (c == 0x4B00) {
- if (hselect > 0) {
- hselect--;
- redrawln=1;
- }
- }
- else if (c == 0x4D00) {
- if (hselect < 17) {
- hselect++;
- redrawln=1;
- }
- }
- else if (c == 0x5000) {
- if (selectsub == 0 && !(hselect >= 11 && hselect <= 15)) {
- selectsub = 1;
- redrawln = 1;
- }
- else if ((selector+1) < adlib_fm_voices) {
- selectsub = 0;
- selector++;
- redrawln=1;
- }
- }
-
- }
- }
-
- shutdown_adlib();
- int10_setmode(3);
-
- return 0;
-}
-
+++ /dev/null
-option quiet system dos4g file dos386f/midi.obj library ../../hw/adlib/dos386f/adlib.lib library ../../hw/8259/dos386f/8259.lib library ../../hw/8254/dos386f/8254.lib library ../../hw/vga/dos386f/vgatty.lib library ../../hw/vga/dos386f/vga.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../windows/ntvdm/dos386f/ntvdmlib.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../windows/ntvdm/dos386f/ntvdmlib.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../windows/ntvdm/dos386f/ntvdmlib.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../windows/ntvdm/dos386f/ntvdmlib.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../hw/vga/dos386f/vga.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../windows/ntvdm/dos386f/ntvdmlib.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../windows/ntvdm/dos386f/ntvdmlib.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib library ../../windows/ntvdm/dos386f/ntvdmlib.lib library ../../hw/dos/dos386f/dos.lib library ../../hw/cpu/dos386f/cpu.lib name dos386f/midi.exe
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-/* apm.c
- *
- * Advanced Power Management BIOS library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * This library is intended for DOS programs that want to communicate with the APM
- * BIOS interface on PC systems made since about 1994. Note that on systems built
- * since 1999 you may want to use the ACPI BIOS instead, however that interface is
- * quite a bit more complex. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/apm/apm.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-
-struct apm_bios_ctx *apm_bios = NULL;
-
-#if TARGET_MSDOS == 32
-static void apm_bios_rm_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x0015
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-#endif
-
-void apm_bios_free() {
- if (apm_bios) free(apm_bios);
- apm_bios = NULL;
-}
-
-int apm_bios_probe() { /* 8.8 version */
- apm_bios_free();
-
- apm_bios = (struct apm_bios_ctx*)malloc(sizeof(*apm_bios));
- if (apm_bios == NULL) return 0;
- memset(apm_bios,0,sizeof(*apm_bios));
-
- apm_bios->version_want = 0x102;
- apm_bios->major_neg = 1;
- apm_bios->minor_neg = 0;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x5300; /* AH=0x53 A=0x00 */
- apm_bios_rm_call(&rc);
- if (!(rc.flags & 1)) { /* CF=0 */
- apm_bios->major = (rc.eax >> 8) & 0xFF;
- apm_bios->minor = (rc.eax & 0xFF);
- apm_bios->signature = (rc.ebx & 0xFFFF);
- apm_bios->flags = (rc.ecx & 0xFFFF);
- }
- }
-#else
- __asm {
- mov ah,0x53
- xor al,al
- xor bx,bx
- int 0x15
- jc err1
-#if defined(__LARGE__) || defined(__COMPACT__)
- push ds
- mov si,seg apm_bios ; we need DS = segment of apm_bios variable
- mov ds,si
- lds si,apm_bios ; DS:SI = apm_bios
-#else
- mov si,apm_bios
-#endif
- mov byte ptr [si+0],ah
- mov byte ptr [si+1],al
- mov word ptr [si+2],bx
- mov word ptr [si+4],cx
-#if defined(__LARGE__) || defined(__COMPACT__)
- pop ds
-#endif
-err1:
- }
-#endif
-
- return (apm_bios->signature == APM_PM_SIG);
-}
-
-void apm_bios_update_capabilities() {
- apm_bios->capabilities = 0;
- apm_bios->batteries = 0;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x5310;
- apm_bios_rm_call(&rc);
- if (!(rc.flags & 1)) { /* CF=0 */
- apm_bios->capabilities = rc.ecx & 0xFFFF;
- apm_bios->batteries = rc.ebx & 0xFF;
- }
- }
-#else
- {
- unsigned char bat=0,err=0;
- unsigned short cap=0;
-
- __asm {
- mov ax,0x5310
- xor bx,bx
- int 0x15
- jnc err1
- mov err,ah
-err1: mov bat,bl
- mov cap,cx
- }
-
- if (err == 0) {
- apm_bios->capabilities = cap;
- apm_bios->batteries = bat;
- }
- }
-#endif
-}
-
-/* FIXME: For the protected mode calls, this code needs to save AX, BX, CX, (E)SI, and (E)DI
- * which contain all the info needed for protected mode selectors */
-int apm_bios_connect(int n) {
- unsigned char err=0;
-
- if (apm_bios == NULL)
- return 0;
- if (n < APM_CONNECT_NONE || n > APM_CONNECT_32_PM)
- return 0;
- if (n == APM_CONNECT_NONE)
- n = 0x04; /* AH=0x04 disconnect function */
-
- /* NTS: for now, only the real-mode interface */
- if (n == APM_CONNECT_16_PM || n == APM_CONNECT_32_PM)
- return 0; /* anything but real mode not supported */
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x5300+n; /* AH=0x53 A=0x01-0x04 */
- apm_bios_rm_call(&rc);
- if (rc.flags & 1) { /* CF=1 */
- err = (rc.eax >> 8) & 0xFF;
- }
- }
-#else
- __asm {
- mov ah,0x53
- mov al,byte ptr n
- xor bx,bx
- int 0x15
- jnc err1
- mov err,ah
-err1:
- }
-#endif
-
- /* translate "n" back to enum */
- if (n == 0x04) n = APM_CONNECT_NONE;
-
- /* success: BIOS returns success, or disconnect (AH=4) command says "not connected" */
- if (err == 0x00 || (err == 0x03 && n == 0x04)) {
- apm_bios->connection = n;
- }
- else if (err == 0x02) { /* err code 2 real mode interface connected */
- apm_bios->connection = APM_CONNECT_REALMODE;
- }
- else if (err == 0x05) { /* err code 5 16-bit prot mode interface connected */
- apm_bios->connection = APM_CONNECT_16_PM;
- }
- else if (err == 0x07) { /* err code 2 32-bit prot mode interface connected */
- apm_bios->connection = APM_CONNECT_32_PM;
- }
-
- /* if transitioning to an interface, negotiate a newer API */
- if (err == 0x00 && n > APM_CONNECT_NONE) {
- unsigned int neg_ver = apm_bios->version_want;
- unsigned short ww = 0;
-
- apm_bios->major_neg = 1;
- apm_bios->minor_neg = 0;
- if (apm_bios->major == 1 && apm_bios->minor != 0 && neg_ver >= 0x101 && neg_ver <= 0x1FF) {
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x530E;
- rc.ecx = neg_ver;
- apm_bios_rm_call(&rc);
- if (!(rc.flags & 1)) { /* CF=0 */
- ww = rc.eax & 0xFFFF;
- }
- }
-#else
- __asm {
- mov ax,0x530E
- xor bx,bx
- mov cx,neg_ver
- int 0x15
- jc err2
- mov ww,ax
-err2:
- }
-#endif
-
- if (ww >= 0x101 && ww <= 0x1FF) {
- apm_bios->major_neg = ww >> 8;
- apm_bios->minor_neg = ww & 0xFF;
- }
- }
- }
-
- if (n > APM_CONNECT_NONE && apm_bios->connection == APM_CONNECT_NONE)
- apm_bios_update_capabilities();
-
- apm_bios->last_error = err;
- return (apm_bios->connection == n);
-}
-
-int apm_bios_cpu_busy() {
- unsigned char err=0;
-
-#if TARGET_MSDOS == 32
-{
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x5306;
- apm_bios_rm_call(&rc);
- if (rc.flags & 1) { /* CF=1 */
- err = (rc.eax >> 8) & 0xFF;
- }
-}
-#else
-__asm {
- mov ax,0x5306
- int 0x15
- jnc err1
- mov err,ah
-err1:
-}
-#endif
-
- return (err == 0);
-}
-
-int apm_bios_cpu_idle() {
- unsigned char err=0;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x5305;
- apm_bios_rm_call(&rc);
- if (rc.flags & 1) { /* CF=1 */
- err = (rc.eax >> 8) & 0xFF;
- }
- }
-#else
- __asm {
- mov ax,0x5305
- int 0x15
- jnc err1
- mov err,ah
-err1:
- }
-#endif
-
- return (err == 0);
-}
-
-signed long apm_bios_pm_evnet() {
- unsigned short ev=0,info=0;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x530B;
- apm_bios_rm_call(&rc);
- if (!(rc.flags & 1)) { /* CF=0 */
- ev = rc.ebx & 0xFFFF;
- info = rc.ecx & 0xFFFF;
- }
- }
-#else
- __asm {
- mov ax,0x530B
- int 0x15
- jc err1
- mov ev,bx
- mov info,cx
-err1:
- }
-#endif
-
- return (ev == 0 ? -1LL : (unsigned long)ev);
-}
-
-void apm_bios_update_status() {
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x530A;
- apm_bios_rm_call(&rc);
- if (!(rc.flags & 1)) { /* CF=0 */
- apm_bios->status_ac = (rc.ebx >> 8) & 0xFF;
- apm_bios->status_battery = (rc.ebx & 0xFF);
- apm_bios->status_battery_flag = (rc.ecx >> 8) & 0xFF;
- apm_bios->status_battery_life = (rc.ecx & 0xFF);
- apm_bios->status_battery_time = rc.edx & 0xFFFF;
- }
- }
-#else
- {
- unsigned short b=0,c=0,d=0;
-
- __asm {
- mov ax,0x530A
- int 0x15
- jc err1
- mov b,bx
- mov c,cx
- mov d,dx
-err1:
- }
-
- apm_bios->status_ac = (b >> 8) & 0xFF;
- apm_bios->status_battery = (b & 0xFF);
- apm_bios->status_battery_flag = (c >> 8) & 0xFF;
- apm_bios->status_battery_life = (c & 0xFF);
- apm_bios->status_battery_time = d & 0xFFFF;
- }
-#endif
-}
-
-int apm_bios_power_state(unsigned short state) {
- unsigned char err=0;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x5307;
- rc.ebx = 0x0001;
- rc.ecx = state;
- apm_bios_rm_call(&rc);
- if (rc.flags & 1) { /* CF=0 */
- err = (rc.eax >> 8) & 0xFF;
- }
- }
-#else
- {
- __asm {
- mov ax,0x5307
- mov bx,0x0001
- mov cx,state
- int 0x15
- jnc err1
- mov err,ah
-err1:
- }
- }
-#endif
-
- return (err == 0);
-}
-
+++ /dev/null
-/* apm.h
- *
- * Advanced Power Management BIOS library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-
-#define APM_PM_SIG 0x504D /* 'PM' */
-
-enum {
- APM_CONNECT_NONE=0,
- APM_CONNECT_REALMODE=1,
- APM_CONNECT_16_PM=2,
- APM_CONNECT_32_PM=3
-};
-
-enum {
- APM_POWER_STANDBY=0x0001,
- APM_POWER_SUSPEND=0x0002,
- APM_POWER_OFF=0x0003
-};
-
-#pragma pack(push,1)
-struct apm_bios_ctx {
- /* do NOT move these structure members---the assembly language requires them */
- unsigned char major,minor; /* +0, +1 */
- unsigned short signature; /* +2 */
- unsigned short flags; /* +4 */
-#define APM_FL_16BIT_PM (1U << 0U) /* 16-bit protected mode interface supported */
-#define APM_FL_32BIT_PM (1U << 1U) /* 32-bit protected mode interface supported */
-#define APM_FL_CPU_IDLE_SLOWS (1U << 2U) /* CPU idle call slows processor clock */
-#define APM_FL_PM_DISABLED (1U << 3U) /* Power Management Disabled */
-#define APM_FL_PM_DISENGAGED (1U << 4U) /* Power Management Disengaged */
- /* -------------------------------------------------- */
- unsigned char connection; /* last known connection to the BIOS */
- unsigned char last_error;
- unsigned short version_want; /* which APM BIOS the caller wants */
- unsigned char major_neg,minor_neg; /* negotiated API with BIOS */
- unsigned short capabilities;
- unsigned char batteries;
- /* status */
- unsigned char status_ac,status_battery;
- unsigned char status_battery_flag,status_battery_life;
- unsigned short status_battery_time;
-};
-#pragma pack(pop)
-
-extern struct apm_bios_ctx *apm_bios;
-
-#define apm_bios_disconnect() apm_bios_connect(APM_CONNECT_NONE)
-
-void apm_bios_free();
-int apm_bios_probe();
-int apm_bios_cpu_busy();
-int apm_bios_cpu_idle();
-int apm_bios_connect(int n);
-void apm_bios_update_status();
-signed long apm_bios_pm_evnet();
-void apm_bios_update_capabilities();
-int apm_bios_power_state(unsigned short state);
-
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_APM_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = apm.c
-OBJS = $(SUBDIR)$(HPS)apm.obj $(SUBDIR)$(HPS)apm.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_APM_LIB): $(OBJS)
- wlib -q -b -c $(HW_APM_LIB) -+$(SUBDIR)$(HPS)apm.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_APM_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_APM_LIB) $(HW_APM_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_APM_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-Support routines for the Advanced Power Management BIOS interface.
-
-If you have a computer that supports it, your DOS program can make
-use of these functions as you need to.
-
+++ /dev/null
-/* test.c
- *
- * Advanced Power Management BIOS test program.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * This program allows you to play with your APM BIOS interface. It should
- * not cause harm, but this code is provided under no warranty express or
- * implied. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/apm/apm.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-#include <hw/dos/doswin.h>
-
-static void help() {
- fprintf(stderr,"test [options] [action]\n");
- fprintf(stderr,"Test program for APM BIOS functions\n");
-#if TARGET_MSDOS == 32
- fprintf(stderr,"32-bit protected mode build\n");
-#else
- fprintf(stderr,"16-bit real mode ");
-# if defined(__LARGE__)
- fprintf(stderr,"large");
-# elif defined(__MEDIUM__)
- fprintf(stderr,"medium");
-# elif defined(__COMPACT__)
- fprintf(stderr,"compact");
-# else
- fprintf(stderr,"small");
-# endif
- fprintf(stderr," build\n");
-#endif
- fprintf(stderr," /h help\n");
- fprintf(stderr," /v1.<n> Use APM v1.N interface (v1.0, v1.1, or v1.2)\n");
- fprintf(stderr," /vn Don't connect to APM\n");
- fprintf(stderr," /nd Don't disconnect after call\n");
- fprintf(stderr," /if:<n> Use interface (real");
-#if TARGET_MSDOS == 32
- fprintf(stderr,", 16pm, 32pm)\n");
-#else
- fprintf(stderr,")\n");
-#endif
- fprintf(stderr,"Commands\n");
- fprintf(stderr," cpu-idle\n");
- fprintf(stderr," cpu-busy\n");
- fprintf(stderr," events\n");
- fprintf(stderr," status\n");
- fprintf(stderr," standby\n");
- fprintf(stderr," suspend\n");
- fprintf(stderr," off\n");
-}
-
-#define REQ_VER_NONE 1
-int main(int argc,char **argv) {
- unsigned int req_ver = 0;
- unsigned int dont_disconnect = 0;
- unsigned int req_mode = APM_CONNECT_NONE;
- const char *action = NULL;
- int i;
-
- for (i=1;i < argc;) {
- const char *a = argv[i++];
-
- if (*a == '/' || *a == '-') {
- do { a++; } while (*a == '/' || *a == '-');
-
- if (!strncmp(a,"v1.",3)) {
- a += 3;
- req_ver = 0x100 + (atoi(a) & 0xFF);
- }
- else if (!strcmp(a,"vn")) {
- req_ver = REQ_VER_NONE;
- }
- else if (!strcmp(a,"nd")) {
- dont_disconnect = 1;
- }
- else if (!strcmp(a,"h") || !strcmp(a,"help")) {
- help();
- }
- else if (!strncmp(a,"if:",3)) {
- a += 3;
- if (!strcmp(a,"real"))
- req_mode = APM_CONNECT_REALMODE;
- else if (!strcmp(a,"16pm"))
- req_mode = APM_CONNECT_16_PM;
- else if (!strcmp(a,"32pm"))
- req_mode = APM_CONNECT_32_PM;
- else {
- fprintf(stderr,"Unknown interface %s\n",a);
- return 1;
- }
- }
- else {
- fprintf(stderr,"Unknown param '%s'\n",a);
- help();
- return 1;
- }
- }
- else if (action == NULL) {
- action = a;
- }
- else {
- fprintf(stderr,"Unknown param\n");
- return 1;
- }
- }
-
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!probe_8259()) {
- printf("Cannot init 8259 PIC\n");
- return 1;
- }
- probe_dos();
- detect_windows();
- if (!apm_bios_probe()) {
- printf("APM BIOS not found\n");
- return 1;
- }
-
- if (req_mode == APM_CONNECT_NONE)
- req_mode = APM_CONNECT_REALMODE;
-
- printf("APM BIOS v%u.%u: ",apm_bios->major,apm_bios->minor);
- if (apm_bios->flags & APM_FL_16BIT_PM) printf("[16-bit pm] ");
- if (apm_bios->flags & APM_FL_32BIT_PM) printf("[32-bit pm] ");
- if (apm_bios->flags & APM_FL_CPU_IDLE_SLOWS) printf("[cpu-idle-slow] ");
- if (apm_bios->flags & APM_FL_PM_DISABLED) printf("[disabled] ");
- if (apm_bios->flags & APM_FL_PM_DISENGAGED) printf("[disengaged] ");
- printf("\n");
-
- if (req_ver >= 0x100) apm_bios->version_want = req_ver;
-
- if (req_ver != REQ_VER_NONE) {
- if (!apm_bios_connect(req_mode)) {
- fprintf(stderr,"Failed to connect to APM BIOS (last=0x%02X)\n",apm_bios->last_error);
- return 1;
- }
-
- printf("Connected to APM BIOS v%u.%u interface\n",apm_bios->major_neg,apm_bios->minor_neg);
- printf(" batteries: %u\n",apm_bios->batteries);
- printf(" capabilities:\n");
- if (apm_bios->capabilities & 1) printf(" Can enter global standby state\n");
- if (apm_bios->capabilities & 2) printf(" Can enter global suspend state\n");
- if (apm_bios->capabilities & 4) printf(" Resume timer will wake from standby\n");
- if (apm_bios->capabilities & 8) printf(" Resume timer will wake from suspend\n");
- if (apm_bios->capabilities & 16) printf(" Resume on ring will wake from standby\n");
- if (apm_bios->capabilities & 32) printf(" Resume on ring will wake from suspend\n");
- if (apm_bios->capabilities & 64) printf(" PCMCIA ring indicator will wake up from standby\n");
- if (apm_bios->capabilities & 128) printf(" PCMCIA ring indicator will wake up from suspend\n");
- printf("\n");
- }
-
- if (action == NULL) {
- }
- else if (!strcmp(action,"cpu-idle")) {
- printf("Issuing CPU idle command\n");
- if (!apm_bios_cpu_idle())
- fprintf(stderr,"CPU Idle failed\n");
- }
- else if (!strcmp(action,"cpu-busy")) {
- printf("Issuing CPU busy command\n");
- if (!apm_bios_cpu_busy())
- fprintf(stderr,"CPU Busy failed\n");
- }
- else if (!strcmp(action,"events")) {
- while (1) {
- signed long ev = apm_bios_pm_evnet();
- if (ev >= 0LL) {
- printf("Event 0x%04X\n",(unsigned int)ev);
- }
-
- if (kbhit()) {
- if (getch() == 27) break;
- }
- }
- }
- else if (!strcmp(action,"status")) {
- apm_bios_update_status();
-
- printf("AC=0x%X Batt=0x%X BattFlag=0x%X BattPercent=%u BattLife=%u%s\n",
- apm_bios->status_ac,
- apm_bios->status_battery,
- apm_bios->status_battery_flag,
- apm_bios->status_battery_life,
- apm_bios->status_battery_time&0x7FFF,
- (apm_bios->status_battery_time&0x8000)?"m":"s");
- }
- else if (!strcmp(action,"standby")) {
- if (!apm_bios_power_state(APM_POWER_STANDBY))
- fprintf(stderr,"Unable to set power state\n");
- }
- else if (!strcmp(action,"suspend")) {
- if (!apm_bios_power_state(APM_POWER_SUSPEND))
- fprintf(stderr,"Unable to set power state\n");
- }
- else if (!strcmp(action,"off")) {
- if (!apm_bios_power_state(APM_POWER_OFF))
- fprintf(stderr,"Unable to set power state\n");
- }
-
- if (req_ver != REQ_VER_NONE && !dont_disconnect) {
- if (!apm_bios_connect(APM_CONNECT_NONE)) {
- fprintf(stderr,"Failed to disconnect\n");
- }
-
- printf("Disconnected APM BIOS\n");
- }
-
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-/* biosdisk.c
- *
- * INT 13h BIOS disk library.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * A library to deal with and use the INT 13h BIOS interface. It
- * wraps some functions to help deal with geometry translation,
- * DMA boundary issues, switching to/from protected mode, etc. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/biosdisk/biosdisk.h>
-
-#if TARGET_MSDOS == 32
-/* the protected mode version of this code needs a real-mode segment to transfer data */
-static uint16_t biosdisk_bufseg = 0;
-static void* biosdisk_buf = NULL;
-#define biosdisk_bufsize 16384
-
-static int biosdisk_buf_init() {
- uint32_t ofs;
-
- if (biosdisk_bufseg == 0) {
- biosdisk_buf = dpmi_alloc_dos(biosdisk_bufsize,&biosdisk_bufseg);
- if (biosdisk_buf == NULL) return 0;
-
- /* if that buffer crosses a 64KB boundary then we need to alloc another */
- ofs = (uint32_t)biosdisk_buf;
- if ((ofs & 0xFFFF0000UL) != ((ofs + biosdisk_bufsize - 1) & 0xFFFF0000UL)) {
- uint16_t p2seg=0;
- void *p2;
-
- p2 = dpmi_alloc_dos(biosdisk_bufsize,&p2seg);
- if (p2 == NULL) {
- dpmi_free_dos(biosdisk_bufseg);
- biosdisk_bufseg = 0;
- biosdisk_buf = NULL;
- return 0;
- }
-
- /* if that buffer crosses a 64KB boundary then give up */
- ofs = (uint32_t)p2;
- if ((ofs & 0xFFFF0000UL) != ((ofs + biosdisk_bufsize - 1) & 0xFFFF0000UL)) {
- dpmi_free_dos(biosdisk_bufseg);
- dpmi_free_dos(p2seg);
- biosdisk_bufseg = 0;
- biosdisk_buf = NULL;
- return 0;
- }
-
- dpmi_free_dos(biosdisk_bufseg);
- biosdisk_bufseg = p2seg;
- biosdisk_buf = p2;
- }
- }
-
- return (biosdisk_bufseg != 0);
-}
-
-static void biosdisk_buf_free() {
- if (biosdisk_bufseg != 0) {
- dpmi_free_dos(biosdisk_bufseg);
- biosdisk_bufseg = 0;
- biosdisk_buf = NULL;
- }
-}
-#else
-/* 16-bit real mode: if the calling program attempts a read spanning a DMA boundary we have a "bounce buffer" for that */
-static void far* biosdisk_bounce = NULL;
-#define biosdisk_bounce_size 4096
-
-static int biosdisk_bounce_init() {
- uint32_t ofs;
-
- if (biosdisk_bounce == NULL) {
- biosdisk_bounce = _fmalloc(biosdisk_bounce_size);
- if (biosdisk_bounce == NULL) return 0;
-
- /* but wait--we need to ensure the buffer does not cross a 64KB boundary */
- ofs = ((uint32_t)FP_SEG(biosdisk_bounce) << 4UL) + ((uint32_t)FP_OFF(biosdisk_bounce));
- if ((ofs & 0xFFFF0000UL) != ((ofs + 0xFFFUL) & 0xFFFF0000UL)) {
- void far *p2 = _fmalloc(biosdisk_bounce_size);
- if (p2 == NULL) {
- _ffree(biosdisk_bounce);
- biosdisk_bounce = NULL;
- return 0;
- }
-
- /* and this new buffer doesn't cross either, right? */
- ofs = ((uint32_t)FP_SEG(p2) << 4UL) + ((uint32_t)FP_OFF(p2));
- if ((ofs & 0xFFFF0000UL) != ((ofs + 0xFFFUL) & 0xFFFF0000UL)) {
- _ffree(biosdisk_bounce);
- biosdisk_bounce = NULL;
- _ffree(p2);
- return 0;
- }
-
- _ffree(biosdisk_bounce);
- biosdisk_bounce = p2;
- }
- }
-
- return (biosdisk_bounce != NULL);
-}
-
-static void biosdisk_bounce_free() {
- if (biosdisk_bounce != NULL) _ffree(biosdisk_bounce);
- biosdisk_bounce = NULL;
-}
-#endif
-
-void biosdisk_free_resources() {
-#if TARGET_MSDOS == 32
- biosdisk_buf_free();
-#else
- biosdisk_bounce_free();
-#endif
-}
-
-#if TARGET_MSDOS == 32
-static void biosdisk_realmode_13_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x0013
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-#endif
-
-int biosdisk_classic_get_geometry(struct biosdisk_drive *d,uint8_t index) {
-#if TARGET_MSDOS == 32
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x0800;
- rc.edx = index;
- rc.edi = 0;
- rc.es = 0;
- biosdisk_realmode_13_call(&rc);
- if (rc.flags & 1) return 0; /* if CF=1 */
- if (((rc.eax >> 8)&0xFF) != 0) return 0; /* if AH != 0 */
-
- d->index = index;
- d->sectors_per_track = (rc.ecx & 63);
- d->cylinders = (((rc.ecx >> 8) & 0xFF) | (((rc.ecx >> 6) & 3) << 8)) + 1;
- d->heads = ((rc.edx >> 8) & 0xFF) + 1;
- d->bytes_per_sector = 512;
- d->total_sectors = (uint64_t)d->sectors_per_track * (uint64_t)d->cylinders * (uint64_t)d->heads;
- return 1;
-#else
- uint8_t last_head=0;
- uint16_t trksect=0;
- uint8_t retc=0xFF;
-
- __asm {
- mov ah,8
- mov dl,index
- push es
- push di
- xor di,di
- mov es,di
- int 0x13
- pop di
- pop es
- jc call1
- mov retc,ah
- mov last_head,dh
- mov trksect,cx
-call1:
- }
-
- if (retc != 0)
- return 0;
-
- d->index = index;
- d->sectors_per_track = (trksect & 63);
- d->cylinders = ((trksect >> 8) | (((trksect >> 6) & 3) << 8)) + 1;
- d->heads = last_head + 1;
- d->bytes_per_sector = 512;
- d->total_sectors = (uint64_t)d->sectors_per_track * (uint64_t)d->cylinders * (uint64_t)d->heads;
- return 1;
-#endif
-}
-
-int biosdisk_check_extensions(struct biosdisk_drive *d,uint8_t index) {
-#if TARGET_MSDOS == 32
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4100;
- rc.edx = index;
- rc.ebx = 0x55AA;
- biosdisk_realmode_13_call(&rc);
- if (rc.flags & 1) return 0; /* if CF=1 */
- if ((rc.ebx & 0xFFFF) != 0xAA55) return 0;
- d->extended = 1;
- d->edd_support = (rc.ecx & 4) ? 1 : 0;
- d->ext_packet_access = (rc.ecx & 1) ? 1 : 0;
- d->drive_locking_eject = (rc.ecx & 2) ? 1 : 0;
- return 1;
-#else
- uint8_t retc=0xFF;
- uint16_t flags=0;
-
- __asm {
- mov ah,0x41
- mov dl,index
- mov bx,0x55AA
- int 0x13
- jc call1
- cmp bx,0xAA55
- jnz call1
- mov retc,ah
- mov flags,cx
-call1:
- }
-
- if (retc == 0xFF)
- return 0;
-
- d->extended = 1;
- d->edd_support = (flags & 4) ? 1 : 0;
- d->ext_packet_access = (flags & 1) ? 1 : 0;
- d->drive_locking_eject = (flags & 2) ? 1 : 0;
- return 1;
-#endif
-}
-
-int biosdisk_edd_get_geometry(struct biosdisk_drive *d,uint8_t index) {
-#if TARGET_MSDOS == 32
- unsigned char *tmp;
-
- if (!biosdisk_buf_init())
- return 0;
-
- tmp = biosdisk_buf;
- memset(tmp,0,sizeof(tmp));
- *((uint16_t*)(tmp+0x00)) = 0x1E;
-
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4800;
- rc.edx = index;
- rc.esi = ((uint32_t)biosdisk_buf) & 0xF;
- rc.ds = ((uint32_t)biosdisk_buf) >> 4;
- biosdisk_realmode_13_call(&rc);
- if (rc.flags & 1) return 0; /* if CF=1 */
- if (((rc.eax >> 8) & 0xFF) != 0) return 0;
- }
-#else
- unsigned char tmp[0x40],retc=0;
- void *p_tmp = (void*)tmp; /* this bullshit would be unnecessary if Watcom's inline assembler could just resolve the address of a stack variable */
-
- memset(tmp,0,sizeof(tmp));
- *((uint16_t*)(tmp+0x00)) = 0x1E;
-
- __asm {
- mov ah,0x48
- mov dl,index
- mov si,word ptr p_tmp
-#ifdef __LARGE__
- push ds
- mov ds,word ptr p_tmp+2
-#endif
- int 0x13
- jnc call1
-#ifdef __LARGE__
- pop ds
-#endif
- mov retc,ah
-call1:
- }
-
- if (retc != 0)
- return 0;
-#endif
-
- d->index = index;
- d->sectors_per_track = *((uint32_t*)(tmp+0x0C));
- d->cylinders = *((uint32_t*)(tmp+0x04));
- d->heads = *((uint32_t*)(tmp+0x08));
- d->bytes_per_sector = *((uint16_t*)(tmp+0x18));
- d->total_sectors = *((uint64_t*)(tmp+0x10)); /* NTS: This is often the TRUE geometry. Most BIOSes intentionally max out the C/H/S from this ioctl at 16383/16/63 */
-
- /* sanity checking: For CD-ROM drives (yes, they do show up through this interface!) the BIOS
- * will often return CHS 0/0/0 and 0 total sectors (Virtual PC) or 0xFFFF/0xFFFF/0xFFFF CHS and
- * 0xFFFFFFFFFFFFFFFF total sectors (VirtualBox). We have to filter our return values a bit
- * to make disk I/O work regardless */
- if (d->bytes_per_sector == 2048) {
- if (d->cylinders == 0 || d->cylinders == (int16_t)0xFFFF) d->cylinders = 16383;
- if (d->sectors_per_track == 0 || d->sectors_per_track == (int16_t)0xFFFF) d->sectors_per_track = 63;
- if (d->heads == 0 || d->heads == (int16_t)0xFFFF) d->heads = 16;
- if (d->total_sectors == 0 || d->total_sectors == 0xFFFFFFFFFFFFFFFFULL)
- d->total_sectors = 0;
- }
-
- return 1;
-}
-
-int biosdisk_get_info(struct biosdisk_drive *d,uint8_t index,uint8_t flags) {
- memset(d,0,sizeof(*d));
- d->heads = d->cylinders = d->sectors_per_track = -1;
- if (index & 0x80) {
- if ((flags & BIOSDISK_EXTENDED) && biosdisk_check_extensions(d,index) && d->edd_support && biosdisk_edd_get_geometry(d,index))
- return 1;
- else {
- /* if I can't get the geometry through extensions then I might as well not use them */
- d->ext_packet_access = 0;
- if (biosdisk_classic_get_geometry(d,index))
- return 1;
- }
- }
-
- /* TODO: floppy interfaces */
-
- return 0;
-}
-
-/* INT 13H disk read, C/H/S style */
-static int biosdisk_std_read(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num) {
- unsigned int C,H,S,srd,segv,offv,segrem,pair;
- unsigned char drv = d->index;
- unsigned char err,erc;
- uint32_t sec32,physo;
-#if TARGET_MSDOS == 16
- int crossdma = 0;
-#endif
- int ret = 0;
-
-#if TARGET_MSDOS == 32
- if (!biosdisk_buf_init())
- return 0;
-#else
- /* normalize pointer */
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- buffer = MK_FP(physo>>4,physo&0xF);
-#endif
-
- d->dma_crossed = 0;
- while (num > 0) {
- if (d->total_sectors != 0ULL && sector >= d->total_sectors)
- return 0;
- if (sector >= (1024ULL*255ULL*63ULL)) /* if this goes beyond the max C/H/S 8GB limit... */
- return 0;
-
- sec32 = (uint32_t)sector;
-
- S = (unsigned int)(sec32 % ((uint32_t)d->sectors_per_track));
- sec32 /= (uint32_t)d->sectors_per_track;
-
- H = (unsigned int)(sec32 % ((uint32_t)d->heads));
- sec32 /= (uint32_t)d->heads;
-
- C = (unsigned int)sec32;
-
- srd = d->sectors_per_track - S;
- if (srd > ((unsigned int)num)) srd = (unsigned int)num;
-
-#if TARGET_MSDOS == 32
- segv = (unsigned int)((size_t)biosdisk_buf >> 4);
- offv = (unsigned int)((size_t)biosdisk_buf & 0xF);
-#else
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
-#endif
-
- /* TODO: If the request crosses a 64KB boundary, then use an alternative buffer and memcpy it back */
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- if ((physo & 0xFFFF0000ULL) != ((physo + ((uint32_t)d->bytes_per_sector) - (uint32_t)1) & 0xFFFF0000ULL)) {
-#if TARGET_MSDOS == 32
- fprintf(stderr,"DMA boundary crossing in 32-bit protected mode! This shouldn't happen!\n");
- fprintf(stderr,"The bounce buffer is not supposed to have been straddling a DMA boundary\n");
- abort();
- break;
-#else
- if (!biosdisk_bounce_init()) {
- fprintf(stderr,"Error: cannot alloc bios disk bounce for DMA boundary read\n");
- break;
- }
-
- srd = 1;
- crossdma = 1;
- d->dma_crossed = 1;
- segv = FP_SEG(biosdisk_bounce);
- offv = FP_OFF(biosdisk_bounce);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- if ((physo & 0xFFFF0000ULL) != ((physo + ((uint32_t)d->bytes_per_sector) - (uint32_t)1) & 0xFFFF0000ULL)) {
- fprintf(stderr,"Error: bounce buffer also crosses DMA boundary---what's the point?\n");
- break;
- }
-#endif
- }
-
- /* how many can we read without crossing 64KB? */
- segrem = (0x10000 - (physo & 0xFFFFUL)) / d->bytes_per_sector;
- assert(segrem != 0); /* because the above code should have caught this! */
- if (srd > segrem) srd = segrem;
-
- assert(S < 63);
- assert(H < 256);
- assert(C < 1024);
- pair = (S + 1) | (((C >> 8) & 3) << 6) | ((C & 0xFF) << 8);
-
- /* normalize the segment offset */
- segv = physo >> 4;
- offv = physo & 0xF;
- err = erc = 0;
-
- /* carry out the read */
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x0200 | srd;
- rc.ebx = offv;
- rc.ecx = pair;
- rc.edx = drv | (H << 8);
- rc.es = segv;
- biosdisk_realmode_13_call(&rc);
- erc = (rc.eax >> 8) & 0xFF;
- if ((rc.flags & 1) == 0) err = rc.eax & 0xFF;
- }
-#else
- __asm {
- push es
- mov ah,0x02
- mov al,byte ptr srd
- mov dh,byte ptr H
- mov dl,drv
- mov cx,pair
- mov bx,segv
- mov es,bx
- mov bx,offv
- int 0x13
- pop es
- mov erc,ah
- jc call1
- mov err,al
-call1:
- }
-#endif
- if (erc != 0)
- break;
- if (err == 0 || err > srd) /* filter out BIOSes that return inane responses when AL should be sector count */
- err = srd; /* Compaq Elite laptop BIOS returns AX=0x0050 when asked to read one sector, for example */
-
- num -= err;
- ret += err;
- sector += (uint64_t)err;
-#if TARGET_MSDOS == 32
- memcpy(buffer,biosdisk_buf,err * d->bytes_per_sector);
- buffer = (void*)((char*)buffer + (err * d->bytes_per_sector));
-#else
- /* need to copy from bounce buffer */
- if (crossdma) _fmemcpy(buffer,biosdisk_bounce,d->bytes_per_sector);
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- physo += (err * d->bytes_per_sector);
- buffer = MK_FP(physo>>4,physo&0xF);
-#endif
- }
-
- return ret;
-}
-
-/* NOTES:
- * Microsoft Virtual PC 2007: For some reason the BIOS stubbornly returns 0x20 (controller failure) and does not allow us to read
- * the CD-ROM drive. */
-static int biosdisk_ext_read(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num) {
- unsigned char drv = d->index;
- unsigned int srd,segv,offv;
- unsigned char pkt[0x10];
- unsigned char err;
- uint32_t physo;
- int ret = 0;
-
-#if TARGET_MSDOS == 32
- if (!biosdisk_buf_init())
- return 0;
-#endif
-
- while (num > 0) {
- if (d->total_sectors != 0ULL && sector >= d->total_sectors)
- return 0;
-
- srd = (unsigned int)num;
-#if TARGET_MSDOS == 32
- if (srd > ((biosdisk_bufsize - 0x20) / d->bytes_per_sector)) srd = ((biosdisk_bufsize - 0x20) / d->bytes_per_sector);
-#else
- if (srd > ((0xFF00 - 0x20) / d->bytes_per_sector)) srd = ((0xFF00 - 0x20) / d->bytes_per_sector);
-#endif
- err = 0x00;
-
-#if TARGET_MSDOS == 32
- segv = (unsigned int)((size_t)((char*)biosdisk_buf + 0x20) >> 4);
- offv = (unsigned int)((size_t)((char*)biosdisk_buf + 0x20) & 0xF);
-#else
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
-#endif
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- pkt[0] = 0x10;
- pkt[1] = 0;
- *((uint16_t*)(pkt+2)) = srd;
- *((uint16_t*)(pkt+4)) = physo & 0xF;
- *((uint16_t*)(pkt+6)) = physo >> 4;
- *((uint64_t*)(pkt+8)) = sector;
-
- /* carry out the read */
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4200;
- rc.edx = drv;
- rc.esi = ((uint32_t)biosdisk_buf) & 0xF;
- rc.ds = ((uint32_t)biosdisk_buf) >> 4;
- memcpy(biosdisk_buf,pkt,0x10);
- biosdisk_realmode_13_call(&rc);
- if (rc.flags & 1) err = (rc.eax >> 8) & 0xFF;
- else err = 0;
- }
-#else
- segv = FP_SEG(pkt);
- offv = FP_OFF(pkt);
- __asm {
- push ds
- mov ah,0x42
- mov dl,drv
- mov ds,segv
- mov si,offv
- int 0x13
- pop ds
- jnc call1
- mov err,ah
-call1:
- }
-#endif
- if (err != 0)
- break;
-
- num -= srd;
- ret += srd;
- sector += (uint64_t)srd;
-#if TARGET_MSDOS == 32
- memcpy(buffer,(char*)biosdisk_buf + 0x20,srd * d->bytes_per_sector);
- buffer = (void*)((char*)buffer + (srd * d->bytes_per_sector));
-#else
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- physo += (srd * d->bytes_per_sector);
- buffer = MK_FP(physo>>4,physo&0xF);
-#endif
- }
-
- return ret;
-}
-
-int biosdisk_read(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num) {
- if (num <= 0)
- return 0;
-
- if (d->ext_packet_access)
- return biosdisk_ext_read(d,buffer,sector,num);
- else if (d->sectors_per_track > 0)
- return biosdisk_std_read(d,buffer,sector,num);
- return 0;
-}
-
-/* INT 13H disk write, C/H/S style */
-static int biosdisk_std_write(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num) {
- unsigned int C,H,S,srd,segv,offv,segrem,pair;
- unsigned char drv = d->index;
- unsigned char err,erc;
- uint32_t sec32,physo;
-#if TARGET_MSDOS == 16
- int crossdma = 0;
-#endif
- int ret = 0;
-
-#if TARGET_MSDOS == 32
- if (!biosdisk_buf_init())
- return 0;
-#else
- /* normalize pointer */
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- buffer = MK_FP(physo>>4,physo&0xF);
-#endif
-
- d->dma_crossed = 0;
- while (num > 0) {
- if (d->total_sectors != 0ULL && sector >= d->total_sectors)
- return 0;
- if (sector >= (1024ULL*255ULL*63ULL)) /* if this goes beyond the max C/H/S 8GB limit... */
- return 0;
-
- sec32 = (uint32_t)sector;
-
- S = (unsigned int)(sec32 % ((uint32_t)d->sectors_per_track));
- sec32 /= (uint32_t)d->sectors_per_track;
-
- H = (unsigned int)(sec32 % ((uint32_t)d->heads));
- sec32 /= (uint32_t)d->heads;
-
- C = (unsigned int)sec32;
-
- srd = d->sectors_per_track - S;
- if (srd > ((unsigned int)num)) srd = (unsigned int)num;
-
-#if TARGET_MSDOS == 32
- segv = (unsigned int)((size_t)biosdisk_buf >> 4);
- offv = (unsigned int)((size_t)biosdisk_buf & 0xF);
- memcpy(biosdisk_buf,buffer,srd * d->bytes_per_sector);
-#else
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
-#endif
-
- /* TODO: If the request crosses a 64KB boundary, then use an alternative buffer and memcpy it back */
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- if ((physo & 0xFFFF0000ULL) != ((physo + ((uint32_t)d->bytes_per_sector) - (uint32_t)1) & 0xFFFF0000ULL)) {
-#if TARGET_MSDOS == 32
- fprintf(stderr,"DMA boundary crossing in 32-bit protected mode! This shouldn't happen!\n");
- fprintf(stderr,"The bounce buffer is not supposed to have been straddling a DMA boundary\n");
- abort();
- break;
-#else
- if (!biosdisk_bounce_init()) {
- fprintf(stderr,"Error: cannot alloc bios disk bounce for DMA boundary read\n");
- break;
- }
-
- srd = 1;
- crossdma = 1;
- d->dma_crossed = 1;
- segv = FP_SEG(biosdisk_bounce);
- offv = FP_OFF(biosdisk_bounce);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- if ((physo & 0xFFFF0000ULL) != ((physo + ((uint32_t)d->bytes_per_sector) - (uint32_t)1) & 0xFFFF0000ULL)) {
- fprintf(stderr,"Error: bounce buffer also crosses DMA boundary---what's the point?\n");
- break;
- }
-
- _fmemcpy(biosdisk_bounce,buffer,d->bytes_per_sector);
-#endif
- }
-
- /* how many can we read without crossing 64KB? */
- segrem = (0x10000 - (physo & 0xFFFFUL)) / d->bytes_per_sector;
- assert(segrem != 0); /* because the above code should have caught this! */
- if (srd > segrem) srd = segrem;
-
- assert(S < 63);
- assert(H < 256);
- assert(C < 1024);
- pair = (S + 1) | (((C >> 8) & 3) << 6) | ((C & 0xFF) << 8);
-
- /* normalize the segment offset */
- segv = physo >> 4;
- offv = physo & 0xF;
- err = erc = 0;
-
- /* carry out the read */
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x0300 | srd;
- rc.ebx = offv;
- rc.ecx = pair;
- rc.edx = drv | (H << 8);
- rc.es = segv;
- biosdisk_realmode_13_call(&rc);
- erc = (rc.eax >> 8) & 0xFF;
- if ((rc.flags & 1) == 0) err = rc.eax & 0xFF;
- }
-#else
- __asm {
- push es
- mov ah,0x03
- mov al,byte ptr srd
- mov dh,byte ptr H
- mov dl,drv
- mov cx,pair
- mov bx,segv
- mov es,bx
- mov bx,offv
- int 0x13
- pop es
- mov erc,ah
- jc call1
- mov err,al
-call1:
- }
-#endif
- if (erc != 0)
- break;
- if (err == 0 || err > srd) /* filter out BIOSes that return inane responses when AL should be sector count */
- err = srd; /* Compaq Elite laptop BIOS returns AX=0x0050 when asked to write one sector, for example */
-
- num -= err;
- ret += err;
- sector += (uint64_t)err;
-#if TARGET_MSDOS == 32
- buffer = (void*)((char*)buffer + (err * d->bytes_per_sector));
-#else
- /* need to copy from bounce buffer */
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- physo += (err * d->bytes_per_sector);
- buffer = MK_FP(physo>>4,physo&0xF);
-#endif
- }
-
- return ret;
-}
-
-static int biosdisk_ext_write(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num) {
- unsigned char drv = d->index;
- unsigned int srd,segv,offv;
- unsigned char pkt[0x10];
- unsigned char err;
- uint32_t physo;
- int ret = 0;
-
-#if TARGET_MSDOS == 32
- if (!biosdisk_buf_init())
- return 0;
-#endif
-
- while (num > 0) {
- if (d->total_sectors != 0ULL && sector >= d->total_sectors)
- return 0;
-
- srd = (unsigned int)num;
-#if TARGET_MSDOS == 32
- if (srd > ((biosdisk_bufsize - 0x20) / d->bytes_per_sector)) srd = ((biosdisk_bufsize - 0x20) / d->bytes_per_sector);
-#else
- if (srd > ((0xFF00 - 0x20) / d->bytes_per_sector)) srd = ((0xFF00 - 0x20) / d->bytes_per_sector);
-#endif
- err = 0x00;
-
-#if TARGET_MSDOS == 32
- segv = (unsigned int)((size_t)((char*)biosdisk_buf + 0x20) >> 4);
- offv = (unsigned int)((size_t)((char*)biosdisk_buf + 0x20) & 0xF);
-#else
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
-#endif
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- pkt[0] = 0x10;
- pkt[1] = 0;
- *((uint16_t*)(pkt+2)) = srd;
- *((uint16_t*)(pkt+4)) = physo & 0xF;
- *((uint16_t*)(pkt+6)) = physo >> 4;
- *((uint64_t*)(pkt+8)) = sector;
-
- /* carry out the write */
-#if TARGET_MSDOS == 32
- memcpy((char*)biosdisk_buf + 0x20,buffer,srd * d->bytes_per_sector);
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4300;
- rc.edx = drv;
- rc.esi = ((uint32_t)biosdisk_buf) & 0xF;
- rc.ds = ((uint32_t)biosdisk_buf) >> 4;
- memcpy(biosdisk_buf,pkt,0x10);
- biosdisk_realmode_13_call(&rc);
- if (rc.flags & 1) err = (rc.eax >> 8) & 0xFF;
- else err = 0;
- }
-#else
- segv = FP_SEG(pkt);
- offv = FP_OFF(pkt);
- __asm {
- push ds
- mov ah,0x43
- mov dl,drv
- mov ds,segv
- mov si,offv
- int 0x13
- pop ds
- jnc call1
- mov err,ah
-call1:
- }
-#endif
- if (err != 0)
- break;
-
- num -= srd;
- ret += srd;
- sector += (uint64_t)srd;
-#if TARGET_MSDOS == 32
- buffer = (void*)((char*)buffer + (srd * d->bytes_per_sector));
-#else
- segv = FP_SEG(buffer);
- offv = FP_OFF(buffer);
- physo = ((uint32_t)segv << 4UL) + ((uint32_t)offv);
- physo += (srd * d->bytes_per_sector);
- buffer = MK_FP(physo>>4,physo&0xF);
-#endif
- }
-
- return ret;
-}
-
-int biosdisk_write(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num) {
- if (num <= 0)
- return 0;
-
- if (!d->write_enable)
- return 0;
-
- if (d->ext_packet_access)
- return biosdisk_ext_write(d,buffer,sector,num);
- else if (d->sectors_per_track > 0)
- return biosdisk_std_write(d,buffer,sector,num);
- return 0;
-}
-
+++ /dev/null
-/* biosdisk.h
- *
- * INT 13h BIOS disk library.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <stdint.h>
-
-struct biosdisk_drive {
- uint8_t index;
- uint8_t extended:1; /* use INT 13h extensions */
- uint8_t ext_packet_access:1; /* can use packet read */
- uint8_t drive_locking_eject:1;
- uint8_t edd_support:1;
- uint8_t write_enable:1; /* enable write functions (sanity checking!!!) */
- uint8_t dma_crossed:1; /* set by CHS read/write functions if your IO crosses DMA boundaries */
- uint8_t reserved:2;
- uint16_t bytes_per_sector;
- int16_t heads,cylinders,sectors_per_track;
- uint64_t total_sectors;
-};
-
-#define BIOSDISK_EXTENDED 1
-
-void biosdisk_free_resources();
-int biosdisk_edd_get_geometry(struct biosdisk_drive *d,uint8_t index);
-int biosdisk_check_extensions(struct biosdisk_drive *d,uint8_t index);
-int biosdisk_classic_get_geometry(struct biosdisk_drive *d,uint8_t index);
-int biosdisk_get_info(struct biosdisk_drive *d,uint8_t index,uint8_t flags);
-int biosdisk_read(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num);
-int biosdisk_write(struct biosdisk_drive *d,
-#if TARGET_MSDOS == 32
-void *buffer,
-#else
-void far *buffer,
-#endif
-uint64_t sector,int num);
-
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (BIOSDISK) or / (Linux)
-NOW_BUILDING = HW_BIOSDISK_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = biosdisk.c
-OBJS = $(SUBDIR)$(HPS)biosdisk.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-!ifeq TARGET_MSDOS 16
-! ifndef TARGET_WINDOWS
-! ifndef TARGET_OS2
-DUMPHDP_EXE = $(SUBDIR)$(HPS)dumphdp.exe
-! endif
-! endif
-!endif
-
-$(HW_BIOSDISK_LIB): $(OBJS)
- wlib -q -b -c $(HW_BIOSDISK_LIB) -+$(SUBDIR)$(HPS)biosdisk.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-BIOSDISK
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-lib: $(HW_BIOSDISK_LIB) .symbolic
-
-exe: $(TEST_EXE) $(DUMPHDP_EXE) .symbolic
-
-$(TEST_EXE): $(HW_BIOSDISK_LIB) $(HW_BIOSDISK_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_BIOSDISK_LIB_WLINK_LIBRARIES) $(HW_BIOSDISK_CPU_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-!ifdef DUMPHDP_EXE
-$(DUMPHDP_EXE): $(SUBDIR)$(HPS)dumphdp.obj $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)dumphdp.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(DUMPHDP_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_BIOSDISK_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* Diagnostic program:
-
- 1. Call INT 13h and request drive C (0x80) geometry.
-
- 2. Locate the BIOS disk table describing drive C and dump it's contents
-
- 3. Read drive C geometry from CMOS (or try to, anyway...)
-
- Comparison against IDE can then be made using the IDE test code.
- Hopefully the results of this program can reveal what Windows 95's "Standard ESDI/IDE controller" driver
- is so goddamn picky about and we can get DOSBox-X to emulate it --Jonathan C */
-
-/* NOTES:
-
- - VirualBox seems to format CMOS data best viewed by "AWARD #2" parsing
-
- - QEMU INT 13h "Get Drive Parameters" returns cylinders - 2, not cylinders - 1
- like most implementations do. Emulating the "spare cylinder" thing perhaps?
- It stores data in the same manner as "AMI".
-
- - If BIOS geometry translation is in effect, the Fixed Disk Parameter Table and
- CMOS values will be translated as well. Getting the real geometry requires
- that we talk to the IDE drive directly.
-
- - ^ This means DOSBox is technically already correct in how it emulates INT 13h
- and said tables/CMOS. Windows 95's hangup with my IDE emulation can't be the
- result of CMOS then...
-
- - IDE drives return a "legacy" current sector total and a "total user addressible"
- sector total. In VirtualBox, the legacy count is always the product C * H * S
- while "total user addressible" is the actual number of sectors on the disk.
- */
-
-#if TARGET_MSDOS == 32
-# error This is not 32-bit capable code
-#endif
-#ifdef TARGET_WINDOWS
-# error This code is NOT for windows
-#endif
-#ifdef TARGET_OS2
-# error This code is NOT for OS2
-#endif
-
-#include <stdio.h>
-#include <conio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <dos.h>
-
-/* NTS: Steal some code from rtc.h */
-static inline void rtc_io_finished() {
- outp(0x70,0x0D);
- inp(0x71);
-}
-
-static inline unsigned char rtc_io_read(unsigned char idx) {
- outp(0x70,idx | 0x80); /* also mask off NMI */
- return inp(0x71);
-}
-
-int main() {
- unsigned int a=0,b=0,c=0,d=0,e=0;
- unsigned char far *fdpt = (unsigned char far*)_dos_getvect(0x41);
-
- /* read INT 13h geometry */
- __asm {
- push es
- mov ah,8
- mov dl,0x80
- xor di,di
- mov bx,di
- mov cx,di
- mov dh,bh
- mov es,di
- int 13h
- pop es
- xor al,al
- jnc no1
- mov al,0xFF
-no1: mov a,ax
- mov b,bx
- mov c,cx
- mov d,dx
- ; AH=bios return error AL=0 if success 0xFF if not
- }
- printf("INT 13h results: AX=%04x BX=%04x CX=%04x DX=%04x\n",a,b,c,d);
- printf(" C/H/S: %u/%u/%u\n",((((c>>6)&3) << 8) | (c>>8))+1,(d>>8)+1,(c&0x3F));
-
- /* read the Fixed Disk Parameter Table */
- printf("Fixed Disk Parameter Table (at %04X:%04X)\n",FP_SEG(fdpt),FP_OFF(fdpt));
- printf(" C/H/S: %u/%u/%u land=%u ctrl=%02x\n",
- *((unsigned short far*)(fdpt+0)),
- fdpt[2],
- fdpt[14],
- *((unsigned short far*)(fdpt+12)),
- fdpt[8]);
- printf(" [RAW]: ");
- for (a=0;a < 16;a++) printf("%02x ",fdpt[a]);
- printf("\n");
-
- /* read CMOS memory where most BIOSes store hard disk geometry */
- __asm cli
- a = rtc_io_read(0x12);
- rtc_io_finished();
- __asm sti
- printf("CMOS hard disk geometry: Drive 0=%u Drive 1=%u\n",(a>>4),a&0xF);
-
- __asm cli
- a = rtc_io_read(0x19);
- b = rtc_io_read(0x1A);
- rtc_io_finished();
- __asm sti
- printf(" Drive 0 ext-type %u Drive 1 ext-type %u\n",a,b);
-
- __asm cli
- a = rtc_io_read(0x1B) | (rtc_io_read(0x1C) << 8);
- b = rtc_io_read(0x1D);
- c = rtc_io_read(0x20);
- d = rtc_io_read(0x23);
- rtc_io_finished();
- __asm sti
- printf(" [AMI] Drive 0 C/H/S %u/%u/%u control %02x\n",a,b,d,c);
-
- __asm cli
- a = rtc_io_read(0x26) | (rtc_io_read(0x27) << 8);
- b = rtc_io_read(0x28);
- c = rtc_io_read(0x2D);
- rtc_io_finished();
- __asm sti
- printf(" [AWARD #1] Drive 0 C/H/S %u/%u/%u\n",a,b,c);
-
- /* apparently this is what VirtualBox follows */
- __asm cli
- a = rtc_io_read(0x1E) | (rtc_io_read(0x1F) << 8); /* 2nd hard disk my ass */
- b = rtc_io_read(0x20);
- c = rtc_io_read(0x25);
- d = rtc_io_read(0x21) | (rtc_io_read(0x22) << 8);
- e = rtc_io_read(0x23) | (rtc_io_read(0x24) << 8);
- rtc_io_finished();
- __asm sti
- printf(" [AWARD #2] Drive 0 C/H/S %u/%u/%u write_precomp=%u land=%u\n",a,b,c,d,e);
-
- return 0;
-}
-
+++ /dev/null
-/* test.c
- *
- * INT 13h BIOS disk test program.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
- *
- * A test program for INT 13h functions.
- *
- * WARNING: If misued, this program CAN ERASE YOUR HARD DRIVE.
- * Please test this program only on a computer who's hard disk
- * contents you don't care for. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/biosdisk/biosdisk.h>
-
-static char enable_extended = 1;
-static unsigned char sector[4096*3]; /* NTS: To hold 512 byte sectors, 2048 byte CD-ROM sectors, or the 4KB sectors on the newest SATA drives */
-static unsigned char sector2[4096*3]; /* NTS: To hold 512 byte sectors, 2048 byte CD-ROM sectors, or the 4KB sectors on the newest SATA drives */
-
-static void print_ent(uint8_t hddcount,struct biosdisk_drive *tmp) {
- printf( "[%u] %02X: E/D/P/R=%u/%u/%u/%u CHS %u/%u/%u ssz=%u tot=%llu (%lluKB)\n",
- hddcount,
- tmp->index,
- tmp->extended,
- tmp->edd_support,
- tmp->ext_packet_access,
- tmp->drive_locking_eject,
- tmp->cylinders,
- tmp->heads,
- tmp->sectors_per_track,
- tmp->bytes_per_sector,
- tmp->total_sectors,
- (tmp->total_sectors * ((uint64_t)tmp->bytes_per_sector)) >> 10ULL);
-}
-
-static int choose_drive(struct biosdisk_drive *drv) {
- struct biosdisk_drive hdd[17];
- int hddcount = 0,i;
- int c;
-
- /* NTS: There are some BIOS bugs that will show up quite visibly here!
- *
- * - Compaq Elite LTE 450C/X: The BIOS apparently only decodes the lower 4 bits of DL (drive index)
- * causing this loop to show the same drive(s) 8 times. But attempting to read/write the ghost
- * drives will fail. It does NOT support the extended INT 13H functions.
- * (BIOS date: Approx 1994) */
-
- /* NTS: This loop will also reveal the hidden CD-ROM drive assignment on some machine and emulator configurations.
- * - Microsoft Virtual PC 2007: CD-ROM drive shows up on 0xF2. But extended functions to read it are denied
- * with the "controller failure" error code. The CD-ROM drive also shows up in the standard C/H/S based
- * INT 13h interface as well.
- *
- * - VirtualBox 4.0.8: CD-ROM drive shows up on 0xE0. Reading works perfectly fine.
- *
- * - Most PC BIOSes: CD-ROM drive is not assigned at all. The only way to test CD-ROM drive detection is to have
- * booted DOS from a CD to run this program (see "El Torito" specification). */
-
- /* stock entry for 1.44MB floppy */
- {
- struct biosdisk_drive *tmp = hdd+hddcount;
- memset(tmp,0,sizeof(*tmp));
-
- tmp->index = 0x00;
- tmp->extended = 0;
- tmp->edd_support = 0;
- tmp->ext_packet_access = 0;
- tmp->drive_locking_eject = 0;
- tmp->cylinders = 80;
- tmp->heads = 2;
- tmp->sectors_per_track = 18;
- tmp->bytes_per_sector = 512;
- tmp->total_sectors = tmp->cylinders * tmp->heads * tmp->sectors_per_track;
- print_ent(hddcount,tmp);
- hddcount++;
- }
-
- for (i=0;i < 0x80 && hddcount < 17;i++) {
- struct biosdisk_drive *tmp = hdd+hddcount;
- if (biosdisk_get_info(tmp,i+0x80,enable_extended ? BIOSDISK_EXTENDED : 0)) {
- print_ent(hddcount,tmp);
- hddcount++;
- }
- }
-
- printf("Choice? "); fflush(stdout);
- scanf("%d",&c);
- if (c < 0 || c >= hddcount) return 0;
-
- *drv = hdd[c];
- return 1;
-}
-
-static void chomp(char *s) {
- char *e = s+strlen(s)-1;
- while (e >= s && *e == '\n') *e-- = 0;
-}
-
-static void showsector(uint64_t sectn,struct biosdisk_drive *bdsk) {
- int row,col,rd;
-
- memset(sector,0xAA,512);
- if ((rd=biosdisk_read(bdsk,sector,sectn,1)) > 0) {
- if (rd != 1) printf("WARNING: BIOS drive returned more sectors than asked for\n");
- printf("Sector %llu contents:\n",sectn);
- for (row=0;row < 4;row++) {
- for (col=0;col < 16;col++)
- printf("%02X ",sector[(row*16)+col]);
-
- printf(" ");
- for (col=0;col < 16;col++) {
- char c = sector[(row*16)+col];
- if (c >= 32) printf("%c",c);
- else printf(".");
- }
- printf("\n");
- }
- }
-}
-
-static void showmsector(uint64_t sectn,struct biosdisk_drive *bdsk) {
- int sects = (int)(sizeof(sector) / bdsk->bytes_per_sector);
- int row,col,rd,rc;
-
- if ((rd=biosdisk_read(bdsk,sector,sectn,sects)) > 0) {
- if (rd > sects) printf("WARNING: BIOS drive returned more sectors than asked for\n");
- rc = 1;
- printf("Sector %llu-%llu contents:\n",sectn,sectn+rd-1);
- for (row=0;row < ((rd*bdsk->bytes_per_sector)/16);row++) {
- printf("%02x ",row);
- for (col=0;col < 16;col++)
- printf("%02X ",sector[(row*16)+col]);
-
- printf(" ");
- for (col=0;col < 16;col++) {
- char c = sector[(row*16)+col];
- if (c >= 32) printf("%c",c);
- else printf(".");
- }
- printf("\n");
-
- if (++rc >= 24) {
- while (getch() != 13);
- rc -= 24;
- }
- }
- }
-}
-
-static void mrv_test(struct biosdisk_drive *d) {
- int sects = (int)(sizeof(sector) / d->bytes_per_sector);
- unsigned int ui,dmacs=0;
- uint64_t sect,max;
- int do_sects;
- int rd,c;
-
- printf("Type 'Y' to begin read test.\n");
- c = getch();
- if (!(c == 'y' || c == 'Y')) return;
- printf("Okay, here we go!\n");
-
- if (d->total_sectors == 0)
- max = 0x7FFFFFFFUL;
- else
- max = d->total_sectors;
-
- for (sect=0;sect < max;) {
- int perc = (int)((sect * 100ULL) / max);
- printf("\x0D %%%u %llu/%llu [%u DMA crossing] ",perc,sect,max,dmacs);
-
- do_sects = sects;
- if ((do_sects+sect) > max) do_sects = (int)(max - sect);
-
- /* multisector read */
- if ((rd=biosdisk_read(d,sector,sect,do_sects)) <= 0) {
- printf("failed [mrt]\n");
- return;
- }
- if (rd < do_sects) {
- printf("Got less than asked for (%d<%d) [mrt]\n",rd,do_sects);
- return;
- }
- if (d->dma_crossed) dmacs++;
-
- /* single-sector read */
- for (rd=0;rd < do_sects;rd++) {
- if (biosdisk_read(d,sector2+(rd*d->bytes_per_sector),sect+((uint64_t)rd),1) != 1) {
- printf("failed [sing]\n");
- return;
- }
- if (d->dma_crossed) dmacs++;
- }
-
- /* do they match? */
- for (ui=0;ui < ((unsigned int)do_sects * d->bytes_per_sector);ui++) {
- if (sector[ui] != sector2[ui]) {
- printf("Byte mismatch at %u into the read\n",ui);
- return;
- }
- }
-
- /* step */
- sect += do_sects;
-
- if (kbhit()) {
- if (getch() == 27)
- break;
- }
- }
- printf("\nTest complete\n");
-}
-
-static void multisector_read_test(struct biosdisk_drive *d) {
- int sects = (int)(sizeof(sector) / d->bytes_per_sector);
- uint64_t sect,max;
- int do_sects;
- int rd,c;
-
- printf("Type 'Y' to begin read test.\n");
- c = getch();
- if (!(c == 'y' || c == 'Y')) return;
- printf("Okay, here we go!\n");
-
- if (d->total_sectors == 0)
- max = 0x7FFFFFFFUL;
- else
- max = d->total_sectors;
-
- for (sect=0;sect < max;) {
- int perc = (int)((sect * 100ULL) / max);
- printf("\x0D %%%u %llu/%llu ",perc,sect,max);
-
- do_sects = sects;
- if ((do_sects+sect) > max) do_sects = (int)(max - sect);
- if ((rd=biosdisk_read(d,sector,sect,do_sects)) <= 0) {
- printf("failed\n");
- return;
- }
-
- if (rd < do_sects)
- printf("Warning, got less than asked for (%d<%d)\n",rd,do_sects);
-
- sect += rd;
-
- if (kbhit()) {
- if (getch() == 27)
- break;
- }
- }
- printf("\nTest complete\n");
-}
-
-static void read_test(struct biosdisk_drive *d) {
- uint64_t sect,max;
- int rd,c;
-
- printf("Type 'Y' to begin read test.\n");
- c = getch();
- if (!(c == 'y' || c == 'Y')) return;
- printf("Okay, here we go!\n");
-
- if (d->total_sectors == 0)
- max = 0x7FFFFFFFUL;
- else
- max = d->total_sectors;
-
- for (sect=0;sect < max;sect++) {
- int perc = (int)((sect * 100ULL) / max);
- printf("\x0D %%%u %llu/%llu ",perc,sect,max);
-
- if ((rd=biosdisk_read(d,sector,sect,1)) != 1) {
- printf("failed\n");
- return;
- }
-
- if (kbhit()) {
- if (getch() == 27)
- break;
- }
- }
- printf("\nTest complete\n");
-}
-
-static void chs_lba_test(struct biosdisk_drive *d) {
- struct biosdisk_drive d_chs={0};
- uint64_t sect;
- int rd,c;
-
- /* we need another biosdisk struct reflecting the CHS view of the drive */
- if (!d->ext_packet_access || d->index < 0x80) {
- printf("LBA extended read mode is not available for this drive\n");
- return;
- }
-
- if (!biosdisk_get_info(&d_chs,d->index,0)) {
- printf("Cannot detect drive in non-extended mode\n");
- return;
- }
-
- printf("Extended geo: %u/%u/%u %u bytes/sec\n",
- d->cylinders,
- d->heads,
- d->sectors_per_track,
- d->bytes_per_sector);
-
- printf("C/H/S non-extended geo: %u/%u/%u %u bytes/sec\n",
- d_chs.cylinders,
- d_chs.heads,
- d_chs.sectors_per_track,
- d_chs.bytes_per_sector);
-
- if (d_chs.bytes_per_sector != d->bytes_per_sector) {
- printf("Bytes per sector must match\n");
- return;
- }
-
- printf("Initial read test: "); fflush(stdout);
- if ((rd=biosdisk_read(d,sector,0,1)) != 1) {
- printf("LBA failed\n");
- return;
- }
- if ((rd=biosdisk_read(&d_chs,sector2,0,1)) != 1) {
- printf("CHS failed\n");
- return;
- }
- printf("OK\n");
- if (memcmp(sector,sector2,d->bytes_per_sector) != 0) {
- printf("...But the data read back does not match!\n");
- return;
- }
-
- printf("Type 'Y' to begin read test.\n");
- c = getch();
- if (!(c == 'y' || c == 'Y')) return;
- printf("Okay, here we go!\n");
-
- for (sect=0;sect < d_chs.total_sectors;sect++) {
- int perc = (int)((sect * 100ULL) / d_chs.total_sectors);
- printf("\x0D %%%u %llu/%llu ",perc,sect,d_chs.total_sectors);
-
- if ((rd=biosdisk_read(d,sector,sect,1)) != 1) {
- printf("LBA failed\n");
- return;
- }
- if ((rd=biosdisk_read(&d_chs,sector2,sect,1)) != 1) {
- printf("CHS failed\n");
- return;
- }
- if (memcmp(sector,sector2,d->bytes_per_sector) != 0) {
- printf("Data mismatch\n");
- return;
- }
-
- if (kbhit()) {
- if (getch() == 27)
- break;
- }
- }
- printf("\nTest complete\n");
-}
-
-static void helpcmd() {
- printf("q: quit g [number]: go to sector z: last sector b: back 1 sector\n");
- printf("w [msg]: write sector with message c1: read test (LBA <-> CHS)\n");
- printf("rt: Read test mrt: multisector read test mr: multisector read\n");
- printf("mrv: Single + Multisector read test\n");
-}
-
-int main(int argc,char **argv) {
- struct biosdisk_drive bdsk = {0};
- uint64_t sectn = 0;
- char line[128],*pp;
- int die=0,ii,cc;
-
- for (ii=1;ii < argc;) {
- char *a = argv[ii++];
-
- if (*a == '-' || *a == '/') {
- do { a++; } while (*a == '-' || *a == '/');
- if (!strcmp(a,"nx")) {
- enable_extended = 0;
- }
- else if (!strcmp(a,"?") || !strcmp(a,"h") || !strcmp(a,"help")) {
- fprintf(stderr," /nx Do not use INT 13h extensions\n");
- return 1;
- }
- else {
- fprintf(stderr,"I don't know what '%s' means\n",a);
- }
- }
- }
-
- cpu_probe();
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- printf("\n");
- printf("WARNING: Running this test program within Windows is NOT recommended.\n");
- }
-
- if (!choose_drive(&bdsk))
- return 1;
-
- helpcmd();
- while (!die) {
- printf("@ %llu\n",sectn);
- line[0]=0; fgets(line,sizeof(line)-1,stdin);
- pp = line; while (*pp == ' ') pp++;
- chomp(pp);
-
- if (*pp == 0) {
- showsector(sectn++,&bdsk);
- }
- else if (!strcmp(pp,"mrv")) {
- mrv_test(&bdsk);
- }
- else if (!strcmp(pp,"mr")) {
- showmsector(sectn,&bdsk);
- }
- else if (!strcmp(pp,"rt")) {
- read_test(&bdsk);
- }
- else if (!strcmp(pp,"mrt")) {
- multisector_read_test(&bdsk);
- }
- else if (!strcmp(pp,"c1")) {
- chs_lba_test(&bdsk);
- }
- else if (*pp == '?') {
- helpcmd();
- }
- else if (*pp == 'q') {
- die = 1;
- }
- else if (*pp == 'g') {
- pp++; while (*pp == ' ') pp++;
- sectn = (uint64_t)strtoll(pp,NULL,0);
- showsector(sectn,&bdsk);
- }
- else if (*pp == 'z') {
- if (bdsk.total_sectors == 0)
- sectn = 0x7FFFFFFFUL;
- else
- sectn = bdsk.total_sectors - 1;
- showsector(sectn,&bdsk);
- }
- else if (*pp == 'b') {
- if (sectn > 0) sectn--;
- showsector(sectn,&bdsk);
- }
- else if (*pp == 'w') {
- if (!bdsk.write_enable) {
- printf("WARNING: If you care about the data on the disk, abort now!\n");
- printf("Enable low-level writing to the disk?!? "); fflush(stdout);
- cc = getch();
- if (cc == 'y' || cc == 'Y') bdsk.write_enable = 1;
- }
-
- if (bdsk.write_enable) {
- int wd;
- pp++; while (*pp == ' ') pp++;
- for (ii=0;ii < bdsk.bytes_per_sector;ii++)
- sector[ii] = 0x30 + (ii & 0xF);
- for (ii=0;ii < bdsk.bytes_per_sector && pp[ii] != 0;ii++)
- sector[ii] = pp[ii];
-
- if ((wd=biosdisk_write(&bdsk,sector,sectn,1)) > 0) {
- if (wd != 1) printf("WARNING: BIOS drive wrote more sectors than asked for\n");
- printf("OK written\n");
- showsector(sectn,&bdsk);
- }
- else {
- printf("Failed\n");
- }
- }
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-set WHAT=make\r
-if "%1" == "clean" set WHAT=clean\r
-\r
-echo Building: 8042\r
-cd 8042\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: 8237\r
-cd 8237\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: 8250\r
-cd 8250\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: 8254\r
-cd 8254\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: 8259\r
-cd 8259\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: acpi\r
-cd acpi\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: adlib\r
-cd adlib\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: apm\r
-cd apm\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: biosdisk\r
-cd biosdisk\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: cpu\r
-cd cpu\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: dos\r
-cd dos\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: flatreal\r
-cd flatreal\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: floppy\r
-cd floppy\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: ide\r
-cd ide\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: isapnp\r
-cd isapnp\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: llmem\r
-cd llmem\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: mb\r
-cd mb\r
-call buildall.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: parport\r
-cd parport\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: pci\r
-cd pci\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: pcie\r
-cd pcie\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: rtc\r
-cd rtc\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: smbios\r
-cd smbios\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: sndsb\r
-cd sndsb\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: ultrasnd\r
-cd ultrasnd\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: usb\r
-cd usb\r
-call buildall.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: vesa\r
-cd vesa\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo Building: vga\r
-cd vga\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo All done\r
+++ /dev/null
-@echo off\r
-if exist *.map del *.map\r
-if exist *.obj del *.obj\r
-if exist *.sym del *.sym\r
-if exist *.exe del *.exe\r
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ lib REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-; alignchk.asm
-;
-; Test program: 80486+ Alignment Check exception
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 386 16-bit protected mode (and back)
-; while playing with the Task State Segment mechanism to
-; demonstrate hopping between "ring 0" and "ring 3".
-; once in RING 3, we turn on the alignment check function of the 486
-; and deliberately try to cause one.
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; SELECTORS
-NULL_SEL equ 0
-CODE_SEL equ 8
-DATA_SEL equ 16
-VIDEO_SEL equ 24
-CODE32_SEL equ 32
-DATA32_SEL equ 40
-TSS_SEL equ 48
-TSS_2_SEL equ 56
-TSS_3_SEL equ 64
-LDT_SEL equ 72
-CODE_SEL3 equ 80
-DATA_SEL3 equ 88
-VIDEO_SEL3 equ 96
-MAX_SEL equ 104
-
-; ===== ENTRY POINT
- call cpu_is_486
- je is_486
- mov dx,str_cpu_not_486
- jmp exit2dos_with_message
-is_486:
-
-; ===== CHECK FOR VIRTUAL 8086 MODE
- smsw ax ; 486 or higher: If we're in real mode
- test al,1 ; and bit 0 is already set, we're in virtual 8086
- jz is_realmode ; and our switch to prot mode will cause problems.
- mov dx,str_cpu_v86_mode
- jmp exit2dos_with_message
-is_realmode:
-
-; ===== WE NEED TO PATCH SOME OF OUR OWN CODE
- mov ax,cs
- mov word [real_entry_patch+3],ax ; overwrite segment field of JMP SEG:OFF
-
-; ===== BUILD THE GLOBAL DESCRIPTOR TABLE AND GDTR REGISTER
- mov ax,cs
- mov bx,ax
- shr bx,12
- shl ax,4 ; BX:AX = 32-bit physical addr of our segment
- mov word [MY_PHYS_BASE],ax
- mov word [MY_PHYS_BASE+2],bx
-
- add ax,GDT
- adc bx,0 ; BX:AX += offset of GDT
-
- mov word [GDTR],MAX_SEL - 1
- mov word [GDTR+2],ax
- mov word [GDTR+4],bx ; GDTR: limit MAX_SEL-1 base=physical mem addr of GDT
-
- mov ax,word [MY_PHYS_BASE]
- mov bx,word [MY_PHYS_BASE+2]
- add ax,IDT
- adc bx,0
-
- mov word [IDTR],2047
- mov word [IDTR+2],ax
- mov word [IDTR+4],bx
-
- cld
-
-; zero IDT
- mov di,IDT
- mov cx,1023
- xor ax,ax
- rep stosw
-
- mov di,GDT
-; NULL selector (NULL_SEL)
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
-; Code selector (CODE_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (VIDEO_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (32-bit) (CODE32_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9E
- stosw ; BASE[23:16] access byte=executable readable conforming
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; Data selector (32-bit) (DATA32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_SEL)
- mov ax,TSS_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_2_SEL)
- mov ax,TSS_AREA_2_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA_2
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS non busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_3_SEL)
- mov ax,TSS_AREA_3_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA_3
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS non busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; LDT selector (32-bit) (LDT_SEL)
- mov ax,LDT_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,LDT_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x82 ; present, non-segment, type=2 (LDT)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; Code selector (CODE_SEL3)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0xFA
- stosw ; BASE[23:16] access byte=executable readable DPL=3
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA_SEL3)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0xF2
- stosw ; BASE[23:16] access byte=data writeable DPL=3
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (VIDEO_SEL3)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0xF2
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-
-; load CPU registers
- cli ; disable interrupts
- lgdt [GDTR] ; load into processor GDTR
- lidt [IDTR]
-
-; switch into protected mode
- mov eax,0x00040001 ; protected mode, enable alignment check exception
- mov cr0,eax
- jmp CODE_SEL:prot_entry
-prot_entry: mov ax,DATA_SEL ; now reload the segment registers
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; load LDT
- mov ax,LDT_SEL
- lldt ax
-
-; zero the first TSS
- cld
- mov edi,TSS_AREA
- mov ecx,TSS_AREA_SIZE / 4
- xor eax,eax
- rep stosd
-
-; zero the second TSS
- cld
- mov edi,TSS_AREA_2
- mov ecx,TSS_AREA_2_SIZE / 4
- xor eax,eax
- rep stosd
-
-; set up the task register. for now, leave it at the first one.
- mov ax,TSS_SEL
- ltr ax
-
-; prepare the second one
- cld
- xor eax,eax ; prepare EAX=0
- mov ebx,eax
- mov ecx,0x12345678 ; check value
- mov edi,TSS_AREA_2
- stosd ; TSS+0x00 = back link
- mov ax,0xF000
- stosd ; TSS+0x04 = ESP0
- mov ax,DATA_SEL
- stosd ; TSS+0x08 = SS0
- mov ax,0xF000
- stosd ; TSS+0x0C = ESP1
- mov ax,DATA_SEL
- stosd ; TSS+0x10 = SS1
- mov ax,0xF000
- stosd ; TSS+0x14 = ESP2
- mov ax,DATA_SEL
- stosd ; TSS+0x18 = SS2
- xor ax,ax
- stosd ; TSS+0x1C = CR3
- mov eax,tss_jump_1
- stosd ; TSS+0x20 = EIP
- pushfd
- pop eax
- stosd ; TSS+0x24 = EFLAGS
- xor eax,eax
- stosd ; TSS+0x28 = EAX
- stosd ; TSS+0x2C = ECX
- stosd ; TSS+0x30 = EDX
- stosd ; TSS+0x34 = EBX
- mov ax,0xF000
- stosd ; TSS+0x38 = ESP
- xor ax,ax
- stosd ; TSS+0x3C = EBP
- stosd ; TSS+0x40 = ESI
- stosd ; TSS+0x44 = EDI
- mov ax,DATA_SEL
- stosd ; TSS+0x48 = ES
- mov ax,CODE_SEL
- stosd ; TSS+0x4C = CS
- mov ax,DATA_SEL
- stosd ; TSS+0x50 = SS
- stosd ; TSS+0x54 = DS
- stosd ; TSS+0x58 = FS
- stosd ; TSS+0x5C = GS
- mov ax,LDT_SEL
- stosd ; TSS+0x60 = LDT selector (meh, I don't use it anyway)
- xor ax,ax
- stosd ; TSS+0x64 = I/O map base=0, T=0
-
-; now, SWITCH!
- jmp TSS_2_SEL:0
-
-; TSS switch should end up HERE.
-; Task register now points to TSS_2_SEL as active task.
-; TEST: If the CPU truly loaded state from TSS_2_SEL, all general regs should be zero
-tss_jump_1: or eax,ebx
- or eax,ecx
- or eax,edx
- or eax,esi
- or eax,edi
- jz tss_jump_1_zero
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E30 ; '0'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_zero:
-; TEST: All segment registers except CS should be DATA_SEL
- mov ax,ds
- sub ax,DATA_SEL
-
- mov bx,es
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,fs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,gs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,ss
- sub bx,DATA_SEL
- or ax,bx
-
- jz tss_jump_1_sreg_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E31 ; '1'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_sreg_ok:
-
-; if the CPU truly saved state into TSS_SEL, the memory location
-; corresponding to ECX should be 0x12345678 (because we loaded ECX
-; with that value prior to switching state, remember?)
- cmp dword [TSS_AREA+0x2C],0x12345678
- jz tss_jump_1_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E32 ; '2'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_ecx_ok:
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- push es
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,vdraw_msg
- xor di,di
-vdraw1: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw1e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw1
-vdraw1e: pop es
-
-; now, jump into 32-bit protected mode
- jmp CODE32_SEL:prot32_entry
-bits 32
-prot32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov esp,0xFFF0
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- mov esi,vdraw32_msg
- mov edi,0xB8000+(80*2)
- sub edi,[MY_PHYS_BASE]
-vdraw321: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw321e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw321
-vdraw321e:
-
-; jump 32-bit to 16-bit
- jmp CODE_SEL:prot32_to_prot
-bits 16
-prot32_to_prot: mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
-
-; prepare the third one---ring 3
- cld
- xor eax,eax ; prepare EAX=0
- mov ebx,eax
- mov ecx,0x12345678 ; check value
- mov edi,TSS_AREA_3
- stosd ; TSS+0x00 = back link
- mov ax,0xE000
- stosd ; TSS+0x04 = ESP0
- mov ax,DATA_SEL
- stosd ; TSS+0x08 = SS0
- mov ax,0xE000
- stosd ; TSS+0x0C = ESP1
- mov ax,DATA_SEL
- stosd ; TSS+0x10 = SS1
- mov ax,0xE000
- stosd ; TSS+0x14 = ESP2
- mov ax,DATA_SEL
- stosd ; TSS+0x18 = SS2
- xor ax,ax
- stosd ; TSS+0x1C = CR3
- mov eax,tss_jump_3
- stosd ; TSS+0x20 = EIP
- pushfd
- pop eax
- stosd ; TSS+0x24 = EFLAGS
- xor eax,eax
- stosd ; TSS+0x28 = EAX
- stosd ; TSS+0x2C = ECX
- stosd ; TSS+0x30 = EDX
- stosd ; TSS+0x34 = EBX
- mov ax,0xF000
- stosd ; TSS+0x38 = ESP
- xor ax,ax
- stosd ; TSS+0x3C = EBP
- stosd ; TSS+0x40 = ESI
- stosd ; TSS+0x44 = EDI
- mov ax,DATA_SEL3 | 3
- stosd ; TSS+0x48 = ES
- mov ax,CODE_SEL3 | 3
- stosd ; TSS+0x4C = CS
- mov ax,DATA_SEL3 | 3
- stosd ; TSS+0x50 = SS
- stosd ; TSS+0x54 = DS
- stosd ; TSS+0x58 = FS
- stosd ; TSS+0x5C = GS
- mov ax,LDT_SEL
- stosd ; TSS+0x60 = LDT selector (meh, I don't use it anyway)
- xor ax,ax
- stosd ; TSS+0x64 = I/O map base=0, T=0
-; Call the TSS, so that we can IRET to return to RING 0
- call TSS_3_SEL:0
- jmp skip_tss_3
-
-; now we are 16-bit RING 3
-tss_jump_3: mov ax,VIDEO_SEL3 ; PROVE IT
- mov es,ax ; BY WRITING TO SCREEN
- mov si,vdraw3_msg
- mov di,80*4
- cld
-vdraw3: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw3e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw3
-vdraw3e:
-
-; switch on the #AC flag in EFLAGS
- pushfd
- pop eax
- or eax,0x40000
- push eax
- popfd
-
-; while we're in RING 3, cause an alignment check fault to test whether the
-; CPU supports it.
- mov si,IDT + (0x11*8) ; INT 11h alignment check exception
- mov word [si+0],tss_ring_3_ac ; base[15:0]
- mov word [si+2],CODE_SEL
- mov word [si+4],0x8600 ; P=1 DPL=0 16-bit interrupt gate
- mov word [si+6],0x0000 ; base[31:16]
-; cause it!
- mov ax,[1] ; misaligned WORD read
-
-; return from ring 3
- iret
-
-; Alignment check exception lands here
-; write our acknowledgement on the screen.
-; Note we're running at ring 0 at this point---I couldn't figure out
-; how to make RING 3 exception handlers work.
-tss_ring_3_ac:
- mov ax,DATA_SEL
- mov ds,ax
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,alignchk_msg
- mov di,80*8
- cld
-vdraw3ac: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw3ace
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw3ac
-vdraw3ace:
-; disable alignment check to avoid further exceptions, and to allow
-; the program to continue. Note that despite what numerous web sites
-; tell you, the AC# exception DOES push an error code onto the stack!
-; Both Intel and AMD docs say so too!
- mov eax,cr0
- and eax,~0x40000
- mov cr0,eax
-; FIXME: I can't fucking figure out how to IRET without crashing, so
-; in the meantime, while we're sitting in ring zero we're just going
-; to go ahead and hack the TSS segment and forcibly restore state.
- mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,0xF000
-; the CPU probably changes the TSS to busy, force it back to non-busy
- mov byte [GDT+TSS_2_SEL+5],0x89
-; having disarmed the busy status, switch.
- jmp TSS_2_SEL:0
-
-; TSS RING-3 test COMPLETE
-skip_tss_3:
-
-; active task is TSS_2_SEL. Prove we can switch tasks again by modifying
-; EIP in TSS_SEL, then switching tasks.
- mov dword [TSS_AREA+0x20],tss_jump_2
- jmp TSS_SEL:0
-tss_jump_2:
-
-; having switched back to TSS_SEL, the value we left in ECX should still
-; be there.
- cmp ecx,0x12345678
- jz tss_jump_2_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E33 ; '3'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_2_ecx_ok:
-
-; switch back to real mode.
-; unlike the 286, switching back means clearing bit 0 of CR0
- xor eax,eax ; clear bit 0
- mov cr0,eax
-
-real_entry_patch:jmp 0x0000:real_entry ; the segment field is patched by code above
-real_entry: mov ax,cs
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; ===== REBUILD GDTR FOR PROPER REAL MODE OPERATION
- mov word [GDTR],0xFFFF
- mov word [GDTR+2],0
- mov word [GDTR+4],0 ; GDTR: limit 0xFFFF base 0x00000000
- lgdt [GDTR] ; load into processor GDTR
-
- mov word [IDTR],0xFFFF
- mov word [IDTR+2],0
- mov word [IDTR+4],0 ; IDTR: limit 0xFFFF base 0x00000000
- lidt [IDTR]
-
-; ====== PROVE WE MADE IT TO REAL MODE
- mov si,vdraw2_msg
- mov ax,0xB800
- mov es,ax
- mov di,80*6
-vdraw2: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw2e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw2
-vdraw2e: mov ax,cs
- mov es,ax
-
- sti
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-; 8086 test: EFLAGS will always have bits 12-15 set
-cpu_is_486: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_486_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_486_not
-; 386 test: We cannot set #AC (bit 18) on a 386
- pushfd
- pop eax
- or eax,0x40000
- push eax
- popfd
- pushfd
- pop eax
- and eax,0x40000
- jz cpu_is_486_not
-; it's a 486
- xor ax,ax ; ZF=1
- ret
-cpu_is_486_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; strings
-str_cpu_not_486: db "486 or higher required$"
-str_cpu_v86_mode: db "Virtual 8086 mode detected$"
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-vdraw3_msg: db "This message was drawn on screen from 386 16-bit protected mode, ring 3!",0
-vdraw_msg: db "This message was drawn on screen from 386 16-bit protected mode!",0
-vdraw32_msg: db "This message was drawn on screen from 386 32-bit protected mode!",0
-alignchk_msg: db "Yes, this processor supports the Alignment Check exception!",0
-
-; THESE VARIABLES DO NOT EXIST IN THE ACTUAL .COM FILE.
-; They exist in the yet-uninitialized area of RAM just beyond the
-; end of the loaded COM file image.
- align 8
-RALLOC: db 0xAA
-GDTR equ RALLOC+0
-IDTR equ GDTR+8
-MY_PHYS_BASE equ IDTR+8
-GDT equ MY_PHYS_BASE+8
-IDT equ GDT+MAX_SEL
- IDT_SIZE equ 2048
-TSS_AREA equ IDT+IDT_SIZE
- TSS_AREA_SIZE equ 2048
-TSS_AREA_2 equ TSS_AREA+TSS_AREA_SIZE
- TSS_AREA_2_SIZE equ 2048
-TSS_AREA_3 equ TSS_AREA_2+TSS_AREA_2_SIZE
- TSS_AREA_3_SIZE equ 2048
-LDT_AREA equ TSS_AREA_3+TSS_AREA_3_SIZE
- LDT_AREA_SIZE equ 64
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <setjmp.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/flatreal/flatreal.h>
-#include <hw/dos/doswin.h>
-
-#include <hw/cpu/apiclib.h>
-
-int main(int argc,char **argv) {
- if (!probe_apic()) {
- printf("APIC not detected. Reason: %s\n",apic_error_str);
- return 1;
- }
-
- printf("APIC base address: 0x%08lx\n",(unsigned long)apic_base);
- printf("APIC global enable: %u\n",(unsigned int)(apic_flags&APIC_FLAG_GLOBAL_ENABLE?1:0));
- printf("Read from bootstrap CPU: %u\n",(unsigned int)(apic_flags&APIC_FLAG_PROBE_ON_BOOT_CPU?1:1));
-
-#if TARGET_MSDOS == 32
- dos_ltp_probe();
- /* TODO: If LTP probe indicates we shouldn't assume physical<->linear addresses (i.e paging) then bail out */
-#else
- probe_dos();
- detect_windows();
- if (!flatrealmode_setup(FLATREALMODE_4GB)) {
- printf("Cannot enter flat real mode\n");
- return 1;
- }
-#endif
-
- {
- unsigned int i;
-
- /* NTS: For safe access on Intel processors always read on 16-byte aligned boundary, 32-bit at all times.
- * Intel warns the undefined bytes 4-15 between the regs are undefined and may cause undefined behavior. */
- printf("APIC dump:\n");
- for (i=0x0;i < 0x400;i += 16) {
- if ((i&0x7F) == 0)
- printf("0x%03x:",i);
-
- printf("%08lx ",(unsigned long)apic_readd(i));
- if ((i&0x7F) == 0x70)
- printf("\n");
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <setjmp.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/flatreal/flatreal.h>
-
-#include <hw/cpu/apiclib.h>
-
-unsigned char apic_flags = 0;
-uint32_t apic_base = 0;
-const char* apic_error_str = NULL;
-
-void forget_apic() {
- apic_flags = 0; /* to permit re-probing */
-}
-
-int probe_apic() {
- if (apic_flags == 0) {
- uint32_t reg;
-
- /* FIXME: Some say the APIC-like interface appeared in the late 486 era, though as a separate chip,
- * unlike the Pentium and later that put the APIC on-chip. How do we detect those? */
- apic_flags = APIC_FLAG_PROBED;
-
- cpu_probe();
- if (cpu_basic_level < CPU_586) {
- apic_error_str = "APIC support requires at least a 586/Pentium class system";
- return 0;
- }
- detect_windows();
- if (windows_mode >= WINDOWS_STANDARD) {
- apic_error_str = "I will not attempt to play with the APIC from within Windows";
- apic_flags |= APIC_FLAG_CANT_DETECT;
- return 0;
- }
- if (cpu_v86_active) {
- apic_error_str = "I will not attempt to play with the APIC from virtual 8086 mode";
- apic_flags |= APIC_FLAG_CANT_DETECT;
- return 0;
- }
- if (!(cpu_flags & CPU_FLAG_CPUID)) {
- apic_error_str = "APIC detection requires CPUID";
- return 0;
- }
- if (!(cpu_cpuid_features.a.raw[2/*EDX*/] & (1UL << 9UL))) {
- apic_error_str = "CPU does not have on-chip APIC";
- return 0;
- }
- if (!(cpu_cpuid_features.a.raw[2/*EDX*/] & (1UL << 5UL))) {
- apic_error_str = "CPU does have on-chip APIC but no support for RDMSR/WRMSR";
- return 0;
- }
-
- reg = cpu_rdmsr(0x0000001B); /* hopefully, we do not crash */
- apic_base = (unsigned long)(reg & 0xFFFFF000UL);
- apic_flags |= APIC_FLAG_PRESENT;
- apic_flags |= (reg & (1UL << 11UL)) ? APIC_FLAG_GLOBAL_ENABLE : 0;
- apic_flags |= (reg & (1UL << 8UL)) ? APIC_FLAG_PROBE_ON_BOOT_CPU : 0;
- }
-
- return (apic_flags & APIC_FLAG_PRESENT)?1:0;
-}
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/flatreal/flatreal.h>
-
-#define APIC_FLAG_PRESENT (1U << 0U)
-#define APIC_FLAG_GLOBAL_ENABLE (1U << 1U)
-#define APIC_FLAG_PROBE_ON_BOOT_CPU (1U << 2U)
-#define APIC_FLAG_CANT_DETECT (1U << 6U)
-#define APIC_FLAG_PROBED (1U << 7U)
-
-extern uint32_t apic_base;
-extern unsigned char apic_flags;
-extern const char* apic_error_str;
-
-/* APIC read/write functions.
- * WARNING: You are responsible for making sure APIC was detected before using these functions!
- * Also, Intel warns about some newer registers requiring aligned access to work properly OR ELSE. */
-#if TARGET_MSDOS == 32
-static inline uint32_t apic_readd(uint32_t offset) {
- return *((volatile uint32_t*)(apic_base+offset));
-}
-#else
-/* 16-bit real mode versions that rely on Flat Real Mode to work */
-static inline uint32_t apic_readd(uint32_t offset) {
- if (flatrealmode_test()) flatrealmode_setup(FLATREALMODE_4GB);
- return flatrealmode_readd(apic_base+offset);
-}
-#endif
-
-void forget_apic();
-int probe_apic();
-
+++ /dev/null
-# configuration file generated by Bochs
-plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, gameport=1, iodebug=1, pci_ide=1, acpi=1, ioapic=1
-config_interface: textconfig
-display_library: x
-memory: host=64, guest=1024
-romimage: file="/usr/share/bochs/BIOS-bochs-latest"
-vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
-boot: floppy
-floppy_bootsig_check: disabled=0
-floppya: type=1_44, 1_44="win95.dsk", status=inserted, write_protected=0
-# no floppyb
-ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
-ata0-master: type=disk, mode=flat, translation=auto, path="hdd.dsk", cylinders=16, heads=16, spt=63, biosdetect=auto, model="Generic 1234"
-ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
-ata2: enabled=0
-ata3: enabled=0
-parport1: enabled=1, file=""
-parport2: enabled=0
-com1: enabled=1, mode=null, dev=""
-com2: enabled=0
-com3: enabled=0
-com4: enabled=0
-usb_uhci: enabled=0
-usb_ohci: enabled=0
-i440fxsupport: enabled=1
-vga_update_interval: 50000
-vga: extension=vbe
-cpu: count=1, ips=4000000, reset_on_triple_fault=1, ignore_bad_msrs=1
-print_timestamps: enabled=0
-debugger_log: -
-magic_break: enabled=0
-port_e9_hack: enabled=0
-private_colormap: enabled=0
-clock: sync=none, time0=local
-# no cmosimage
-ne2k: enabled=0
-pnic: enabled=0
-sb16: enabled=0
-# no loader
-log: -
-logprefix: %t%e%d
-panic: action=ask
-error: action=report
-info: action=report
-debug: action=ignore
-keyboard_type: mf
-keyboard_serial_delay: 250
-keyboard_paste_delay: 100000
-keyboard_mapping: enabled=0, map=
-user_shortcut: keys=none
-mouse: enabled=0, type=ps2, toggle=ctrl+mbutton
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-
-# The build system we have has no effect on NASM (at the moment) and
-# all memory models+CPU modes build the same binary. So why build them
-# again and again? Build them only in dos86s mode.
-!ifndef TARGET_WINDOWS
-! ifndef TARGET_OS2
-! ifeq TARGET_MSDOS 16
-! ifeq TARGET86 86
-! ifeq MMODE s
-BUILD_NASM_COM = 1
-! endif
-! endif
-! endif
-! endif
-!endif
-
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-AFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NASMFLAGS_THIS =
-NOW_BUILDING = HW_CPU_LIB
-
-# NTS: CPU functions here are to be moved at some point to the cpu library!
-OBJS = $(SUBDIR)$(HPS)cpuasm.obj $(SUBDIR)$(HPS)cpup3sn.obj $(SUBDIR)$(HPS)cpup3snc.obj $(SUBDIR)$(HPS)cpusse.obj $(SUBDIR)$(HPS)cpu.obj $(SUBDIR)$(HPS)cpuidext.obj $(SUBDIR)$(HPS)gdt_enum.obj $(SUBDIR)$(HPS)libgrind.obj $(SUBDIR)$(HPS)cpurdtsc.obj $(SUBDIR)$(HPS)cpuiopd.obj $(SUBDIR)$(HPS)cpustrlv.obj $(SUBDIR)$(HPS)resetasm.obj $(SUBDIR)$(HPS)cpuid.obj $(SUBDIR)$(HPS)cpurdmsr.obj $(SUBDIR)$(HPS)cpussea.obj
-
-# test programs (MS-DOS and Windows)
-MMX_EXE = $(SUBDIR)$(HPS)mmx.exe
-SSE_EXE = $(SUBDIR)$(HPS)sse.exe
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-GRIND_EXE = $(SUBDIR)$(HPS)grind.exe
-GR_ADD_EXE = $(SUBDIR)$(HPS)gr_add.exe
-DISPSN_EXE = $(SUBDIR)$(HPS)dispsn.exe
-SSEOFF_EXE = $(SUBDIR)$(HPS)sseoff.exe
-GDTLIST_EXE = $(SUBDIR)$(HPS)gdtlist.exe
-!ifndef WIN386
-GDTTAE_EXE = $(SUBDIR)$(HPS)gdttae.exe
-!endif
-RDTSC_EXE = $(SUBDIR)$(HPS)rdtsc.exe
-
-!ifndef TARGET_WINDOWS
-! ifndef TARGET_OS2
-# test programs (MS-DOS only)
-RESET_EXE = $(SUBDIR)$(HPS)reset.exe
-APIC_EXE = $(SUBDIR)$(HPS)apic.exe
-! endif
-!endif
-
-!ifdef BUILD_NASM_COM
-# MS-DOS COM output
-V86_COM = $(SUBDIR)$(HPS)v86.com
-TSS_COM = $(SUBDIR)$(HPS)tss.com
-PROT286_COM = $(SUBDIR)$(HPS)prot286.com
-PROT386_COM = $(SUBDIR)$(HPS)prot386.com
-TSSRING_COM = $(SUBDIR)$(HPS)tssring.com
-V86KERN_COM = $(SUBDIR)$(HPS)v86kern.com
-PROTVCPI_COM =$(SUBDIR)$(HPS)protvcpi.com
-PROTDPMI_COM =$(SUBDIR)$(HPS)protdpmi.com
-V86KERN2_COM =$(SUBDIR)$(HPS)v86kern2.com
-ALIGNCHK_COM =$(SUBDIR)$(HPS)alignchk.com
-!endif
-
-!ifdef APIC_EXE
-OBJS += $(SUBDIR)$(HPS)apiclib.obj
-!endif
-
-$(HW_CPU_LIB): $(OBJS)
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)cpu.obj -+$(SUBDIR)$(HPS)cpuasm.obj
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)gdt_enum.obj -+$(SUBDIR)$(HPS)libgrind.obj
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)cpuidext.obj -+$(SUBDIR)$(HPS)cpusse.obj
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)cpup3sn.obj -+$(SUBDIR)$(HPS)cpup3snc.obj
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)cpurdtsc.obj -+$(SUBDIR)$(HPS)cpuiopd.obj
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)cpustrlv.obj -+$(SUBDIR)$(HPS)resetasm.obj
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)cpuid.obj -+$(SUBDIR)$(HPS)cpurdmsr.obj
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)cpussea.obj
-!ifdef APIC_EXE
- wlib -q -b -c $(HW_CPU_LIB) -+$(SUBDIR)$(HPS)apiclib.obj
-!endif
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS_CON) $[@
- $(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS_CON) $[@
-
-all: lib exe
-
-lib: $(HW_CPU_LIB) .symbolic
-
-exe: $(GDTTAE_EXE) $(TEST_EXE) $(GRIND_EXE) $(GR_ADD_EXE) $(DISPSN_EXE) $(RESET_EXE) $(APIC_EXE) $(MMX_EXE) $(SSE_EXE) $(SSEOFF_EXE) $(PROT286_COM) $(PROT386_COM) $(TSS_COM) $(TSSRING_COM) $(ALIGNCHK_COM) $(V86_COM) $(V86KERN_COM) $(V86KERN2_COM) $(PROTVCPI_COM) $(PROTDPMI_COM) $(RDTSC_EXE) $(GDTLIST_EXE) .symbolic
-
-!ifdef BUILD_NASM_COM
-$(V86_COM): v86.asm
- nasm -o $@ -f bin $(NASMFLAGS) $[@
-
-$(TSS_COM): tss.asm
- nasm -o $@ -f bin $(NASMFLAGS) $[@
-
-$(TSSRING_COM): tssring.asm
- nasm -o $@ -f bin $(NASMFLAGS) $[@
-
-$(PROT286_COM): prot286.asm
- nasm -o $@ -f bin $(NASMFLAGS) $[@
-
-$(PROT386_COM): prot386.asm
- nasm -o $@ -f bin $(NASMFLAGS) $[@
-
-$(V86KERN_COM): v86kern.asm
- nasm -o $@ -f bin $(NASMFLAGS) -l $(SUBDIR)$(HPS)v86kern.lst -O9 $[@
-
-$(PROTVCPI_COM): protvcpi.asm
- nasm -o $@ -f bin $(NASMFLAGS) -l $(SUBDIR)$(HPS)protvcpi.lst -O9 $[@
-
-$(PROTDPMI_COM): protdpmi.asm
- nasm -o $@ -f bin $(NASMFLAGS) -l $(SUBDIR)$(HPS)protdpmi.lst -O9 $[@
-
-$(V86KERN2_COM): v86kern2.asm
- nasm -o $@ -f bin $(NASMFLAGS) -l $(SUBDIR)$(HPS)v86kern2.lst -O9 $[@
-
-$(ALIGNCHK_COM): alignchk.asm
- nasm -o $@ -f bin $(NASMFLAGS) $[@
-!endif
-
-$(MMX_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)mmx.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)mmx.obj option map=$(SUBDIR)$(HPS)mmx.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(MMX_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(MMX_EXE)
- @wbind $(MMX_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(MMX_EXE)
-! endif
-
-$(SSE_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)sse.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)sse.obj option map=$(SUBDIR)$(HPS)sse.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(SSE_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(SSE_EXE)
- @wbind $(SSE_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(SSE_EXE)
-! endif
-
-$(TEST_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)test.obj option map=$(SUBDIR)$(HPS)test.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(TEST_EXE)
- @wbind $(TEST_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(TEST_EXE)
-! endif
-
-$(GRIND_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)grind.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)grind.obj option map=$(SUBDIR)$(HPS)grind.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(GRIND_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(GRIND_EXE)
- @wbind $(GRIND_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(GRIND_EXE)
-! endif
-
-$(GR_ADD_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)gr_add.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)gr_add.obj option map=$(SUBDIR)$(HPS)gr_add.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(GR_ADD_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(GR_ADD_EXE)
- @wbind $(GR_ADD_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(GR_ADD_EXE)
-! endif
-
-$(RDTSC_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_8254_LIB) $(SUBDIR)$(HPS)rdtsc.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) library $(HW_8254_LIB) file $(SUBDIR)$(HPS)rdtsc.obj option map=$(SUBDIR)$(HPS)rdtsc.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(RDTSC_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(RDTSC_EXE)
- @wbind $(RDTSC_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(RDTSC_EXE)
-! endif
-
-!ifdef RESET_EXE
-$(RESET_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_8042_LIB) $(HW_8254_LIB) $(SUBDIR)$(HPS)reset.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) library $(HW_8042_LIB) library $(HW_8254_LIB) file $(SUBDIR)$(HPS)reset.obj option map=$(SUBDIR)$(HPS)reset.map
- %write tmp.cmd name $(RESET_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef APIC_EXE
-$(APIC_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(SUBDIR)$(HPS)apic.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)apic.obj option map=$(SUBDIR)$(HPS)apic.map
- %write tmp.cmd name $(APIC_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-$(DISPSN_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)dispsn.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)dispsn.obj option map=$(SUBDIR)$(HPS)dispsn.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(DISPSN_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(DISPSN_EXE)
- @wbind $(DISPSN_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(DISPSN_EXE)
-! endif
-
-$(SSEOFF_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)sseoff.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)sseoff.obj option map=$(SUBDIR)$(HPS)sseoff.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(SSEOFF_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(SSEOFF_EXE)
- @wbind $(SSEOFF_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(SSEOFF_EXE)
-! endif
-
-$(GDTLIST_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)gdtlist.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)gdtlist.obj option map=$(SUBDIR)$(HPS)gdtlist.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(GDTLIST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(GDTLIST_EXE)
- @wbind $(GDTLIST_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(GDTLIST_EXE)
-! endif
-
-!ifdef GDTTAE_EXE
-$(GDTTAE_EXE): $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)gdttae.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) $(HW_CPU_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)gdttae.obj option map=$(SUBDIR)$(HPS)gdttae.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(GDTTAE_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(GDTTAE_EXE)
- @wbind $(GDTTAE_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(GDTTAE_EXE)
-! endif
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_CPU_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-DEVICE=HIMEM.SYS /testmem:off\r
-DEVICE=EMM386.EXE\r
-FILES=30\r
-BUFFERS=20\r
-\r
-REM DEVICE=dos\cd1.SYS /D:banana\r
-\r
-rem DEVICE=cd1.SYS /D:banana /P:1f0,14\r
-rem DEVICE=cd1.SYS /D:banana /P:170,15\r
-rem DEVICE=cd1.SYS /D:banana /P:170,10\r
-rem DEVICE=cd1.SYS /D:banana /P:1e8,12\r
-rem DEVICE=cd1.SYS /D:banana /P:1e8,11\r
-rem DEVICE=cd1.SYS /D:banana /P:168,10\r
-rem DEVICE=cd1.SYS /D:banana /P:168,9\r
-\r
-LASTDRIVE=Z\r
+++ /dev/null
-/* cpu.c
- *
- * Runtime CPU detection library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS
- * - Windows 3.0/3.1/95/98/ME
- * - Windows NT 3.1/3.51/4.0/2000/XP/Vista/7
- * - OS/2 16-bit
- * - OS/2 32-bit
- *
- * A common library to autodetect the CPU at runtime. If the program calling us
- * is interested, we can also provide Pentium CPUID and extended CPUID information.
- * Also includes code to autodetect at runtime 1) if SSE is present and 2) if SSE
- * is enabled by the OS and 3) if we can enable SSE. */
-
-/* FIXME: The 16-bit real mode DOS builds of this program are unable to detect CPUID under OS/2 2.x and OS/2 Warp 3. Why? */
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-/* Win16: We're probably on a 386, but we could be on a 286 if Windows 3.1 is in standard mode.
- * If the user manages to run us under Windows 3.0, we could also run in 8086 real mode.
- * We still do the tests so the Windows API cannot deceive us, but we still need GetWinFlags
- * to tell between 8086 real mode + virtual8086 mode and protected mode. */
-# include <windows.h>
-# include <toolhelp.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-# include <hw/dos/winfcon.h>
-#endif
-
-char cpu_cpuid_vendor[13]={0};
-struct cpu_cpuid_features cpu_cpuid_features = {0};
-signed char cpu_basic_level = -1;
-uint32_t cpu_cpuid_max = 0;
-unsigned char cpu_flags = 0;
-uint16_t cpu_tmp1 = 0;
-
-void cpu_probe() {
-#if TARGET_MSDOS == 32
- /* we're obviously in 32-bit protected mode, or else this code would not be running at all */
- /* Applies to: 32-bit DOS, Win32, Win95/98/ME/NT/2000/XP/etc. */
- cpu_flags = CPU_FLAG_PROTECTED_MODE | CPU_FLAG_PROTECTED_MODE_32;
-#else
- cpu_flags = 0;
-#endif
-
- cpu_basic_level = cpu_basic_probe();
-
-#if defined(TARGET_OS2)
- /* OS/2 wouldn't let a program like myself touch control registers. Are you crazy?!? */
- cpu_flags |= CPU_FLAG_DONT_WRITE_RDTSC;
-#elif defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
- /* Under Windows 3.1 Win32s and Win 9x/ME/NT it's pretty much a given any attempt to work with
- * control registers will fail. Win 9x/ME will silently ignore, and NT will fault it */
- cpu_flags |= CPU_FLAG_DONT_WRITE_RDTSC;
-#elif !defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
- /* 32-bit DOS: Generally yes we can, but only if we're Ring 0 */
- {
- unsigned int s=0;
-
- __asm {
- xor eax,eax
- mov ax,cs
- and ax,3
- mov s,eax
- }
-
- if (s != 0) cpu_flags |= CPU_FLAG_DONT_WRITE_RDTSC;
- }
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
- /* Windows 3.0/3.1 specific: are we in 32-bit protected mode? 16-bit protected mode? real mode?
- * real mode with v86 mode (does Windows even work that way?). Note that GetWinFlags only appeared
- * in Windows 3.0. If we're under Windows 2.x we have to use alternative detection methods, or
- * else assume Real Mode since Windows 2.x usually does run that way. But: There are 286 and 386
- * enhanced versions of Windows 2.x, so how do we detect those?
- *
- * NTS: This code doesn't even run under Windows 2.x. If we patch the binary to report itself as
- * a 2.x compatible and try to run it under Windows 2.11, the Windows kernel says it's
- * "out of memory" and then everything freezes (?!?). */
- {
-# if TARGET_WINDOWS >= 30 /* If targeting Windows 3.0 or higher at compile time, then assume GetWinFlags() exists */
- DWORD flags = GetWinFlags();
- if (1) {
-# elif TARGET_WINDOWS >= 20 /* If targeting Windows 2.0 or higher, then check the system first in case we're run under 3.0 or higher */
- /* FIXME: If locating the function by name fails, what ordinal do we search by? */
- DWORD (PASCAL FAR *__GetWinFlags)() = (LPVOID)GetProcAddress(GetModuleHandle("KERNEL"),"GETWINFLAGS");
- if (__GetWinFlags != NULL) {
- DWORD flags = __GetWinFlags();
- MessageBox(NULL,"Found it","",MB_OK);
-# else /* don't try. Windows 1.0 does not have GetWinFlags() and does not have any dynamic library functions either. There is
- no GetModuleHandle, GetProcAddress, etc. */
- if (0) {
-# endif
- if (WF_PMODE) {
- cpu_flags |= CPU_FLAG_DONT_WRITE_RDTSC;
- if (flags & WF_ENHANCED)
- cpu_flags |= CPU_FLAG_PROTECTED_MODE | CPU_FLAG_PROTECTED_MODE_32;
- else if (flags & WF_STANDARD)
- cpu_flags |= CPU_FLAG_PROTECTED_MODE;
- }
- /* I highly doubt Windows 3.0 "real mode" every involves virtual 8086 mode, but
- * just in case, check the machine status register. Since Windows 3.0 could run
- * on an 8086, we must be cautious to do this test only on a 286 or higher */
- else if (cpu_basic_level >= 2) {
- unsigned int tmp=0;
-
- __asm {
- .286
- smsw tmp
- }
-
- if (tmp & 1) {
- /* if the PE bit is set, we're under Protected Mode
- * that must mean that all of windows is in Real Mode, but overall
- * the whole show is in virtual 8086 mode.
- * We're assuming here that Windows would not lie to us about what mode is active.
- *
- * THEORY: Could this happen if Windows 3.0 were started in Real Mode
- * while EMM386.EXE is resident and active? */
- cpu_flags |= CPU_FLAG_V86_ACTIVE;
- cpu_flags |= CPU_FLAG_DONT_WRITE_RDTSC;
- }
- }
- }
- }
-#endif
-}
-
+++ /dev/null
-/* cpu.h
- *
- * Runtime CPU detection library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#ifndef __HW_CPU_CPU_H
-#define __HW_CPU_CPU_H
-
-#include <stdint.h>
-#include <dos.h>
-
-#if !defined(FAR)
-# if defined(TARGET_WINDOWS)
-# include <windows.h>
-# else
-# if TARGET_MSDOS == 32
-# define FAR
-# else
-# define FAR far
-# endif
-# endif
-#endif
-
-/* FIX: Open Watcom does not provide inpd/outpd in 16-bit real mode, so we have to provide it ourself */
-/* We assume for the same stupid reasons the pragma aux function can't be used because it's a 386 level instruction */
-#if TARGET_MSDOS == 16
-uint32_t __cdecl inpd(uint16_t port);
-void __cdecl outpd(uint16_t port,uint32_t data);
-#endif
-
-#if TARGET_MSDOS == 16
-static inline uint32_t ptr2phys(void far *p) {
- return (((uint32_t)FP_SEG(p)) << 4UL) +
- ((uint32_t)FP_OFF(p));
-}
-#endif
-
-#pragma pack(push,1)
-struct cpu_cpuid_features {
- union {
- uint32_t raw[4]; /* EAX, EBX, EDX, ECX */
- struct {
- uint32_t todo[4];
- } f;
- } a;
-};
-
-struct cpu_cpuid_ext_features {
- union {
- uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
- struct {
- uint32_t todo[4];
- } f;
- } a;
-};
-
-struct cpu_cpuid_ext_cache_tlb {
- union {
- uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
- struct {
- uint32_t todo[4];
- } f;
- } a;
-};
-
-struct cpu_cpuid_ext_cache_tlb_l2 {
- union {
- uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
- struct {
- uint32_t todo[4];
- } f;
- } a;
-};
-
-struct cpu_cpuid_ext_longmode {
- union {
- uint32_t raw[4]; /* EAX, EBX, ECX, EDX */
- struct {
- uint32_t todo[4];
- } f;
- } a;
-};
-
-struct cpu_cpuid_ext_apm {
- union {
- uint32_t raw[1]; /* EAX */
- struct {
- uint32_t todo[1];
- } f;
- } a;
-};
-
-struct cpuid_result {
- uint32_t eax,ebx,ecx,edx;
-};
-#pragma pack(pop)
-
-/* "Basic" CPU level */
-enum {
- CPU_8086=0, /* 0 */
- CPU_186,
- CPU_286,
- CPU_386,
- CPU_486,
- CPU_586,
- CPU_686,
- CPU_MAX
-};
-
-extern const char * cpu_basic_level_str[CPU_MAX];
-extern char cpu_cpuid_vendor[13];
-extern struct cpu_cpuid_features cpu_cpuid_features;
-extern signed char cpu_basic_level;
-extern uint32_t cpu_cpuid_max;
-extern unsigned char cpu_flags;
-extern uint16_t cpu_tmp1;
-
-/* compatability */
-#define cpu_v86_active (cpu_flags & CPU_FLAG_V86_ACTIVE)
-
-#define cpu_basic_level_to_string(x) (x >= 0 ? cpu_basic_level_str[x] : "?")
-
-/* CPU flag: CPU supports CPUID */
-#define CPU_FLAG_CPUID (1 << 0)
-#define CPU_FLAG_FPU (1 << 1)
-#define CPU_FLAG_CPUID_EXT (1 << 2)
-#define CPU_FLAG_V86_ACTIVE (1 << 3)
-#define CPU_FLAG_PROTECTED_MODE (1 << 4)
-#define CPU_FLAG_PROTECTED_MODE_32 (1 << 5)
-/* ^ Windows-specific: we are not only a 16-bit Win16 app, but Windows is running in 386 enhanced mode
- * and we can safely use 32-bit registers and hacks. This will always be set for
- * Win32 and 32-bit DOS, obviously. If set, PROTECTED_MODE is also set. */
-#define CPU_FLAG_DONT_WRITE_RDTSC (1 << 6)
-
-void cpu_probe();
-int cpu_basic_probe(); /* external assembly language function */
-
-static void _cli();
-#pragma aux _cli = "cli"
-static void _sti();
-#pragma aux _sti = "sti"
-
-static inline void _sti_if_flags(unsigned int f) {
- if (f&0x200) _sti(); /* if IF bit was set, then restore interrupts by STI */
-}
-
-/* NTS: remember for Watcom: 16-bit realmode sizeof(int) == 2, 32-bit flat mode sizeof(int) == 4 */
-static unsigned int get_cpu_flags();
-#if TARGET_MSDOS == 32
-#pragma aux get_cpu_flags = \
- "pushfd" \
- "pop eax" \
- value [eax];
-#else
-#pragma aux get_cpu_flags = \
- "pushf" \
- "pop ax" \
- value [ax];
-#endif
-
-static void set_cpu_flags(unsigned int f);
-#if TARGET_MSDOS == 32
-#pragma aux set_cpu_flags = \
- "push eax" \
- "popfd " \
- parm [eax];
-#else
-#pragma aux set_cpu_flags = \
- "push ax" \
- "popf " \
- parm [ax];
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-/* Watcom does not offer int86/int386 for Win32s/Win9x/NT/etc */
-#else
-static inline void just_int86(unsigned char c,union REGS *r1,union REGS *r2) {
-# ifdef __386__
- int386(c,r1,r2);
-# else
- int86(c,r1,r2);
-# endif
-}
-#endif
-
-#if TARGET_MSDOS == 32
-static inline void cpu_cpuid(uint32_t idx,struct cpuid_result *x);
-#pragma aux cpu_cpuid = \
- ".586p" \
- "xor ebx,ebx" \
- "mov ecx,ebx" \
- "mov edx,ebx" \
- "cpuid" \
- "mov [esi],eax" \
- "mov [esi+4],ebx" \
- "mov [esi+8],ecx" \
- "mov [esi+12],edx" \
- parm [eax] [esi] \
- modify [ebx ecx edx]
-#else
-void cpu_cpuid(uint32_t idx,struct cpuid_result *x);
-#endif
-
-#if TARGET_MSDOS == 32
-static inline uint64_t cpu_rdmsr(const uint32_t idx);
-#pragma aux cpu_rdmsr = \
- ".586p" \
- "rdmsr" \
- parm [ecx] \
- value [edx eax]
-
-static inline void cpu_wrmsr(const uint32_t idx,const uint64_t val);
-#pragma aux cpu_wrmsr = \
- ".586p" \
- "wrmsr" \
- parm [ecx] [edx eax]
-#else
-/* This is too much code to inline insert everywhere---unless you want extra-large EXEs.
- * It's better to conform to Watcom's register calling convention and make it a function.
- * Note that if you look at the assembly language most of the code is shuffling the values
- * around to convert EDX:EAX to AX:BX:CX:DX and disabling interrupts during the call. */
-/* see CPUASM.ASM */
-uint64_t cpu_rdmsr(const uint32_t idx);
-void cpu_wrmsr(const uint32_t idx,const uint64_t val);
-#endif
-
-#endif /* __HW_CPU_CPU_H */
+++ /dev/null
-; cpuasm.asm
-;
-; Runtime CPU detection library, assembly language portion
-; (C) 2009-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-
-; FIXME: This needs to provide CPUID for 16-bit real mode code (32-bit versions can use #pragma aux or inline asm)
-
-; NTS: We use NASM (Netwide Assembler) to achieve our goals here because WASM (Watcom Assembler) sucks.
-; I'll consider using their assembler when they get a proper conditional macro system in place.
-
-%if TARGET_MSDOS == 16
- %ifndef TARGET_WINDOWS
-extern _dpmi_pm_cs
-extern _dpmi_pm_ds
-extern _dpmi_pm_ss
-extern _dpmi_pm_es
-extern _dpmi_entered
-extern _dpmi_pm_entry
-extern _dpmi_rm_entry
- %endif
-%endif
-
-global cpu_basic_probe_
-extern _cpu_flags
-extern _cpu_tmp1
-extern _cpu_cpuid_max
-; char cpu_v86_active
-; extern _cpu_v86_active
-; char cpu_cpuid_vendor[13];
-extern _cpu_cpuid_vendor
-; struct cpu_cpuid_feature cpu_cpuid_features;
-extern _cpu_cpuid_features
-; NTS: Do NOT define variables here, Watcom or NASM is putting them in the wrong places (like at 0x000!)
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-; 0 = 8086
-; 1 = 186
-; 2 = 286
-; 3 = 386
-; 4 = 486
-
-; flags:
-; bit 0 = CPUID
-; bit 1 = FPU
-
-; caller is expected to zero cpu_flags prior to calling
-
-cpu_basic_probe_:
-%if TARGET_MSDOS == 16
- push bx
- push cx
- push dx
- push si
- push di
- push bp
-%else
- push ebx
- push ecx
- push edx
- push esi
- push edi
- push ebp
-%endif
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
-; BUGFIX: Calling near a function that returns far is like taking a long walk off a short pier
- push cs
- %else
- %ifidni MMODE,m
-; BUGFIX: Calling near a function that returns far is like taking a long walk off a short pier
- push cs
- %endif
- %endif
-%endif
- call cpu_basic_probe_f_
-%if TARGET_MSDOS == 16
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
-%else
- pop ebp
- pop edi
- pop esi
- pop edx
- pop ecx
- pop ebx
-%endif
- retnative
-
-cpu_basic_probe_f_:
-
- ; check: is a FPU present?
- fninit
- mov word [_cpu_tmp1],0x5A5A
- fnstsw word [_cpu_tmp1]
- cmp word [_cpu_tmp1],0
- jnz no_fpu ; so... if the FPU is not present the memory addr will never be updated?
-
- fnstcw word [_cpu_tmp1]
- mov ax,word [_cpu_tmp1]
- and ax,0x103F ; look at TOP and lower status flags (after FNINIT they are set?)
- cmp ax,0x003F
- jnz no_fpu
-
- or byte [_cpu_flags],2
-
-no_fpu:
-
-; 32-bit mode: If this code is executing then DUH the CPU is at least a 386.
-; Skip the 8086 test.
-%if TARGET_MSDOS == 16
- pushfn
- pop result
-
- ; an 8086 will always set bits 12-15
- and ax,0x0FFF
- push result
- popfn
- pushfn
- pop result
- and ax,0xF000
- cmp ax,0xF000
- jnz test286
- mov result,0
- retnative
-%endif
-
-test286:
-
-; 32-bit mode: If this code is executing then DUH the CPU is at least a 386.
-; Skip the 286 test.
-; 16-bit mode: Do the test, make sure to restore the original CFLAGS. Failure to do so is not fatal in
-; 16-bit real mode, but under Windows 3.1 can cause a nasty crash when this process terminates.
-%if TARGET_MSDOS == 16
- ; a 286 will always clear bits 12-15 (in real mode)
- pushfn ; save FLAGS
- or ax,0xF000
- push result
- popfn
- pushfn
- pop result
- popfn ; restore original FLAGS
- and ax,0xF000
- jnz test386 ; if ((val&0xF000) == 0) then AND shouldv'e left ZF=1
- mov result,2
- retnative
-%endif
-
-test386:
-
-; 32-bit mode: The following test is only useful for 16-bit real mode code.
-; in fact, in earlier 32-bit builds this part may have been responsible for hard crashes observed
-; with DOS4/GW and EMM386.EXE resident.
-; Don't do this test for Windows 3.1, it will always see the PM bit set. Instead the code in cpu.c
-; will call GetWinFlags
-%if TARGET_MSDOS == 16
- %ifndef TARGET_WINDOWS
- ; quick test: now that we know we're on a 386 or higher, are we running in Virtual 8086 mode?
- smsw ax
- and al,1
- mov cl,3
- shl al,cl ; NTS: do not use shl AL,3 we could be running on an 8086 which doesn't support it
- or byte [_cpu_flags],al ; cpu_flags |= (1 << 3) if v86 mode active
- %endif
-%endif
-
- pushfd
- pop eax
-
- ; a 386 will not allow setting the AC bit (bit 18)
- or eax,0x40000
- push eax
- popfd
- pushfd
- pop eax
- test eax,0x40000
- jnz test486
- mov result,3
- retnative
-
-test486:
-
- ; this is a 486 or higher, the last thing we want to check is whether the ID bit works (bit 21)
- and eax,~0x200000 ; clear ID
- push eax
- popfd
- pushfd
- pop eax
- test eax,0x200000
- jnz no_cpuid ; we masked it off, it should be zero
-
- or eax,0x200000 ; set ID
- push eax
- popfd
- pushfd
- pop eax
- test eax,0x200000
- jz no_cpuid ; we set it, it should be nonzero
-
- or byte [_cpu_flags],1
-
- ; 486 or Pentium with CPUID, so get the vendor string
- xor eax,eax
- cpuid
-
- mov point_s,_cpu_cpuid_vendor
- mov dword [point_s+0],ebx
- mov dword [point_s+4],edx
- mov dword [point_s+8],ecx
- mov byte [point_s+12],0
- mov [_cpu_cpuid_max],eax
-
- mov eax,1 ; ++EAX == 1
- cpuid
-
- mov point_s,_cpu_cpuid_features
- mov dword [point_s+0],eax
- mov dword [point_s+4],ebx
- mov dword [point_s+8],edx
- mov dword [point_s+12],ecx
-
- ; we care at this point ("basic check" remember?) only if it's a Pentium, Pentium II or higher (686), or otherwise
- ; NTS: EAX already loaded with EAX from CPUID(1)
- shr eax,8
- and eax,0xF
- cmp al,4
- jz cpuid_as_is
- cmp al,5
- jz cpuid_as_is
- cmp al,6
- jz cpuid_as_is
- mov al,6
-
-cpuid_as_is:
- retnative
-
-no_cpuid:
- mov result,4
- retnative
-
+++ /dev/null
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%if TARGET_MSDOS == 16
-; incoming Watcom convention:
-; DX:AX = CPUID register
-; BX = (near) pointer to struct OR
-; CX:BX = (far) pointer to struct
-global cpu_cpuid_
-cpu_cpuid_:
-%ifidni MMODE,l
- push ds
- push es
-%endif
-%ifidni MMODE,c
- push ds
- push es
-%endif
- pushf
- push ax
- push bx
- push cx
- push dx
- push si
- cli
-
- ; EAX = DX:AX
- shl edx,16
- and eax,0xFFFF
- or eax,edx
-
-%ifidni MMODE,l
- mov dx,ds
- mov es,dx
- mov ds,cx
-%endif
-%ifidni MMODE,c
- mov dx,ds
- mov es,dx
- mov ds,cx
-%endif
- mov si,bx ; CPUID will overwrite BX
-
-; SO:
-; EAX = CPUID function to execute
-; (DS):SI = pointer to structure to fill in with CPUID results
- cpuid
- mov dword [si],eax
- mov dword [si+4],ebx
- mov dword [si+8],ecx
- mov dword [si+12],edx
-
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
-%ifidni MMODE,l
- pop es
- pop ds
-%endif
-%ifidni MMODE,c
- pop es
- pop ds
-%endif
- retnative
-%endif
-
+++ /dev/null
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-/* Win16: We're probably on a 386, but we could be on a 286 if Windows 3.1 is in standard mode.
- * If the user manages to run us under Windows 3.0, we could also run in 8086 real mode.
- * We still do the tests so the Windows API cannot deceive us, but we still need GetWinFlags
- * to tell between 8086 real mode + virtual8086 mode and protected mode. */
-# include <windows.h>
-# include <toolhelp.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/cpu/cpuidext.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-# include <hw/dos/winfcon.h>
-#endif
-
-struct cpu_cpuid_ext_info* cpu_cpuid_ext_info = NULL;
-
-void cpu_extended_cpuid_info_free() {
- if (cpu_cpuid_ext_info) free(cpu_cpuid_ext_info);
- cpu_cpuid_ext_info = NULL;
-}
-
-int cpu_extended_cpuid_probe() {
- struct cpuid_result r={0};
-
- cpu_extended_cpuid_info_free();
-
- cpu_cpuid_ext_info = malloc(sizeof(struct cpu_cpuid_ext_info));
- if (cpu_cpuid_ext_info == NULL) return 0;
- memset(cpu_cpuid_ext_info,0,sizeof(struct cpu_cpuid_ext_info));
-
- if (cpu_flags & CPU_FLAG_CPUID) {
- /* probe for extended CPUID */
- cpu_cpuid(0x80000000UL,&r);
- if (r.eax >= 0x80000001UL) {
- cpu_cpuid_ext_info->cpuid_max = r.eax;
- cpu_flags |= CPU_FLAG_CPUID_EXT;
-
- cpu_cpuid(0x80000001UL,&r);
- cpu_cpuid_ext_info->features.a.raw[0] = r.eax;
- cpu_cpuid_ext_info->features.a.raw[1] = r.ebx;
- cpu_cpuid_ext_info->features.a.raw[2] = r.ecx;
- cpu_cpuid_ext_info->features.a.raw[3] = r.edx;
-
- if (cpu_cpuid_ext_info->cpuid_max >= 0x80000004UL) {
- cpu_cpuid(0x80000002UL,&r);
- ((uint32_t*)cpu_cpuid_ext_info->brand)[0] = r.eax;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[1] = r.ebx;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[2] = r.ecx;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[3] = r.edx;
-
- cpu_cpuid(0x80000003UL,&r);
- ((uint32_t*)cpu_cpuid_ext_info->brand)[4] = r.eax;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[5] = r.ebx;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[6] = r.ecx;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[7] = r.edx;
-
- cpu_cpuid(0x80000004UL,&r);
- ((uint32_t*)cpu_cpuid_ext_info->brand)[8] = r.eax;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[9] = r.ebx;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[10] = r.ecx;
- ((uint32_t*)cpu_cpuid_ext_info->brand)[11] = r.edx;
-
- cpu_cpuid_ext_info->brand[48] = 0;
- }
-
- if (cpu_cpuid_ext_info->cpuid_max >= 0x80000005UL) {
- cpu_cpuid(0x80000005UL,&r);
- cpu_cpuid_ext_info->cache_tlb.a.raw[0] = r.eax;
- cpu_cpuid_ext_info->cache_tlb.a.raw[1] = r.ebx;
- cpu_cpuid_ext_info->cache_tlb.a.raw[2] = r.ecx;
- cpu_cpuid_ext_info->cache_tlb.a.raw[3] = r.edx;
- }
-
- if (cpu_cpuid_ext_info->cpuid_max >= 0x80000006UL) {
- cpu_cpuid(0x80000006UL,&r);
- cpu_cpuid_ext_info->cache_tlb_l2.a.raw[0] = r.eax;
- cpu_cpuid_ext_info->cache_tlb_l2.a.raw[1] = r.ebx;
- cpu_cpuid_ext_info->cache_tlb_l2.a.raw[2] = r.ecx;
- cpu_cpuid_ext_info->cache_tlb_l2.a.raw[3] = r.edx;
- }
-
- if (cpu_cpuid_ext_info->cpuid_max >= 0x80000007UL) {
- cpu_cpuid(0x80000007UL,&r);
- cpu_cpuid_ext_info->apm.a.raw[0] = r.eax;
- }
-
- if (cpu_cpuid_ext_info->cpuid_max >= 0x80000008UL) {
- cpu_cpuid(0x80000008UL,&r);
- cpu_cpuid_ext_info->longmode.a.raw[0] = r.eax;
- cpu_cpuid_ext_info->longmode.a.raw[1] = r.ebx;
- cpu_cpuid_ext_info->longmode.a.raw[2] = r.ecx;
- cpu_cpuid_ext_info->longmode.a.raw[3] = r.edx;
- }
- }
- }
-
- return (cpu_flags & CPU_FLAG_CPUID_EXT)?1:0;
-}
-
+++ /dev/null
-
-#ifndef __HW_CPU_CPUIDEXT_H
-#define __HW_CPU_CPUIDEXT_H
-
-#include <stdint.h>
-#include <dos.h>
-
-#if !defined(FAR)
-# if defined(TARGET_WINDOWS)
-# include <windows.h>
-# else
-# if TARGET_MSDOS == 32
-# define FAR
-# else
-# define FAR far
-# endif
-# endif
-#endif
-
-/* has L1 TLB/CACHE info */
-#define cpu_cpuid_ext_info_has_cache_tlb_l1 (cpu_cpuid_ext_info && cpu_cpuid_ext_info->cpuid_max >= 0x80000005UL)
-
-/* has L2 TLB/CACHE info */
-#define cpu_cpuid_ext_info_has_cache_tlb_l2 (cpu_cpuid_ext_info && cpu_cpuid_ext_info->cpuid_max >= 0x80000006UL)
-
-/* has APM info */
-#define cpu_cpuid_ext_info_has_apm (cpu_cpuid_ext_info && cpu_cpuid_ext_info->cpuid_max >= 0x80000007UL)
-
-/* has Long mode info */
-#define cpu_cpuid_ext_info_has_longmode (cpu_cpuid_ext_info && cpu_cpuid_ext_info->cpuid_max >= 0x80000008UL)
-
-struct cpu_cpuid_ext_info {
- char brand[49];
- uint32_t cpuid_max;
- struct cpu_cpuid_ext_features features;
- struct cpu_cpuid_ext_cache_tlb cache_tlb;
- struct cpu_cpuid_ext_cache_tlb_l2 cache_tlb_l2;
- struct cpu_cpuid_ext_apm apm;
- struct cpu_cpuid_ext_longmode longmode;
-};
-
-extern struct cpu_cpuid_ext_info* cpu_cpuid_ext_info;
-
-int cpu_extended_cpuid_probe();
-void cpu_extended_cpuid_info_free();
-
-#endif /* __HW_CPU_CPUIDEXT_H */
-
+++ /dev/null
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%if TARGET_MSDOS == 16
-; uint32_t __cdecl inpd(uint16_t port);
-global _inpd
-_inpd: push bp
- mov bp,sp
- mov dx,[bp+cdecl_param_offset]
- in eax,dx
- mov dx,ax
- shr eax,16
- xchg dx,ax
- pop bp
- retnative
-
-; void __cdecl outpd(uint16_t port,uint32_t data);
-global _outpd
-_outpd: push bp
- mov bp,sp
- mov dx,[bp+cdecl_param_offset]
- mov eax,[bp+cdecl_param_offset+2]
- out dx,eax
- pop bp
- retnative
-%endif
-
+++ /dev/null
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-; struct cpu_serial_number cpu_serial;
-extern _cpu_serial
-
-; cpu_disable_serial(): Disable the Processor Serial Number on Intel
-; Pentium III processors that have it.
-;
-; Note that you cannot re-enable the processor serial number from
-; software and it will not come back until a full reboot. This is by
-; design.
-;
-; Warning: This routine does not check for you whether the CPU supports
-; it. If your CPU does not support this function the resulting
-; fault is your responsibility.
-;
-; Warning: This code will likely cause a fault if run within virtual
-; 8086 mode.
-global cpu_disable_serial_
-cpu_disable_serial_:
- push eax
- push ecx
- push edx
- mov ecx,0x119
- rdmsr
- or eax,0x200000
- wrmsr
- pop edx
- pop ecx
- pop eax
- retnative
-
-; cpu_ask_serial(): Read the Processor Serial Number on Intel Pentium III
-; processors.
-;
-; Warning: This does not check whether your CPU supports the feature. Checking
-; for PSN support is your responsibility, else the CPU will issue a fault and
-; crash your program. Note that if the serial number was disabled by software
-; this code will cause a fault as if the feature were never present.
-global cpu_ask_serial_
-cpu_ask_serial_:
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- push ds
- %endif
- %ifidni MMODE,c
- push ds
- %endif
-%endif
- push eax
- push ebx
- push ecx
- push edx
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- mov ax,seg _cpu_serial
- mov ds,ax
- %endif
- %ifidni MMODE,c
- mov ax,seg _cpu_serial
- mov ds,ax
- %endif
-%endif
-
- xor ebx,ebx
- mov ecx,ebx
- mov edx,ebx
- mov eax,3
- cpuid
- mov dword [_cpu_serial+0],edx
- mov dword [_cpu_serial+4],ecx
- mov dword [_cpu_serial+8],ebx
- mov dword [_cpu_serial+12],eax
-
- pop edx
- pop ecx
- pop ebx
- pop eax
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- pop ds
- %endif
- %ifidni MMODE,c
- pop ds
- %endif
-%endif
- retnative
-
+++ /dev/null
-
-#include <stdint.h>
-#include <dos.h>
-
-#pragma pack(push,1)
-struct cpu_serial_number {
- uint32_t raw[4]; /* EDX, ECX, EBX, EAX */
-};
-#pragma pack(pop)
-
-/* WARNING: Caller is expected to check CPUID information to ensure the
- processor supports this feature! */
-void cpu_ask_serial();
-void cpu_disable_serial();
-extern struct cpu_serial_number cpu_serial;
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/cpup3sn.h>
-
-struct cpu_serial_number cpu_serial = {0};
-
+++ /dev/null
-
-global cpu_basic_probe_
-extern _cpu_flags
-extern _cpu_tmp1
-extern _cpu_cpuid_max
-; char cpu_v86_active
-; extern _cpu_v86_active
-; char cpu_cpuid_vendor[13];
-extern _cpu_cpuid_vendor
-; struct cpu_cpuid_feature cpu_cpuid_features;
-extern _cpu_cpuid_features
-; NTS: Do NOT define variables here, Watcom or NASM is putting them in the wrong places (like at 0x000!)
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%if TARGET_MSDOS == 16
-; WARNING: Do not execute this instruction when you are a Windows application.
-; The Windows VM doesn't take it well.
-; uint64_t __cdecl cpu_rdmsr(uint32_t val):
-; read MSR and return.
-; places 64-bit value in AX:BX:CX:DX according to Watcom register calling convention
-global cpu_rdmsr_
-cpu_rdmsr_:
- pushf
- cli
-
- ; assemble EAX = DX:AX 32-bit value given to us
- shl edx,16
- mov dx,ax
- mov ecx,edx
-
- ; doit
- rdmsr
-
- ; reshuffle to return as 64-bit value in AX:BX:CX:DX
- xchg eax,edx
- mov ecx,edx
- mov ebx,eax
- shr eax,16
- shr ecx,16
-
- popf
- retnative
-%endif
-
+++ /dev/null
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%if TARGET_MSDOS == 16
-; cpu_rdtsc():
-; read RDTSC and return.
-; places 64-bit value in AX:BX:CX:DX according to Watcom register calling convention
-global cpu_rdtsc_
-cpu_rdtsc_:
- pushf
- cli
- rdtsc
- xchg eax,edx
- mov ecx,edx
- mov ebx,eax
- shr eax,16
- shr ecx,16
- popf
- retnative
-%endif
-
-%if TARGET_MSDOS == 16
-; WARNING: Do not execute this instruction when you are a Windows application.
-; The Windows VM doesn't take it well.
-; void __cdecl cpu_rdtsc_write(uint64_t val):
-; write RDTSC and return.
-global cpu_rdtsc_write_
-cpu_rdtsc_write_:
- pushf
- push ax
- push bx
- push cx
- push dx
- cli
-
- ; assemble EAX = AX:BX
- shl eax,16
- mov ax,bx
-
- ; assemble EDX = CX:DX
- shl ecx,16
- and edx,0xFFFF
- or edx,ecx
-
- ; doit
- xchg eax,edx
- mov ecx,0x10
- wrmsr
-
- pop dx
- pop cx
- pop bx
- pop ax
- popf
- retnative
-%endif
-
+++ /dev/null
-/* rdtsc.h
- *
- * Library of functions to read the Pentium TSC register.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#ifndef __HW_CPU_RDTSC_H
-#define __HW_CPU_RDTSC_H
-
-#include <stdint.h>
-
-typedef uint64_t rdtsc_t;
-
-#if TARGET_MSDOS == 32
-static inline uint64_t cpu_rdtsc();
-#pragma aux cpu_rdtsc = \
- ".586p" \
- "rdtsc" \
- value [edx eax]
-
-static inline void cpu_rdtsc_write(const uint64_t val);
-#pragma aux cpu_rdtsc_write = \
- ".586p" \
- "mov ecx,0x10" \
- "wrmsr" \
- parm [edx eax] \
- modify [ecx]
-#else
-/* This is too much code to inline insert everywhere---unless you want extra-large EXEs.
- * It's better to conform to Watcom's register calling convention and make it a function.
- * Note that if you look at the assembly language most of the code is shuffling the values
- * around to convert EDX:EAX to AX:BX:CX:DX and disabling interrupts during the call. */
-uint64_t cpu_rdtsc();
-void cpu_rdtsc_write(const uint64_t val);
-#endif
-
-#endif /* __HW_CPU_RDTSC_H */
-
+++ /dev/null
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-/* Win16: We're probably on a 386, but we could be on a 286 if Windows 3.1 is in standard mode.
- * If the user manages to run us under Windows 3.0, we could also run in 8086 real mode.
- * We still do the tests so the Windows API cannot deceive us, but we still need GetWinFlags
- * to tell between 8086 real mode + virtual8086 mode and protected mode. */
-# include <windows.h>
-# include <toolhelp.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/cpu/cpusse.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-# include <hw/dos/winfcon.h>
-#endif
-
-unsigned char cpu_sse_usable = 0;
-unsigned char cpu_sse_usable_probed = 0;
-unsigned char cpu_sse_usable_can_turn_on = 0;
-unsigned char cpu_sse_usable_can_turn_off = 0;
-const char* cpu_sse_unusable_reason = NULL;
-const char* cpu_sse_usable_detection_method = NULL;
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-static unsigned char faulted = 0;
-
-static void __declspec(naked) fault_int6_vec() {
- /* the test routine executes a XORPS xmm0,xmm0 (3 bytes long).
- * if we just IRET the CPU will go right back and execute it again */
-# if TARGET_MSDOS == 32
- __asm {
- push ds
- push eax
- mov ax,seg faulted
- mov ds,ax
- pop eax
- mov faulted,1
- pop ds
- add dword ptr [esp],3
- iretd
- }
-# else
- __asm {
- push bp
- mov bp,sp
- add word ptr [bp+2],3
- push ds
- mov bp,seg faulted
- mov ds,bp
- mov faulted,1
- pop ds
- pop bp
- iretf
- }
-# endif
-}
-
-# if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-unsigned int _cdecl cpu_dpmi_win9x_sse_test();
-# endif
-
-# if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-static void __declspec(naked) fault_int6() { /* DPMI exception handler */
- __asm {
- .386p
- push ds
- push eax
- mov ax,seg faulted
- mov ds,ax
- mov faulted,1
- add dword ptr [esp+8+12],3 /* +3 bytes for 'xorps xmm0,xmm0' */
- pop eax
- pop ds
- retf
- }
-}
-# endif
-#elif defined(TARGET_WINDOWS) && TARGET_MSDOS == 16 && !defined(TARGET_OS2)
-static unsigned char faulted = 0;
-
-/* SS:SP + 12h = SS (fault)
- * SS:SS + 10h = SP (fault)
- * SS:SP + 0Eh = FLAGS (fault)
- * SS:SP + 0Ch = CS (fault)
- * SS:SP + 0Ah = IP (fault)
- * SS:SP + 08h = handle (internal)
- * SS:SP + 06h = interrupt number
- * SS:SP + 04h = AX (to load into DS)
- * SS:SP + 02h = CS (toolhelp.dll)
- * SS:SP + 00h = IP (toolhelp.dll)
- *
- * to pass exception on: RETF
- * to restart instruction: clear first 10 bytes of the stack, and IRET (??) */
-static void __declspec(naked) fault_int6_toolhelp() {
- __asm {
- .386p
- push ds
- push ax
- push bp
- mov bp,sp
-
- /* is this for INT 6h? */
- cmp word ptr [bp+6+6],6 /* SS:SP + 06h = interrupt number */
- jnz pass_on
-
- /* set the faulted flag, change the return address, then IRET directly back */
- mov ax,seg faulted
- mov ds,ax
- mov faulted,1
- add word ptr [bp+6+10],3
- pop bp
- pop ax
- pop ds
- add sp,0Ah /* throw away handle, int number, and CS:IP return */
- iret
-
-/* tell ToolHelp we didn't handle the interrupt */
-pass_on: retf
- }
-}
-
-static void __declspec(naked) fault_int6() { /* DPMI exception handler */
- __asm {
- .386p
- push ds
- push ax
- push bp
- mov bp,sp
- mov ax,seg faulted
- mov ds,ax
- mov faulted,1
- add word ptr [bp+6+6],3
- pop bp
- pop ax
- pop ds
- retf
- }
-}
-#endif
-
-/* check if SSE is usable. Just because CPUID says it's there
- * doesn't mean the OS enabled it.
- *
- * if do_enable is nonzero and the function detects that it's
- * possible, the function will enable SSE and return success */
-int cpu_check_sse_is_usable() {
- if (!cpu_sse_usable_probed) {
- cpu_sse_usable_probed = 1;
- cpu_sse_usable = 0;
- cpu_sse_unusable_reason = "";
- cpu_sse_usable_detection_method = "None";
- cpu_sse_usable_can_turn_off = 0;
- cpu_sse_usable_can_turn_on = 0;
-
- if (cpu_basic_level < 0) cpu_probe();
-
- if (!(cpu_flags & CPU_FLAG_CPUID)) {
- cpu_sse_unusable_reason = "No CPUID available";
- return 0;
- }
- if (!(cpu_cpuid_features.a.raw[2] & (1UL << 25UL))) {
- cpu_sse_unusable_reason = "CPUID indicates SSE is not present";
- return 0;
- }
-
-#ifdef TARGET_WINDOWS
-/* ==================== RUNNING WITHIN WINDOWS =================== */
-/* Within Windows, we have no way to enable SSE if the OS kernel doesn't support it.
- * So we first must learn whether or not the OS supports it.
- * Guide: Windows NT/2000/XP/Vista/etc... you can use IsProcessorFeaturePresent()
- * Windows 95/98/ME... there is no way other than attempting the instruction to see if it causes a fault.
- * Windows 3.1/3.0... NO. And you cannot enable it either! Buuuuut.... if the Windows 3.1 binary is run
- * under Windows XP/ME/98 and the kernel has SSE enabled, then it is possible to use SSE instructions.
- *
- * NOTE: Any Windows 9x kernel prior to 98SE does not support SSE, but if something happens to enable it in CR4
- * prior to Windows taking control, then it will stay enabled while Windows is running. Those versions
- * treat the SSE enable bit as unknown and they don't change it. BUT also realize that the SSE registers
- * are not saved and restored by the kernel scheduler! If you are the only process that will be using SSE
- * that is fine, but if two or more tasks try to use SSE there will be serious conflicts and possibly
- * a crash.
- *
- * Reading CR4 to determine availability has the same effects as it does for the MS-DOS code, either
- * nonsense values (Windows 9x/ME) or it causes a fault (Windows NT). */
- detect_windows();
-# if TARGET_MSDOS == 32
-# ifdef WIN386
- /* Windows 3.0/3.1 Win386: the underlying system is 16-bit and we're 32-bit through an extender */
- cpu_sse_unusable_reason = "SSE support for Windows 3.x Win386 is not implemented";
- return 0;
-# else
- {
- BOOL (WINAPI *__IsProcFeaturePresent)(DWORD f) = NULL;
-
- if (windows_mode == WINDOWS_NT)
- __IsProcFeaturePresent = (BOOL (WINAPI *)(DWORD))GetProcAddress(GetModuleHandle("KERNEL32.DLL"),"IsProcessorFeaturePresent");
-
- if (__IsProcFeaturePresent != NULL) {
- cpu_sse_usable_detection_method = "IsProcessorFeaturePresent [WinNT]";
- printf("Using IsProcessorFeaturePresent\n");
- if (!__IsProcFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
- cpu_sse_unusable_reason = "Windows NT HAL says SSE not enabled";
- else
- cpu_sse_usable = 1;
- }
- else {
- BYTE ok=1;
-
- cpu_sse_usable_detection_method = "Executing SSE to see if it causes a fault [Win31s/9x/ME/NT]";
-
- /* we just have to try */
- __try {
- __asm {
- .686p
- .xmm
- xorps xmm0, xmm0
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER) {
- ok = 0;
- }
-
- if (!ok) {
- cpu_sse_unusable_reason = "Windows 3.1/9x/ME kernel does not have SSE enabled";
- return 0;
- }
- else {
- cpu_sse_usable = 1;
- }
- }
- }
-# endif
-# else /* TARGET_MSDOS == 16 */
- if ((windows_mode == WINDOWS_STANDARD || windows_mode == WINDOWS_ENHANCED) && windows_version < 0x35F) {
- /* Windows 3.0/3.1: We can abuse the DPMI server to hook INT 6h exceptions.
- * Very clean, and it does not require TOOLHELP.DLL. But it doesn't work under Windows 9x/ME.
- * The DPMI call silently fails and KERNEL32.DLL catches the fault without passing it on to us. */
- void far *op;
-
- op = win16_getexhandler(6);
- cpu_sse_usable_detection_method = "Hooking INT 6, executing SSE to see if it causes a fault [Win16]";
- if (win16_setexhandler(6,fault_int6)) {
- faulted = 0;
- __asm {
- .686p
- .xmm
- xorps xmm0, xmm0
- }
- win16_setexhandler(6,op);
- }
- else {
- win16_setexhandler(6,op);
- cpu_sse_unusable_reason = "Unable to hook INT 6 by DPMI";
- return 0;
- }
-
- if (faulted) {
- cpu_sse_unusable_reason = "Windows 3.x kernel does not have SSE enabled";
- return 0;
- }
- else {
- cpu_sse_usable = 1;
- }
- }
- /* Windows 9x/ME. Abusing DPMI as in Windows 3.1 doesn't work, the calls silently fail. But Microsoft
- * apparently made sure the TOOLHELP API functions do their job, so we use that technique. It even works
- * under NTVDM.EXE in Windows NT/2000/XP */
- else if ((windows_mode == WINDOWS_STANDARD || windows_mode == WINDOWS_ENHANCED || windows_mode == WINDOWS_NT) && ToolHelpInit()) {
- cpu_sse_usable_detection_method = "InterruptRegister/TOOLHELP.DLL, executing SSE to see if it causes a fault [Win16]";
- if (__InterruptRegister(NULL,MakeProcInstance((FARPROC)fault_int6_toolhelp,_win_hInstance))) {
- faulted = 0;
- __asm {
- .686p
- .xmm
- xorps xmm0, xmm0
- }
-
- if (!__InterruptUnRegister(NULL))
- MessageBox(NULL,"WARNING: Unable to unregister interrupt","",MB_OK);
-
- if (faulted) {
- cpu_sse_unusable_reason = "Windows 9x/ME/NT kernel does not have SSE enabled";
- return 0;
- }
- else {
- cpu_sse_usable = 1;
- }
- }
- else {
- MessageBox(NULL,"WARNING: Unable to register interrupt","",MB_OK);
- }
- }
- else {
- cpu_sse_unusable_reason = "This library does not have support for detecting SSE from Win16 under Windows 3.0 Real Mode";
- return 0;
- }
-# endif
-#elif defined(TARGET_OS2)
-/* ==================== RUNNING AS OS/2 APP ====================== */
- /* TODO */
- cpu_sse_unusable_reason = "Assuming not present";
- cpu_sse_usable = 0;
- cpu_sse_usable_detection_method = "None";
- cpu_sse_usable_can_turn_on = 0;
- cpu_sse_usable_can_turn_off = 0;
-#else
-/* ==================== RUNNING AS MS-DOS APP ==================== */
- detect_windows();
-
- if ((windows_mode == WINDOWS_STANDARD || windows_mode == WINDOWS_ENHANCED) && TARGET_MSDOS == 16) {
-#if TARGET_MSDOS == 16
- /* Windows 9x/ME DOS box.
- * we can't read the control registers, and hooking INT 6 doesn't work. If the SSE test causes
- * an Invalid Opcode exception Windows 9x will NOT forward the exception down to us!
- * Same with Windows 3.0/3.1 Standard/Enhanced mode!
- *
- * But, Windows 9x does offer DPMI. So to carry out the test, we use DPMI to enter protected mode,
- * set up DPMI exception handlers, perform the test, and then use DPMI to exit back to real mode
- * with the results.
- *
- * Note that this code is not necessary for Windows NT/2000/XP/Vista/etc. as NTVDM.EXE contains
- * code to forward the Invalid Opcode exception to us if it sees that we hooked it */
- cpu_sse_usable_detection_method = "Hook INT 6h, execute SSE to see if it causes a fault [DPMI under Win 3.1/9x/ME DOS box]";
- probe_dpmi();
- if (dpmi_present) {
- /* to carry out this test, we must enter protected mode through DPMI. we must initialize
- * DPMI if not already done, or if the caller has already gone through DPMI, we must
- * enter using whatever bit width he chose.
- *
- * NOTE: This means then, that if the calling program needs DPMI the program must have
- * set it's own preferences up prior to calling this function, because otherwise
- * you're going to be stuck with our preferences. Now maybe if DPMI had thought
- * about something like... I dunno... a way to un-initialize DPMI for itself,
- * maybe we wouldn't have this problem, would we? */
- if (dpmi_entered == 0)
- dpmi_enter(DPMI_ENTER_AUTO);
-
- if (dpmi_entered != 0) {
- unsigned int reason = cpu_dpmi_win9x_sse_test();
- if (reason == 0) {
- /* it worked */
- cpu_sse_usable = 1;
- }
- else if (reason == 1) {
- /* test OK, sse not available */
- cpu_sse_unusable_reason = "SSE is currently disabled, nobody has enabled it yet";
- }
- }
- else {
- cpu_sse_unusable_reason = "Unable to enter DPMI protected mode";
- }
- }
- else {
- cpu_sse_unusable_reason = "As an MS-DOS application I have no way to test for SSE from within Win 3.1/9x/ME DOS box, DPMI is not available";
- }
-#endif
- }
- else if (cpu_v86_active || windows_mode == WINDOWS_NT ||
- ((windows_mode == WINDOWS_STANDARD || windows_mode == WINDOWS_ENHANCED) && TARGET_MSDOS == 32)) {
- /* pure DOS mode with virtual 8086 mode, or Windows NT DOS box.
- * we can't read the control registers (or under EMM386.EXE we can, but within v86 mode it's
- * not wise to assume that we can). Note that DOS32a is able to catch Invalid Opcode exceptions,
- * even from within Windows 9x/ME/NT, so when compiled as a 32-bit DOS app we also need to use DPMI functions
- * "set exception handler" to ensure that we catch the fault. */
- void far *oh;
-#if TARGET_MSDOS == 32
- void far *oh_ex;
-#endif
-
- cpu_sse_usable_detection_method = "Hook INT 6h, execute SSE to see if it causes a fault [MS-DOS]";
-
-#if TARGET_MSDOS == 32
- oh_ex = dpmi_getexhandler(6);
- dpmi_setexhandler(6,(void far*)fault_int6);
-#endif
-
- oh = _dos_getvect(6);
- _dos_setvect(6,(void far*)fault_int6_vec);
-
- __asm {
- .686p
- .xmm
- xorps xmm0, xmm0
- }
-
- _dos_setvect(6,oh);
-#if TARGET_MSDOS == 32
- dpmi_setexhandler(6,oh_ex);
-#endif
-
- /* TODO: If we're in pure DOS mode, and virtual 8086 mode is active, and we know VCPI is present,
- * then it is possible for us to enable/disable SSE by switching into protected mode via VCPI */
-
- if (faulted) {
- cpu_sse_unusable_reason = "SSE is currently disabled, nobody has enabled it yet";
- }
- else {
- cpu_sse_usable = 1;
- }
- }
- else {
- /* pure DOS mode. we can read the control registers without crashing */
- uint32_t v=0;
-
- cpu_sse_usable_detection_method = "80386 MOV CR4 [MS-DOS]";
-
- __asm {
- .386p
- mov eax,cr4
- mov v,eax
- }
-
- if (v & 0x200) {
- cpu_sse_usable = 1;
- }
- else {
- cpu_sse_unusable_reason = "SSE is currently disabled";
- }
-
- cpu_sse_usable_can_turn_on = 1;
- cpu_sse_usable_can_turn_off = 1;
- }
-#endif /* TARGET_WINDOWS */
- }
-
- return cpu_sse_usable;
-}
-
-int cpu_sse_disable() {
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
- uint32_t confidence=0;
-#endif
-
- if (!(cpu_flags & CPU_FLAG_CPUID))
- return 0;
- if (!(cpu_cpuid_features.a.raw[2] & (1UL << 25UL)))
- return 0;
- if (!cpu_sse_usable_can_turn_off)
- return 0;
-
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
- return 0; /* it's very unlikely we could ever touch the control registers from within Windows */
- /* FIXME: Maybe as a Win32 app under Windows 9x we could try? */
-#else
- __asm {
- .386p
- mov eax,cr4
- and eax,0xFFFFFDFF /* bit 9 */
- mov cr4,eax
- mov ebx,eax /* remember what we wrote */
-
- mov eax,cr4
- and eax,0x200
- and ebx,0x200
- xor eax,ebx
- mov confidence,eax /* EAX = nonzero if write didn't work */
- }
-
- if (confidence) {
- cpu_sse_unusable_reason = "Attempting to write CR4 failed";
- return 0;
- }
-
- cpu_sse_usable = 0;
- return 1;
-#endif
-}
-
-int cpu_sse_enable() {
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
- uint32_t confidence=0;
-#endif
-
- if (!(cpu_flags & CPU_FLAG_CPUID))
- return 0;
- if (!(cpu_cpuid_features.a.raw[2] & (1UL << 25UL)))
- return 0;
- if (!cpu_sse_usable_can_turn_on)
- return 0;
-
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
- return 0; /* it's very unlikely we could ever touch the control registers from within Windows */
- /* FIXME: Maybe as a Win32 app under Windows 9x we could try? */
-#else
- __asm {
- .386p
- mov eax,cr4
- or eax,0x200 /* bit 9 */
- mov cr4,eax
- mov ebx,eax /* remember what we wrote */
-
- mov eax,cr4
- and eax,0x200
- and ebx,0x200
- xor eax,ebx
- mov confidence,eax /* EAX = nonzero if write didn't work */
- }
-
- if (confidence) {
- cpu_sse_unusable_reason = "Attempting to write CR4 failed";
- return 0;
- }
-
- cpu_sse_usable = 1;
- return 1;
-#endif
-}
-
+++ /dev/null
-
-extern unsigned char cpu_sse_usable;
-extern unsigned char cpu_sse_usable_probed;
-extern const char* cpu_sse_unusable_reason;
-extern unsigned char cpu_sse_usable_can_turn_on;
-extern unsigned char cpu_sse_usable_can_turn_off;
-extern const char* cpu_sse_usable_detection_method;
-
-int cpu_check_sse_is_usable();
-int cpu_sse_disable();
-int cpu_sse_enable();
-
+++ /dev/null
-
-%if TARGET_MSDOS == 16
- %ifndef TARGET_WINDOWS
-extern _dpmi_pm_cs
-extern _dpmi_pm_ds
-extern _dpmi_pm_ss
-extern _dpmi_pm_es
-extern _dpmi_entered
-extern _dpmi_pm_entry
-extern _dpmi_rm_entry
- %endif
-%endif
-
-global cpu_basic_probe_
-extern _cpu_flags
-extern _cpu_tmp1
-extern _cpu_cpuid_max
-; char cpu_v86_active
-; extern _cpu_v86_active
-; char cpu_cpuid_vendor[13];
-extern _cpu_cpuid_vendor
-; struct cpu_cpuid_feature cpu_cpuid_features;
-extern _cpu_cpuid_features
-; NTS: Do NOT define variables here, Watcom or NASM is putting them in the wrong places (like at 0x000!)
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef TARGET_WINDOWS
-; unsigned int _cdecl cpu_dpmi_win9x_sse_test();
-; NOTE: The caller should have first checked dpmi_present, and that dpmi_pm_entry, and dpmi_rm_entry
-; are valid. We assume they are.
-global _cpu_dpmi_win9x_sse_test
-_cpu_dpmi_win9x_sse_test:
- push ds
- push es
- push ss
-
-; copy return vector
- mov ax,seg _dpmi_rm_entry
- mov ds,ax
- mov ax,[_dpmi_rm_entry+0]
- mov word [cs:_cpu_dpmi_return_vec+0],ax
- mov ax,[_dpmi_rm_entry+2]
- mov word [cs:_cpu_dpmi_return_vec+2],ax
- mov ax,[_dpmi_rm_entry+4]
- mov word [cs:_cpu_dpmi_return_vec+4],ax
-
-; save some key registers
- mov word [cs:_cpu_dpmi_saved_cs],cs
- mov word [cs:_cpu_dpmi_saved_ss],ss
- mov ax,sp
- mov word [cs:_cpu_dpmi_saved_sp],ax
-
- mov ax,seg _dpmi_entered
- mov ds,ax
- mov al,[_dpmi_entered]
- mov byte [cs:_cpu_dpmi_mode],al
- mov byte [cs:_cpu_dpmi_result],0
-
-; enter protected mode
- mov ax,seg _dpmi_pm_ds
- mov ds,ax
- mov ax,[_dpmi_pm_ds]
- mov cx,ax
-
- mov dx,seg _dpmi_pm_ss
- mov ds,dx
- mov dx,[_dpmi_pm_ss]
-
- mov si,seg _dpmi_pm_cs
- mov ds,si
- mov si,[_dpmi_pm_cs]
-
- mov bx,seg _dpmi_pm_entry
- mov es,bx
- mov bx,sp
- mov di,.enterpm
- jmp far word [es:_dpmi_pm_entry]
-.enterpm:
-; remember: when the DOS code first entered, DS == CS so DS is an alias to CS
-
-; the path we take depends on 16-bit or 32-bit dpmi!
- cmp byte [cs:_cpu_dpmi_mode],32
- jz .path32
-; 16-bit path
- mov ax,0x0202 ; get current exception vector for #UD
- mov bl,0x06
- int 31h
- push cx
- push dx ; save on stack
-
- mov ax,0x0203 ; set exception vector for #UD to our test routine
- mov bl,0x06
- mov cx,cs
- mov edx,_cpu_dpmi_win9x_sse_test_except16
- int 31h
-
- ; the exception handler will set DS:_cpu_dpmi_result = 1
- xorps xmm0,xmm0
-
- pop dx ; restore exception vector for #UD
- pop cx
- mov ax,0x0203
- mov bl,0x06
- int 31h
-
- ; now return to real mode
- mov ax,word [_cpu_dpmi_saved_cs]
- mov cx,ax
- mov si,ax
- mov dx,word [_cpu_dpmi_saved_ss]
- mov bx,sp
- mov di,.exitpm
- jmp far word [_cpu_dpmi_return_vec]
-; 32-bit path
-.path32:
- mov ax,0x0202 ; get current exception vector for #UD
- mov bl,0x06
- int 31h
- push ecx
- push edx ; save on stack
-
- mov ax,0x0203 ; set exception vector for #UD to our test routine
- mov bl,0x06
- mov cx,cs
- mov edx,_cpu_dpmi_win9x_sse_test_except32
- int 31h
-
- ; the exception handler will set DS:_cpu_dpmi_result = 1
- xorps xmm0,xmm0
-
- pop edx ; restore exception vector for #UD
- pop ecx
- mov ax,0x0203
- mov bl,0x06
- int 31h
-
- ; now return to real mode
- mov ax,word [_cpu_dpmi_saved_cs]
- mov cx,ax
- mov si,ax
- mov dx,word [_cpu_dpmi_saved_ss]
- mov bx,sp
- mov di,.exitpm
- jmp far dword [_cpu_dpmi_return_vec]
-
-.exitpm:
-; exit point
- pop ss
- pop es
- pop ds
- movzx result,byte [cs:_cpu_dpmi_result]
- retnative
-
-; exception handler. skip the offending instruction by directly modifying "IP" on the stack
-_cpu_dpmi_win9x_sse_test_except32:
- push bp
- mov bp,sp
- mov byte [_cpu_dpmi_result],1
- add dword [bp+2+12],3 ; 'xorps xmm0,xmm0' is 3 bytes long
- pop bp
- o32 retf
-
-; exception handler. skip the offending instruction by directly modifying "IP" on the stack
-_cpu_dpmi_win9x_sse_test_except16:
- push bp
- mov bp,sp
- mov byte [_cpu_dpmi_result],1
- add word [bp+2+6],3 ; 'xorps xmm0,xmm0' is 3 bytes long
- pop bp
- retf
-
-_cpu_dpmi_saved_cs dw 0
-_cpu_dpmi_saved_ss dw 0
-_cpu_dpmi_saved_sp dw 0
-_cpu_dpmi_mode db 0
-_cpu_dpmi_result db 0
-_cpu_dpmi_return_vec dd 0
- dw 0
-
- %endif
-%endif
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-
-const char *cpu_basic_level_str[CPU_MAX] = {
- "8086",
- "186",
- "286",
- "386",
- "486",
- "586",
- "686"
-};
-
+++ /dev/null
-/* dispsn.c
- *
- * Runtime CPU detection library:
- * demonstration program on disabling the Pentium III serial number.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS
- * - Windows 3.0/3.1/95/98/ME
- * - Windows NT 3.1/3.51/4.0/2000/XP/Vista/7
- * - OS/2 16-bit
- * - OS/2 32-bit
- *
- * Demonstrates detecting the Pentium III serial number, and whether we can
- * disable it */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/cpup3sn.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main(int argc,char **argv,char **envp) {
- int testval = -1; /* TEST FOR BUGFIX: Failure to save registers during call */
- cpu_probe();
- assert(testval == -1);
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
- if (cpu_v86_active)
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
- if (!(cpu_flags & CPU_FLAG_CPUID)) {
- printf(" - Your CPU does not support CPUID, how could it support the PSN?\n");
- return 1;
- }
- if (!(cpu_cpuid_features.a.raw[2] & (1UL << 18UL))) {
- printf(" - CPU does not support PSN, or has already disabled it\n");
- return 1;
- }
-
- if (argc > 1 && !strcmp(argv[1],"doit")) {
-#if defined(TARGET_WINDOWS)
- printf("I don't think the Windows kernel would ever let me turn off the Processor Serial Number.\n");
-#else
- if (cpu_v86_active) {
- printf("Virtual 8086 mode is active, I cannot switch off the Processor Serial Number.\n");
- }
- else {
- printf("Disabling PSN... "); fflush(stdout);
- cpu_disable_serial();
- printf("OK\n");
- }
-#endif
- }
- else {
- printf("To disable the processor serial number, type 'dispsn doit'\n");
- }
-
- return 0;
-}
-
+++ /dev/null
-/* gdt_enum.c
- *
- * Library for reading the Global Descriptor Table if possible.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS
- * - Windows 3.0/3.1/95/98/ME
- * - Windows NT 3.1/3.51/4.0/2000/XP/Vista/7
- * - OS/2 16-bit
- * - OS/2 32-bit
- *
- * If the host OS is loose, or unprotected, this library can abuse the
- * loophole to read the contents of the Global Descriptor Table. Note
- * that this is possible under Windows 3.0/3.1/95/98/ME because they
- * leave it out in the open. Windows NT does NOT let us do this!! Neither
- * does OS/2!
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/cpu/gdt_enum.h>
-
-unsigned char cpu_gdtlib_can_read = 0,cpu_gdtlib_can_write = 0,cpu_gdtlib_result = 0xFF;
-uint16_t cpu_gdtlib_ldtr = 0;
-struct x86_gdtr cpu_gdtlib_gdtr;
-struct cpu_gdtlib_entry cpu_gdtlib_ldt_ent;
-#if TARGET_MSDOS == 16 && defined(TARGET_WINDOWS)
-uint16_t cpu_gdtlib_gdt_sel = 0; /* selector for reading GDT table */
-uint16_t cpu_gdtlib_ldt_sel = 0; /* selector for reading LDT table */
-#endif
-
-#if TARGET_MSDOS == 32 && defined(TARGET_WINDOWS)
-uint32_t cpu_gdtlib_lin_bias = 0UL;
-#endif
-
-unsigned int cpu_gdtlib_gdt_entries(struct x86_gdtr *r) {
- if (r->limit == 0xFFFFU) return 0x2000;
- return ((unsigned int)r->limit + 1U) >> 3;
-}
-
-unsigned int cpu_gdtlib_ldt_entries(struct cpu_gdtlib_entry *r) {
- return ((unsigned int)(r->limit + 1UL)) >> 3UL;
-}
-
-int cpu_gdtlib_read_ldtr(uint16_t *sel) {
- if (!cpu_gdtlib_can_read)
- return 0;
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
- /* in what is likely a strange inversion of priorities, the Win 9x kernel allows
- * DOS programs like us to read the GDTR register. But... attempts to read the LDTR
- * are not permitted. */
- if (windows_mode == WINDOWS_ENHANCED)
- return 0;
-#endif
-
-#if TARGET_MSDOS == 16
-# if defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .286p
- push ds
- push si
- lds si,sel
- sldt [si]
- pop si
- pop ds
- }
-# else
- __asm {
- .286p
- push si
- mov si,sel
- sldt [si]
- pop si
- }
-# endif
-#else
- __asm {
- push eax
- mov eax,sel
- sldt [eax]
- pop eax
- }
-#endif
- return 1;
-}
-
-int cpu_gdtlib_read_gdtr(struct x86_gdtr *raw) {
- if (!cpu_gdtlib_can_read)
- return 0;
-
-#if TARGET_MSDOS == 16
-# if defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .286p
- push ds
- push si
- lds si,raw
- sgdt [si]
- pop si
- pop ds
- }
-# else
- __asm {
- .286p
- push si
- mov si,raw
- sgdt [si]
- pop si
- }
-# endif
-#else
- __asm {
- push eax
- mov eax,raw
- sgdt [eax]
- pop eax
- }
-#endif
- return 1;
-}
-
-int cpu_gdtlib_init() {
- if (cpu_gdtlib_result == 0xFF) {
- cpu_gdtlib_ldtr = 0;
- cpu_gdtlib_can_read = cpu_gdtlib_can_write = 0;
- if (cpu_basic_level < 0) cpu_probe();
- if (cpu_basic_level < 3) return (cpu_gdtlib_result=0);
- probe_dos();
- detect_windows();
-
-#if defined(TARGET_OS2)
- /* OS/2 16-bit or 32-bit: Not gonna happen */
- return (cpu_gdtlib_result=0);
-#elif TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS)
- /* 16-bit MS-DOS:
- * Either:
- * - We're in real mode, and there is no such GDT installed
- * - We're in v86 mode, we might be able to locate the GDT and read it
- * - We're in v86 mode and VCPI is present: uhhhmmmm.... we'll we could enter via VCPI but that only installs our OWN GDT tables, so...
- * - We're in v86 mode under Windows 3.x/9x/ME: DPMI is likely available, we could take advantage of the 9x kernel's permissiveness to read the GDT
- * - We're in v86 mode under Windows NT/2000/XP: don't try, not gonna happen. */
- if (windows_mode == WINDOWS_NT)
- return (cpu_gdtlib_result=0);
- if (windows_mode == WINDOWS_REAL)
- return (cpu_gdtlib_result=0);
- if (!cpu_v86_active) /* if there's no v86 mode, then there's no protected mode GDT table */
- return (cpu_gdtlib_result=0);
- if (!dpmi_lin2fmemcpy_init())
- return (cpu_gdtlib_result=0);
-
- /* FIXME: Windows 3.0: This code hangs */
- if (windows_mode == WINDOWS_ENHANCED && windows_version < 0x30A) /* Anything less than Windows 3.1 */
- return (cpu_gdtlib_result=0);
-
- cpu_gdtlib_can_read = 1;
- return (cpu_gdtlib_result=1);
-#elif TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS)
- /* 32-bit MS-DOS:
- * Either:
- * - Pure DOS mode is active, the DOS extender did not enable paging, and we're ring 0. we can just read the GDT directly. No problem.
- * - Pure DOS mode with EMM386.EXE. The DOS extender used VCPI to enter protected mode, we just have to locate the GDT somehow.
- * Usually it ends up in the first 1MB (DOS area) where 1:1 mapping is still retained. We can read it
- * - Windows 3.x/9x/ME DOS Box: We're running at ring 3, but we can take advantage of the 9x kernel's apparent permissiveness to
- * locate the GDT and read it.
- * - Windows NT/2000/XP: Not gonna happen. Even reading the control register will fault our application. */
- if (windows_mode == WINDOWS_NT)
- return (cpu_gdtlib_result=0);
-
- cpu_gdtlib_can_read = 1;
- return (cpu_gdtlib_result=1);
-#elif TARGET_MSDOS == 16 && defined(TARGET_WINDOWS)
- /* 16-bit Win16 application:
- * Either:
- * - Windows 3.x/9x/ME: As a Win16 app we can use Win16 functions like AllocateSelector(), etc. to give ourself access to the GDT.
- * - Windows NT/2000/XP: We might be able to use AllocateSelector(), etc. NTVDM.EXE allows "SGDT" but result seems to point to garbage
- *
- * For obvious reasons, we do not attempt to read the GDT in real-mode Windows 3.0 because there is no GDT */
- if (windows_mode == WINDOWS_NT)
- return (cpu_gdtlib_result=0);
- if (windows_mode == WINDOWS_REAL)
- return (cpu_gdtlib_result=0);
-
- cpu_gdtlib_can_read = 1;
- return (cpu_gdtlib_result=1);
-#elif TARGET_MSDOS == 32 && defined(TARGET_WINDOWS)
- /* 32-bit Windows application:
- * Either:
- * - Windows 3.1/9x/ME: We can use "sgdt" to read the GDTR, and then just refer to that location in memory.
- * - Windows NT/2000/XP: Not gonna happen */
- if (windows_mode == WINDOWS_NT)
- return (cpu_gdtlib_result=0);
-
-# ifdef WIN386
- {
- unsigned short s=0;
-
- __asm {
- mov ax,ds
- mov s,ax
- }
-
- /* #1: We need to know what Watcom Win386's data selector bias is */
- cpu_gdtlib_lin_bias = GetSelectorBase(s);
-
- /* #2: Whatever the base is, Win386 usually sets the limit to 0xFFFFFFFF.
- * The base is usually something like 0x80302330, and the GDT is usually
- * something like 0x80112000, so if we have to rollover BACKWARDS we
- * want to make sure the limit is 0xFFFFFFFF */
- if (GetSelectorLimit(s) != 0xFFFFFFFFUL)
- return (cpu_gdtlib_result=0);
- }
-# else
- /* Windows 3.1 with Win32s sets the flat selectors to base = 0xFFFF0000 for whatever reason.
- * So to properly read the GDT we have to compensate for that */
- if (windows_mode == WINDOWS_ENHANCED && windows_version < 0x35F)
- cpu_gdtlib_lin_bias = 0xFFFF0000UL;
-# endif
-
- cpu_gdtlib_can_read = 1;
- return (cpu_gdtlib_result=1);
-#endif
- }
-
- return cpu_gdtlib_result;
-}
-
-void cpu_gdtlib_free() {
-#if TARGET_MSDOS == 16 && defined(TARGET_WINDOWS)
- if (cpu_gdtlib_gdt_sel != 0) {
- FreeSelector(cpu_gdtlib_gdt_sel);
- cpu_gdtlib_gdt_sel=0;
- }
- if (cpu_gdtlib_ldt_sel != 0) {
- FreeSelector(cpu_gdtlib_ldt_sel);
- cpu_gdtlib_ldt_sel=0;
- }
-#endif
-}
-
-int cpu_gdtlib_ldt_read_entry(struct cpu_gdtlib_entry *e,unsigned int i) {
- if (i >= cpu_gdtlib_ldt_entries(&cpu_gdtlib_ldt_ent))
- return 0;
- if (!cpu_gdtlib_can_read)
- return 0;
-
-#if defined(TARGET_OS2)
- return 0; /* NOPE */
-#elif TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS)
- { /* 16-bit real mode DOS */
- unsigned char tmp[8];
-
- if (dpmi_lin2fmemcpy(tmp,cpu_gdtlib_ldt_ent.base + (i << 3),8) == 0)
- return 0;
-
- e->limit = (uint32_t)( *((uint16_t*)(tmp+0)) );
- e->base = (uint32_t)( *((uint32_t*)(tmp+2)) & 0xFFFFFFUL );
- e->access = tmp[5];
- e->granularity = tmp[6];
- e->base |= ((uint32_t)tmp[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
- }
-#elif TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS)
- { /* 32-bit protected mode DOS */
- unsigned char *p = (unsigned char*)cpu_gdtlib_ldt_ent.base + (i << 3);
- e->limit = (uint32_t)( *((uint16_t*)(p+0)) );
- e->base = (uint32_t)( *((uint32_t*)(p+2)) & 0xFFFFFFUL );
- e->access = p[5];
- e->granularity = p[6];
- e->base |= ((uint32_t)p[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
- }
-#elif TARGET_MSDOS == 16 && defined(TARGET_WINDOWS)
- { /* 16-bit Win16 app */
- unsigned char far *p;
-
- if (cpu_gdtlib_ldt_sel == 0) {
- uint16_t myds=0;
- __asm mov myds,ds
- cpu_gdtlib_ldt_sel = AllocSelector(myds);
- if (cpu_gdtlib_ldt_sel == 0) return 0;
- SetSelectorLimit(cpu_gdtlib_ldt_sel,(DWORD)cpu_gdtlib_ldt_ent.limit);
- SetSelectorBase(cpu_gdtlib_ldt_sel,(DWORD)cpu_gdtlib_ldt_ent.base);
- }
-
- if (cpu_gdtlib_ldt_sel != 0) {
- p = MK_FP(cpu_gdtlib_ldt_sel,i << 3);
- e->limit = (uint32_t)( *((uint16_t far*)(p+0)) );
- e->base = (uint32_t)( *((uint32_t far*)(p+2)) & 0xFFFFFFUL );
- e->access = p[5];
- e->granularity = p[6];
- e->base |= ((uint32_t)p[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
- }
- }
-#elif TARGET_MSDOS == 32 && defined(TARGET_WINDOWS)
- { /* 32-bit Windows app */
- unsigned char *p = (unsigned char*)cpu_gdtlib_ldt_ent.base + (i << 3) - cpu_gdtlib_lin_bias;
- e->limit = (uint32_t)( *((uint16_t*)(p+0)) );
- e->base = (uint32_t)( *((uint32_t*)(p+2)) & 0xFFFFFFUL );
- e->access = p[5];
- e->granularity = p[6];
- e->base |= ((uint32_t)p[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
-
- }
-#endif
-
-#if !defined(TARGET_OS2)
- if (e->granularity & 0x80)
- e->limit = (e->limit << 12UL) | 0xFFFUL;
-
- return 1;
-#endif
-}
-
-int cpu_gdtlib_gdt_read_entry(struct cpu_gdtlib_entry *e,unsigned int i) {
- if (i >= cpu_gdtlib_gdt_entries(&cpu_gdtlib_gdtr))
- return 0;
- if (!cpu_gdtlib_can_read)
- return 0;
-
-#if defined(TARGET_OS2)
- return 0; /* NOPE */
-#elif TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS)
- { /* 16-bit real mode DOS */
- unsigned char tmp[8];
-
- if (dpmi_lin2fmemcpy(tmp,cpu_gdtlib_gdtr.base + (i << 3),8) == 0)
- return 0;
-
- e->limit = (uint32_t)( *((uint16_t*)(tmp+0)) );
- e->base = (uint32_t)( *((uint32_t*)(tmp+2)) & 0xFFFFFFUL );
- e->access = tmp[5];
- e->granularity = tmp[6];
- e->base |= ((uint32_t)tmp[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
- }
-#elif TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS)
- { /* 32-bit protected mode DOS */
- unsigned char *p = (unsigned char*)cpu_gdtlib_gdtr.base + (i << 3);
- e->limit = (uint32_t)( *((uint16_t*)(p+0)) );
- e->base = (uint32_t)( *((uint32_t*)(p+2)) & 0xFFFFFFUL );
- e->access = p[5];
- e->granularity = p[6];
- e->base |= ((uint32_t)p[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
- }
-#elif TARGET_MSDOS == 16 && defined(TARGET_WINDOWS)
- { /* 16-bit Win16 app */
- unsigned char far *p;
-
- if (cpu_gdtlib_gdt_sel == 0) {
- uint16_t myds=0;
- __asm mov myds,ds
- cpu_gdtlib_gdt_sel = AllocSelector(myds);
- if (cpu_gdtlib_gdt_sel == 0) return 0;
- SetSelectorLimit(cpu_gdtlib_gdt_sel,(DWORD)cpu_gdtlib_gdtr.limit);
- SetSelectorBase(cpu_gdtlib_gdt_sel,(DWORD)cpu_gdtlib_gdtr.base);
- }
-
- if (cpu_gdtlib_gdt_sel != 0) {
- p = MK_FP(cpu_gdtlib_gdt_sel,i << 3);
- e->limit = (uint32_t)( *((uint16_t far*)(p+0)) );
- e->base = (uint32_t)( *((uint32_t far*)(p+2)) & 0xFFFFFFUL );
- e->access = p[5];
- e->granularity = p[6];
- e->base |= ((uint32_t)p[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
- }
- }
-#elif TARGET_MSDOS == 32 && defined(TARGET_WINDOWS)
- { /* 32-bit Windows app */
- unsigned char *p = (unsigned char*)cpu_gdtlib_gdtr.base + (i << 3) - cpu_gdtlib_lin_bias;
- e->limit = (uint32_t)( *((uint16_t*)(p+0)) );
- e->base = (uint32_t)( *((uint32_t*)(p+2)) & 0xFFFFFFUL );
- e->access = p[5];
- e->granularity = p[6];
- e->base |= ((uint32_t)p[7]) << 24UL;
- e->limit |= ((uint32_t)e->granularity & 0xFUL) << 16UL;
-
- }
-#endif
-
-#if !defined(TARGET_OS2)
- if (e->granularity & 0x80)
- e->limit = (e->limit << 12UL) | 0xFFFUL;
-
- return 1;
-#endif
-}
-
-int cpu_gdtlib_empty_gdt_entry(struct cpu_gdtlib_entry *e) {
- if (e->limit == 0 && e->base == 0 && e->access == 0 && e->granularity == 0)
- return 1;
-
- return 0;
-}
-
-#define cpu_gdtlib_empty_ldt_entry cpu_gdtlib_empty_gdt_entry
-
-int cpu_gdtlib_entry_is_special(struct cpu_gdtlib_entry *e) {
- return !(e->access & 0x10);
-}
-
-int cpu_gdtlib_entry_is_executable(struct cpu_gdtlib_entry *e) {
- return (e->access & 0x08);
-}
-
-int cpu_gdtlib_read_current_regs() {
-#if TARGET_MSDOS == 16 && defined(TARGET_WINDOWS)
- if (cpu_gdtlib_ldt_sel != 0) {
- FreeSelector(cpu_gdtlib_ldt_sel);
- cpu_gdtlib_ldt_sel=0;
- }
-#endif
-
- /* it matters if we can't read the GDTR */
- if (!cpu_gdtlib_read_gdtr(&cpu_gdtlib_gdtr))
- return 0;
-
- /* but if we can't read the LDTR, we don't care */
- memset(&cpu_gdtlib_ldt_ent,0,sizeof(cpu_gdtlib_ldt_ent));
- cpu_gdtlib_ldtr = 0;
- cpu_gdtlib_read_ldtr(&cpu_gdtlib_ldtr);
-
- return 1;
-}
-
-int cpu_gdtlib_prepare_to_read_ldt() {
- if (cpu_gdtlib_ldtr == 0) return 0;
- if (cpu_gdtlib_ldt_ent.limit == 0 && cpu_gdtlib_ldt_ent.access == 0) {
- if (cpu_gdtlib_gdt_read_entry(&cpu_gdtlib_ldt_ent,cpu_gdtlib_ldtr>>3) == 0)
- return 0;
- if (cpu_gdtlib_empty_gdt_entry(&cpu_gdtlib_ldt_ent))
- return 0;
- }
-
- return 1;
-}
-
+++ /dev/null
-/* gdt_enum.h
- *
- * Library for reading the Global Descriptor Table if possible.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS
- * - Windows 3.0/3.1/95/98/ME
- * - Windows NT 3.1/3.51/4.0/2000/XP/Vista/7
- * - OS/2 16-bit
- * - OS/2 32-bit
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-
-#pragma pack(push,1)
-struct x86_gdtr {
- uint16_t limit;
- uint32_t base;
- uint16_t pad;
-};
-#pragma pack(pop)
-
-#pragma pack(push,1)
-struct cpu_gdtlib_entry {
- uint32_t limit;
- uint32_t base;
- uint8_t access,granularity;
-};
-#pragma pack(pop)
-
-extern unsigned char cpu_gdtlib_can_read,cpu_gdtlib_can_write,cpu_gdtlib_result;
-extern uint16_t cpu_gdtlib_ldtr;
-extern struct x86_gdtr cpu_gdtlib_gdtr;
-extern struct cpu_gdtlib_entry cpu_gdtlib_ldt_ent;
-#if TARGET_MSDOS == 16 && defined(TARGET_WINDOWS)
-extern uint16_t cpu_gdtlib_gdt_sel; /* selector for reading GDT table */
-extern uint16_t cpu_gdtlib_ldt_sel; /* selector for reading LDT table */
-#endif
-
-/* HACK: Win32 builds must be careful. Windows 9x/ME sets the flat selector as base == 0 limit = 0xFFFFFFFF while
- * Windows 3.1 Win32s sets base = 0xFFFF0000 limit = 0xFFFFFFFF for whatever weird reason. */
-#if TARGET_MSDOS == 32 && defined(TARGET_WINDOWS)
-extern uint32_t cpu_gdtlib_lin_bias;
-#else
-# define cpu_gdtlib_lin_bias (0UL)
-#endif
-
-#define cpu_gdtlib_empty_ldt_entry cpu_gdtlib_empty_gdt_entry
-
-unsigned int cpu_gdtlib_gdt_entries(struct x86_gdtr *r);
-unsigned int cpu_gdtlib_ldt_entries(struct cpu_gdtlib_entry *r);
-int cpu_gdtlib_read_ldtr(uint16_t *sel);
-int cpu_gdtlib_read_gdtr(struct x86_gdtr *raw);
-int cpu_gdtlib_init();
-void cpu_gdtlib_free();
-int cpu_gdtlib_ldt_read_entry(struct cpu_gdtlib_entry *e,unsigned int i);
-int cpu_gdtlib_gdt_read_entry(struct cpu_gdtlib_entry *e,unsigned int i);
-int cpu_gdtlib_empty_gdt_entry(struct cpu_gdtlib_entry *e);
-int cpu_gdtlib_entry_is_special(struct cpu_gdtlib_entry *e);
-int cpu_gdtlib_entry_is_executable(struct cpu_gdtlib_entry *e);
-int cpu_gdtlib_read_current_regs();
-int cpu_gdtlib_prepare_to_read_ldt();
-
+++ /dev/null
-/* gdt_list.c
- *
- * Test program for gdt_enum.c library.
- * Dumps the contents of the GDT onto the screen, if possible.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * Compiles for intended target environments:
- * - MS-DOS
- * - Windows 3.0/3.1/95/98/ME
- * - Windows NT 3.1/3.51/4.0/2000/XP/Vista/7
- * - OS/2 16-bit
- * - OS/2 32-bit
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/cpu/gdt_enum.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- struct cpu_gdtlib_entry ent;
- unsigned int i,prn=0;
- int c;
-
- if (!cpu_gdtlib_init()) {
- printf("Unable to init CPU GDT library\n");
- return 1;
- }
- if (!cpu_gdtlib_read_current_regs()) {
- printf("Cannot read current regs in any meaningful way\n");
- return 1;
- }
-
- printf("GDTR: Limit=0x%04x Base=0x%08lX LDTR: 0x%04x ",
- (unsigned int)cpu_gdtlib_gdtr.limit,
- (unsigned long)cpu_gdtlib_gdtr.base,
- (unsigned int)cpu_gdtlib_ldtr);
-
- /* for reference: print my code and data segment/selector values */
- {
- uint16_t v_cs=0,v_ds=0;
-
- __asm {
- mov ax,cs
- mov v_cs,ax
-
- mov ax,ds
- mov v_ds,ax
- }
-
- printf("CS=%04X DS=%04X\n",v_cs,v_ds);
- }
-
- prn = 2;
- for (i=0;i < cpu_gdtlib_gdt_entries(&cpu_gdtlib_gdtr);i++) {
- if (cpu_gdtlib_gdt_read_entry(&ent,i)) {
- if (!cpu_gdtlib_empty_gdt_entry(&ent)) {
- printf("%04X: Lim=%08lX Base=%08lX Acc=%02X G=%02X ",
- (unsigned int)i << 3,
- (unsigned long)ent.limit,
- (unsigned long)ent.base,
- ent.access,
- ent.granularity);
- if (cpu_gdtlib_entry_is_special(&ent)) {
- printf("P=%u Other-%u Type=%u PL=%u",
- (ent.access>>7)&1,
- (ent.granularity&0x40) ? 32 : 16,
- (ent.access&0xF),
- (ent.access>>5)&3);
- }
- else if (cpu_gdtlib_entry_is_executable(&ent)) {
- printf("P=%u CODE-%u C=%u Read=%u PL=%u",
- (ent.access>>7)&1,
- (ent.granularity&0x40) ? 32 : 16,
- ent.access&1,
- (ent.access>>1)&1,
- (ent.access>>5)&3);
- }
- else {
- printf("P=%u DATA-%u D=%u RW=%u PL=%u",
- (ent.access>>7)&1,
- (ent.granularity&0x40) ? 32 : 16,
- ent.access&1,
- (ent.access>>1)&1,
- (ent.access>>5)&3);
- }
- printf("\n");
-
- if (++prn >= 23) {
- prn = 0;
- do {
- c = getch();
- if (c == 27) return 1;
- } while (c != 13);
- }
- }
- }
- }
-
- if (cpu_gdtlib_prepare_to_read_ldt()) {
- printf("LDT: Base=%08lX Limit=%08lX\n",
- (unsigned long)cpu_gdtlib_ldt_ent.base,
- (unsigned long)cpu_gdtlib_ldt_ent.limit);
-
- for (i=0;i < cpu_gdtlib_ldt_entries(&cpu_gdtlib_ldt_ent);i++) {
- if (cpu_gdtlib_ldt_read_entry(&ent,i)) {
- if (!cpu_gdtlib_empty_ldt_entry(&ent)) {
- printf("%04X: Lim=%08lX Base=%08lX Acc=%02X G=%02X ",
- (unsigned int)(i << 3)+4,
- (unsigned long)ent.limit,
- (unsigned long)ent.base,
- ent.access,
- ent.granularity);
- if (cpu_gdtlib_entry_is_special(&ent)) {
- printf("P=%u Other-%u Type=%u PL=%u",
- (ent.access>>7)&1,
- (ent.granularity&0x40) ? 32 : 16,
- (ent.access&0xF),
- (ent.access>>5)&3);
- }
- else if (cpu_gdtlib_entry_is_executable(&ent)) {
- printf("P=%u CODE-%u C=%u Read=%u PL=%u",
- (ent.access>>7)&1,
- (ent.granularity&0x40) ? 32 : 16,
- ent.access&1,
- (ent.access>>1)&1,
- (ent.access>>5)&3);
- }
- else {
- printf("P=%u DATA-%u D=%u RW=%u PL=%u",
- (ent.access>>7)&1,
- (ent.granularity&0x40) ? 32 : 16,
- ent.access&1,
- (ent.access>>1)&1,
- (ent.access>>5)&3);
- }
- printf("\n");
-
- if (++prn >= 23) {
- prn = 0;
- do {
- c = getch();
- if (c == 27) return 1;
- } while (c != 13);
- }
- }
- }
- }
- }
-
- cpu_gdtlib_free();
- return 0;
-}
-
+++ /dev/null
-/* gdt_tae.c
- *
- * Dumps the contents of the GDT onto the screen using "trial and error",
- * meaning that it loads each segment and attempts to read from it. It uses
- * exception handling to safely recover.
- *
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/cpuidext.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-unsigned char tmp[16]; /* <- Watcom C you fucking pussy */
-int lines=0;
-
-#if TARGET_MSDOS == 32 && defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-int TestSegmentWin32(unsigned int segm,unsigned char *ptrv,unsigned int cntv) {
- int worked = -1;
-
- __try {
- __asm {
- mov eax,segm
- mov es,ax ; <- might fault here
- ; OK try to read
- ; Be *CAREFUL*, it might be a 16-bit data segment which depending on
- ; i386 intricate details and CPU might make this code act wonky.
- ; more specifically, it might affect how the cpu decodes 16-bit vs 32-bit instructions with data.
- ; so we want to access only in a way the CPU will basically do the same thing either way.
- mov worked,0
-
- ; if decoded as 16-bit: becomes MOV AL,[BX]
- ; if decoded as 32-bit: becomes MOV AL,[EDI]
- xor ebx,ebx
- mov edi,ebx
- mov esi,ptrv
- mov ecx,cntv ; <- copy 32 bytes
-
- ; read data
-lev1: mov al,BYTE PTR [es:edi]
- mov BYTE PTR [esi],al
- inc edi
- inc esi
- mov ebx,edi
- mov worked,edi
- loop lev1
- }
- }
- __except(1) {
- }
-
- __asm {
- push ds
- pop es
- }
-
- return worked;
-}
-#endif
-
-#if TARGET_MSDOS == 32 && defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-static void pause_if_tty() {
- unsigned char c;
- if (isatty(1)) { do { read(0,&c,1); } while (c != 13); }
-}
-#endif
-
-int main() {
- cpu_probe();
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
-
- if (cpu_v86_active)
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
- if (cpu_flags & CPU_FLAG_PROTECTED_MODE)
- printf(" - Your CPU is currently running in protected mode\n");
- if (cpu_flags & CPU_FLAG_PROTECTED_MODE_32)
- printf(" - Your CPU is currently running in 32-bit protected mode\n");
-
-#if TARGET_MSDOS == 32 && defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
- {
- unsigned int selv=0,i;
- int worked;
-
- __asm {
- xor eax,eax
- mov ax,cs
- mov selv,eax
- }
- printf("CS=%04x\n",selv);
-
- __asm {
- xor eax,eax
- mov ax,ds
- mov selv,eax
- }
- printf("DS=%04x\n",selv);
-
- /* start from segment 0x08 and move on from there, alternating LDT and GDT, always assuming DPL=3 */
- for (selv=8|3;selv <= 0xFFFF;selv += 4) {
- worked = TestSegmentWin32(selv,tmp,sizeof(tmp));
- if (worked >= 0) {
- printf("Found segment %04x (%u bytes)\n",selv,worked);
- fflush(stdout);
- lines++;
-
- if (worked != 0) {
- for (i=0;i < worked;i++) printf("%02x ",tmp[i]);
- printf("\n");
- lines++;
- }
-
- if (lines >= 20) {
- pause_if_tty();
- lines -= 20;
- }
- }
- }
- }
-#else
- printf("Target environment is not applicable\n");
-#endif
-
- cpu_extended_cpuid_info_free();
- return 0;
-}
-
+++ /dev/null
-/* grind.c
- *
- * Run instruction encodings through combinations and record changes to registers and flags.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <malloc.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/libgrind.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-static unsigned int min_i=0,max_i=511;
-static unsigned int min_j=0,max_j=511;
-
-static unsigned char asm_buf[64];
-
-static char *log_filename = NULL;
-
-#if TARGET_MSDOS == 32
-static unsigned char log_buf[63*1024]; // 63KB
-#else
-static unsigned char log_buf[30*1024]; // 30KB
-#endif
-
-static int log_reopen_counter=0;
-static unsigned int log_bufi=0;
-static int log_fd = -1;
-
-static void do_pause() {
- unsigned char c;
- if (isatty(1)) { do { read(0,&c,1); } while (c != 13); }
-}
-
-static void log_close();
-static int log_reopen();
-static int log_open(const char *path);
-
-static void log_incname() {
- unsigned int num;
- char *n;
-
- if (log_filename == NULL)
- return;
-
- n = log_filename;
- while (*n && n[1] != 0) n++; // scan until n = last char
- if (*n == 0) return;
-
- num = ++log_reopen_counter;
-
- do {
- *n = ((char)(num % 10U)) + '0';
- num /= 10U;
- n--;
- if (n < log_filename) break;
- if (*n == '.') break;
- } while (num != 0U);
-}
-
-static void log_flush() {
- if (log_fd >= 0 && log_bufi != 0) {
- unsigned int wd,wr,wo=0;
-
- do {
- assert(wo < log_bufi);
- wr = log_bufi - wo;
- wd = write(log_fd,log_buf+wo,wr);
- if (/*another way to check for wd == -1*/wd > sizeof(log_buf)) wd = 0;
-
- // note what we could write
- if (wd > 0) wo += wd;
-
- if (wd < wr) {
- // make sure DOS flushes to disk
- if (log_fd >= 0) {
- close(log_fd);
- log_fd = -1;
- }
-
- // strange behavior in MS-DOS 5.0: if there is not enough disk space for X bytes, then it will
- // write 0 bytes and return to us that it wrote 0 bytes. not what I expected, coming from the
- // Linux world that would write as much as it can before giving up. --J.C.
- if (errno == ENOSPC) {
- printf("\nWrite: out of space (%u / %u written)\n",wd,wr);
- printf("Unable to write full log. Swap floppies and hit ENTER or CTRL+C to quit.\n");
- printf("You will have to assemble the full file from fragments when this is done.\n");
- do_pause();
-
- log_incname();
- if (!log_reopen()) {
- printf("Unable to reopen log.\n");
- exit(1);
- }
- }
- else {
- printf("\nError writing log: %s.\n",strerror(errno));
- exit(1);
- }
- }
- else {
- break;
- }
- } while (wo < log_bufi);
- }
-
- log_bufi = 0;
-}
-
-static void log_lazy_flush(size_t extra) {
- if (log_fd >= 0 && (extra >= sizeof(log_buf) || log_bufi >= (sizeof(log_buf)-extra)))
- log_flush();
-}
-
-static void log_close() {
- log_flush();
- if (log_fd >= 0) {
- close(log_fd);
- log_fd = -1;
- }
-}
-
-static int log_reopen() {
- if (log_fd >= 0) return 1;
- if (log_filename == NULL) return 0;
-
- log_fd = open(log_filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644);
- if (log_fd < 0) return 0;
-
- return 1;
-}
-
-static int log_open(const char *path) {
- log_close();
-
- if (log_filename) {
- free(log_filename);
- log_filename = NULL;
- }
-
- log_reopen_counter = 0;
-
- log_fd = open(path,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644);
- if (log_fd < 0) return 0;
-
- log_filename = strdup(path);
- return 1;
-}
-
-static inline grind_ADDw() {
- const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
- unsigned int i,j;
-
- if (!grind_init()) {
- grind_free();
- return 1;
- }
- if (!grind_alloc_buf()) {
- grind_free();
- return 1;
- }
- if (!grind_lock_buf()) {
- grind_free();
- return 1;
- }
-
- log_open("gr_add.bin");
- // header
- *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
- log_bufi += 4;
- *((uint32_t*)(log_buf+log_bufi)) = 0x77444441; // 'ADDw'
- log_bufi += 4;
- *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
- log_bufi += 1;
- *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
- log_bufi += 1;
- *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
- log_bufi += sizeof(unsigned int);
-
- log_lazy_flush(32);
-
- i = min_i;
- do {
- printf("i=%u j=%u..%u",i,min_j,max_j);
- fflush(stdout);
-
- j = min_j;
- do {
- grind_buf_ptr_t w = grind_buf;
-
- *((grind_imm_t*)(asm_buf+0)) = 0; // ADD result
- *((grind_imm_t*)(asm_buf+4)) = 0; // ADD result (2)
- *((grind_imm_t*)(asm_buf+8)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+12)) = 0; // FLAGS after
- *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
-
-// *w++ = GRIND_INT3_INS; // INT3
-
- // save DS, EAX, FLAGS
- w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
-
- // DS = segment of asm_buf
- w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
- w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+8
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+0
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Add_const(w,GRIND_REG_AX,j); // ADD (E)AX,const
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, in asm_buf+12
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+16
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+4
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Add_const(w,GRIND_REG_AX,j); // ADD (E)AX,const
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, store result in asm_buf+20
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // restore FLAGS, EAX, DS, exit subroutine
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
- *w++ = GRIND_RET_INS; // RET
-
- // SANITY CHECK
- if (w > (grind_buf + grind_buf_size)) {
- printf("<--BUFFER OVERRUN\n");
- grind_free();
- return 1;
- }
-
- // EXECUTE IT
- if (!grind_execute_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- // sanity check
- if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+4))) {
- printf("WARNING: Two ADD passes with different sums 0x%x != 0x%x\n",
- *((grind_imm_t*)(asm_buf+0)),
- *((grind_imm_t*)(asm_buf+4)));
- }
-
- // log results
- log_lazy_flush(64);
- *((unsigned int*)(log_buf+log_bufi)) = i; // I
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = j; // J
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I+J
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+8)); // FLAGS before init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+12)); // FLAGS after init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #2
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #2
- log_bufi += sizeof(unsigned int);
- // log entry finish
- log_lazy_flush(16);
- } while ((j++) != max_j);
-
- printf("\x0D");
- fflush(stdout);
- } while ((i++) != max_i);
-
- grind_unlock_buf();
- grind_free_buf();
- grind_free();
- log_flush();
- return 0;
-}
-
-static inline grind_SUBw() {
- const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
- unsigned int i,j;
-
- if (!grind_init()) {
- grind_free();
- return 1;
- }
- if (!grind_alloc_buf()) {
- grind_free();
- return 1;
- }
- if (!grind_lock_buf()) {
- grind_free();
- return 1;
- }
-
- log_open("gr_sub.bin");
- // header
- *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
- log_bufi += 4;
- *((uint32_t*)(log_buf+log_bufi)) = 0x77425553; // 'SUBw'
- log_bufi += 4;
- *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
- log_bufi += 1;
- *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
- log_bufi += 1;
- *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
- log_bufi += sizeof(unsigned int);
-
- log_lazy_flush(32);
-
- i = min_i;
- do {
- printf("i=%u j=%u..%u",i,min_j,max_j);
- fflush(stdout);
-
- j = min_j;
- do {
- grind_buf_ptr_t w = grind_buf;
-
- *((grind_imm_t*)(asm_buf+0)) = 0; // ADD result
- *((grind_imm_t*)(asm_buf+4)) = 0; // ADD result (2)
- *((grind_imm_t*)(asm_buf+8)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+12)) = 0; // FLAGS after
- *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
-
-// *w++ = GRIND_INT3_INS; // INT3
-
- // save DS, EAX, FLAGS
- w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
-
- // DS = segment of asm_buf
- w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
- w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+8
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+0
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Sub_const(w,GRIND_REG_AX,j); // SUB (E)AX,const
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, in asm_buf+12
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+16
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+4
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Sub_const(w,GRIND_REG_AX,j); // SUB (E)AX,const
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, store result in asm_buf+20
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // restore FLAGS, EAX, DS, exit subroutine
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
- *w++ = GRIND_RET_INS; // RET
-
- // SANITY CHECK
- if (w > (grind_buf + grind_buf_size)) {
- printf("<--BUFFER OVERRUN\n");
- grind_free();
- return 1;
- }
-
- // EXECUTE IT
- if (!grind_execute_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- // sanity check
- if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+4))) {
- printf("WARNING: Two SUB passes with different results 0x%x != 0x%x\n",
- *((grind_imm_t*)(asm_buf+0)),
- *((grind_imm_t*)(asm_buf+4)));
- }
-
- // log results
- log_lazy_flush(64);
- *((unsigned int*)(log_buf+log_bufi)) = i; // I
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = j; // J
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I-J
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+8)); // FLAGS before init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+12)); // FLAGS after init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #2
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #2
- log_bufi += sizeof(unsigned int);
- // log entry finish
- log_lazy_flush(16);
- } while ((j++) != max_j);
-
- printf("\x0D");
- fflush(stdout);
- } while ((i++) != max_i);
-
- grind_unlock_buf();
- grind_free_buf();
- grind_free();
- log_flush();
- return 0;
-}
-
-static inline grind_MULw() {
- const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
- unsigned int i,j;
-
- if (!grind_init()) {
- grind_free();
- return 1;
- }
- if (!grind_alloc_buf()) {
- grind_free();
- return 1;
- }
- if (!grind_lock_buf()) {
- grind_free();
- return 1;
- }
-
- log_open("gr_mul.bin");
- // header
- *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
- log_bufi += 4;
- *((uint32_t*)(log_buf+log_bufi)) = 0x774C554D; // 'MULw'
- log_bufi += 4;
- *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
- log_bufi += 1;
- *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
- log_bufi += 1;
- *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
- log_bufi += sizeof(unsigned int);
-
- log_lazy_flush(32);
-
- i = min_i;
- do {
- printf("i=%u j=%u..%u",i,min_j,max_j);
- fflush(stdout);
-
- j = min_j;
- do {
- grind_buf_ptr_t w = grind_buf;
-
- *((grind_imm_t*)(asm_buf+0)) = 0; // MUL result (AX)
- *((grind_imm_t*)(asm_buf+4)) = 0; // MUL result (DX)
- *((grind_imm_t*)(asm_buf+8)) = 0; // MUL result 2 (AX)
- *((grind_imm_t*)(asm_buf+12)) = 0; // MUL result 2 (DX)
- *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
- *((grind_imm_t*)(asm_buf+24)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+28)) = 0; // FLAGS after
-
-// *w++ = GRIND_INT3_INS; // INT3
-
- // save DS, EAX, FLAGS
- w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__push_Reg(w,GRIND_REG_BX); // PUSH (E)BX
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
-
- // DS = segment of asm_buf
- w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
- w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+16
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+0
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
- w=grind_buf_w__mul_Reg(w,GRIND_REG_BX); // MUL (E)BX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_DX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, in asm_buf+20
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+24
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+24,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+4
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
- w=grind_buf_w__mul_Reg(w,GRIND_REG_BX); // MUL (E)BX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_DX); // MOV [offset],(E)DX
-
- // store state of EFLAGS now, store result in asm_buf+28
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+28,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // restore FLAGS, EAX, DS, exit subroutine
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_BX); // POP (E)BX
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
- *w++ = GRIND_RET_INS; // RET
-
- // SANITY CHECK
- if (w > (grind_buf + grind_buf_size)) {
- printf("<--BUFFER OVERRUN\n");
- grind_free();
- return 1;
- }
-
- // EXECUTE IT
- if (!grind_execute_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- // sanity check
- if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+8)) ||
- *((grind_imm_t*)(asm_buf+4)) != *((grind_imm_t*)(asm_buf+12))) {
- printf("WARNING: Two MUL passes with different products %x:%x != %x:%x\n",
- *((grind_imm_t*)(asm_buf+4)), *((grind_imm_t*)(asm_buf+0)),
- *((grind_imm_t*)(asm_buf+12)), *((grind_imm_t*)(asm_buf+8)));
- }
-
- // log results
- log_lazy_flush(64);
- *((unsigned int*)(log_buf+log_bufi)) = i; // I
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = j; // J
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I*J (low word)
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+4)); // I*J (high word)
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+24)); // FLAGS before init #2
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+28)); // FLAGS after init #2
- log_bufi += sizeof(unsigned int);
- // log entry finish
- log_lazy_flush(16);
- } while ((j++) != max_j);
-
- printf("\x0D");
- fflush(stdout);
- } while ((i++) != max_i);
-
- grind_unlock_buf();
- grind_free_buf();
- grind_free();
- log_flush();
- return 0;
-}
-
-static inline grind_DIVw() {
- const unsigned int FL_mask = 0x8D5U; // CF(0),PF(2),AF(4),ZF(6),SF(7),OF(11) 1000 1101 0101
- unsigned int i,j;
-
- if (!grind_init()) {
- grind_free();
- return 1;
- }
- if (!grind_alloc_buf()) {
- grind_free();
- return 1;
- }
- if (!grind_lock_buf()) {
- grind_free();
- return 1;
- }
-
- log_open("gr_div.bin");
- // header
- *((uint32_t*)(log_buf+log_bufi)) = 0x444E5247; // 'GRND'
- log_bufi += 4;
- *((uint32_t*)(log_buf+log_bufi)) = 0x77564944; // 'DIVw'
- log_bufi += 4;
- *((uint8_t*)(log_buf+log_bufi)) = sizeof(unsigned int); // sizeof unsigned int (2 or 4)
- log_bufi += 1;
- *((uint8_t*)(log_buf+log_bufi)) = cpu_flags; // CPU flags
- log_bufi += 1;
- *((unsigned int*)(log_buf+log_bufi)) = min_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_i; // min-max i inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = min_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = max_j; // min-max j inclusive
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = FL_mask; // flag test mask
- log_bufi += sizeof(unsigned int);
-
- log_lazy_flush(32);
-
- i = min_i;
- do {
- printf("i=%u j=%u..%u",i,min_j,max_j);
- fflush(stdout);
-
- j = min_j;
- do {
- grind_buf_ptr_t w = grind_buf;
-
- *((grind_imm_t*)(asm_buf+0)) = 0; // DIV result (AX)
- *((grind_imm_t*)(asm_buf+4)) = 0; // DIV result (DX)
- *((grind_imm_t*)(asm_buf+8)) = 0; // DIV result 2 (AX)
- *((grind_imm_t*)(asm_buf+12)) = 0; // DIV result 2 (DX)
- *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
- *((grind_imm_t*)(asm_buf+24)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+28)) = 0; // FLAGS after
-
- // do NOT divide by zero!
- if (j != 0) {
-// *w++ = GRIND_INT3_INS; // INT3
-
- // save DS, EAX, FLAGS
- w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__push_Reg(w,GRIND_REG_BX); // PUSH (E)BX
- w=grind_buf_w__push_Reg(w,GRIND_REG_DX); // PUSH (E)DX
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
-
- // DS = segment of asm_buf
- w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
- w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~FL_mask); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+16
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+0
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
- w=grind_buf_w__xor_Reg_Reg(w,GRIND_REG_DX,GRIND_REG_DX); // XOR (E)DX,(E)DX
- w=grind_buf_w__div_Reg(w,GRIND_REG_BX); // DIV (E)BX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_DX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, in asm_buf+20
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,FL_mask); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+24
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+24,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+4
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
- w=grind_buf_w__xor_Reg_Reg(w,GRIND_REG_DX,GRIND_REG_DX); // XOR (E)DX,(E)DX
- w=grind_buf_w__div_Reg(w,GRIND_REG_BX); // DIV (E)BX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_DX); // MOV [offset],(E)DX
-
- // store state of EFLAGS now, store result in asm_buf+28
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+28,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // restore FLAGS, EAX, DS, exit subroutine
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_DX); // POP (E)DX
- w=grind_buf_w__pop_Reg(w,GRIND_REG_BX); // POP (E)BX
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
- *w++ = GRIND_RET_INS; // RET
-
- // SANITY CHECK
- if (w > (grind_buf + grind_buf_size)) {
- printf("<--BUFFER OVERRUN\n");
- grind_free();
- return 1;
- }
-
- // EXECUTE IT
- if (!grind_execute_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- // sanity check
- if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+8)) ||
- *((grind_imm_t*)(asm_buf+4)) != *((grind_imm_t*)(asm_buf+12))) {
- printf("WARNING: Two DIV passes with different results (rem:res) %x:%x != %x:%x\n",
- *((grind_imm_t*)(asm_buf+4)), *((grind_imm_t*)(asm_buf+0)),
- *((grind_imm_t*)(asm_buf+12)), *((grind_imm_t*)(asm_buf+8)));
- }
- }//end j != 0
-
- // log results
- log_lazy_flush(64);
- *((unsigned int*)(log_buf+log_bufi)) = i; // I
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = j; // J
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+0)); // I/J (result)
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+4)); // I%J (remainder)
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+16)); // FLAGS before init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+20)); // FLAGS after init #1
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+24)); // FLAGS before init #2
- log_bufi += sizeof(unsigned int);
- *((unsigned int*)(log_buf+log_bufi)) = *((grind_imm_t*)(asm_buf+28)); // FLAGS after init #2
- log_bufi += sizeof(unsigned int);
- // log entry finish
- log_lazy_flush(16);
- } while ((j++) != max_j);
-
- printf("\x0D");
- fflush(stdout);
- } while ((i++) != max_i);
-
- grind_unlock_buf();
- grind_free_buf();
- grind_free();
- log_flush();
- return 0;
-}
-
-int main() {
- cpu_probe();
-
- printf("Testing ADDw x+y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
- grind_ADDw();
- log_close();
-
- printf("Testing SUBw x-y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
- grind_SUBw();
- log_close();
-
- printf("Testing MULw x*y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
- grind_MULw();
- log_close();
-
- printf("Testing DIVw x*y (%u <= x <= %u)+(%u <= y <= %u)\n",min_i,max_i,min_j,max_j);
- grind_DIVw();
- log_close();
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-echo Make sure you are running this from the dos86l or dos386f dir.\r
-echo Grind test in progress. Results will be written to the current directory.\r
-echo Look for GR_ADD.CPU and GR_ADD.BIN, GR_SUB.BIN, GR_MUL.BIN, and GR_DIV.BIN.\r
-rem MS-DOS doesn't support >> append mode. Argh.\r
-test >GR_ADD.CPU\r
-gr_add\r
-\r
+++ /dev/null
-/* grind.c
- *
- * Run instruction encodings through combinations and record changes to registers and flags.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/libgrind.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-static unsigned char asm_buf[64];
-
-static void pause_if_tty() {
- unsigned char c;
- if (isatty(1)) { do { read(0,&c,1); } while (c != 13); }
-}
-
-static int grind_selftest_buffer() {
- unsigned int i;
-
- for (i=0;i < 24;i++) {
- printf("Buffer test... ");fflush(stdout);
-
- printf("INIT ");fflush(stdout);
- if (!grind_init()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- printf("ALLOC(%zu) ",grind_buf_size);fflush(stdout);
- if (!grind_alloc_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- printf("LOCK ");fflush(stdout);
- if (!grind_lock_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-#ifdef GRIND_FAR
- printf("[buf=%x:%x] ",FP_SEG(grind_buf),FP_OFF(grind_buf));
-#else
- printf("[buf=%p] ",grind_buf);
-#endif
-
- printf("UNLOCK ");fflush(stdout);
- grind_unlock_buf();
-
- printf("FREE ");fflush(stdout);
- grind_free_buf();
-
- printf("OK\n");
- }
-
- return 0;
-}
-
-static int grind_selftest_bufwrite() {
- unsigned int i;
-
- for (i=0;i < 24;i++) {
- printf("Buffer write... ");fflush(stdout);
-
- printf("INIT ");fflush(stdout);
- if (!grind_init()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- printf("ALLOC ");fflush(stdout);
- if (!grind_alloc_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
- printf("[hnd=%x] ",grind_buf_whnd);
-#endif
-
- printf("LOCK ");fflush(stdout);
- if (!grind_lock_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-#ifdef GRIND_FAR
- printf("[buf=%x:%x] ",FP_SEG(grind_buf),FP_OFF(grind_buf));
-#else
- printf("[buf=%p] ",grind_buf);
-#endif
-
- printf("WRITE ");fflush(stdout);
- grind_buf[0] = i;
- grind_buf[1] = i+1;
-
- printf("UNLOCK ");fflush(stdout);
- grind_unlock_buf();
-
- printf("FREE ");fflush(stdout);
- grind_free_buf();
-
- printf("OK\n");
- }
-
- return 0;
-}
-
-static int grind_selftest_nullret() {
- unsigned int i;
-
- for (i=0;i < 24;i++) {
-#ifdef GRIND_FAR
- printf("RETF... ");fflush(stdout);
-#else
- printf("RET... ");fflush(stdout);
-#endif
-
- printf("INIT ");fflush(stdout);
- if (!grind_init()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- printf("ALLOC ");fflush(stdout);
- if (!grind_alloc_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- printf("LOCK ");fflush(stdout);
- if (!grind_lock_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- printf("WRITE ");fflush(stdout);
- grind_buf[0] = GRIND_RET_INS;
-
- printf("EXEC ");fflush(stdout);
- if (!grind_execute_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- printf("UNLOCK ");fflush(stdout);
- grind_unlock_buf();
-
- printf("FREE ");fflush(stdout);
- grind_free_buf();
-
- printf("OK\n");
- }
-
- return 0;
-}
-
-static inline grind_ADDw() {
- unsigned int i,j;
-
- if (!grind_init()) {
- grind_free();
- return 1;
- }
- if (!grind_alloc_buf()) {
- grind_free();
- return 1;
- }
- if (!grind_lock_buf()) {
- grind_free();
- return 1;
- }
-
- for (i=0;i < 64;i++) {
- for (j=0;j < 64;j++) {
- grind_buf_ptr_t w = grind_buf;
-
- *((grind_imm_t*)(asm_buf+0)) = 0; // ADD result
- *((grind_imm_t*)(asm_buf+4)) = 0; // ADD result (2)
- *((grind_imm_t*)(asm_buf+8)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+12)) = 0; // FLAGS after
- *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
-
-// *w++ = GRIND_INT3_INS; // INT3
-
- // save DS, EAX, FLAGS
- w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
-
- // DS = segment of asm_buf
- w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
- w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~0xAD5); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+8
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+0
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Add_const(w,GRIND_REG_AX,j); // ADD (E)AX,const
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, in asm_buf+12
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,0xAD5); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+16
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i + j, store result in asm_buf+4
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Add_const(w,GRIND_REG_AX,j); // ADD (E)AX,const
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // store state of EFLAGS now, store result in asm_buf+20
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // restore FLAGS, EAX, DS, exit subroutine
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
- *w++ = GRIND_RET_INS; // RET
-
- // SANITY CHECK
- if (w > (grind_buf + grind_buf_size)) {
- printf("<--BUFFER OVERRUN\n");
- grind_free();
- return 1;
- }
-
- // EXECUTE IT
- if (!grind_execute_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- // note what checked
- {
- // what changed after init, before ADDs
- grind_imm_t chf = *((grind_imm_t*)(asm_buf+8)) ^ *((grind_imm_t*)(asm_buf+16));
- // what changed between ADDs. IF(9) is supposed to change, therefore the ^0x200. ideally chf2 == 0 unless emulation problems.
- grind_imm_t chf2 = *((grind_imm_t*)(asm_buf+12)) ^ *((grind_imm_t*)(asm_buf+20)) ^ 0x200;
- // what flags were changed by both DIV instructions
- grind_imm_t chbf = ((*((grind_imm_t*)(asm_buf+8)) ^ *((grind_imm_t*)(asm_buf+12))) |
- (*((grind_imm_t*)(asm_buf+16)) ^ *((grind_imm_t*)(asm_buf+20)))) &
- chf;
-
- if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+4))) {
- printf("WARNING: Two ADD passes with different sums 0x%x != 0x%x\n",
- *((grind_imm_t*)(asm_buf+0)),
- *((grind_imm_t*)(asm_buf+4)));
- }
-
- // NTS: We want to know if EFLAGS differed after both ADD instructions to detect problems.
- // Executing the ADD instruction twice should show same results and same changes to the flags.
- printf("ADDw %3u + %-3u = %3u\n",i,j,(unsigned int)(*((grind_imm_t*)(asm_buf+0))));
- printf(" zero/set flags that changed: 0x%08x (wanted=0xAD5)\n",chf); // what flags we were able to change vs what we changed
- printf(" ...then after ADD: 0x%08x (^0x200 expect IF change)\n",chf2); // what differed between the two ADD instructions.
- printf(" flag changes (both): 0x%08x\n",chbf); // what was changed by DIV
- printf(" flag result: CF%u PF%u AF%u ZF%u SF%u TF%u IF%u DF%u OF%u\n",
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 0) & 1, // CF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 2) & 1, // PF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 4) & 1, // AF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 6) & 1, // ZF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 7) & 1, // SF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 8) & 1, // TF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 9) & 1, // IF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 10) & 1, // DF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 11) & 1); // OF
- }
- }
- }
-
- grind_unlock_buf();
- grind_free_buf();
- grind_free();
- return 0;
-}
-
-static inline grind_DIVw() {
- unsigned int i,j;
-
- if (!grind_init()) {
- grind_free();
- return 1;
- }
- if (!grind_alloc_buf()) {
- grind_free();
- return 1;
- }
- if (!grind_lock_buf()) {
- grind_free();
- return 1;
- }
-
- for (i=0;i < 64;i++) {
- for (j=1;j < 64;j++) { // do NOT divide by zero
- grind_buf_ptr_t w = grind_buf;
-
- *((grind_imm_t*)(asm_buf+0)) = 0; // DIV result
- *((grind_imm_t*)(asm_buf+4)) = 0; // DIV result (2)
- *((grind_imm_t*)(asm_buf+8)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+12)) = 0; // FLAGS after
- *((grind_imm_t*)(asm_buf+16)) = 0; // FLAGS before (after init)
- *((grind_imm_t*)(asm_buf+20)) = 0; // FLAGS after
- *((grind_imm_t*)(asm_buf+24)) = 0; // DIV remainder
- *((grind_imm_t*)(asm_buf+28)) = 0; // DIV remainder (2)
-
-// *w++ = GRIND_INT3_INS; // INT3
-
- // save DS, EAX, FLAGS
- w=grind_buf_w__push_Sreg(w,GRIND_SEG_DS); // PUSH DS
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__push_Reg(w,GRIND_REG_BX); // PUSH (E)BX
- w=grind_buf_w__push_Reg(w,GRIND_REG_DX); // PUSH (E)DX
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
-
- // DS = segment of asm_buf
- w=grind_buf_w__mov_Reg16_const(w,GRIND_REG_AX,FP_SEG(asm_buf)); // MOV AX,const
- w=grind_buf_w__mov_Seg_from_Reg(w,GRIND_SEG_DS,GRIND_REG_AX); // MOV <seg>,<reg>
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__and_Reg_const(w,GRIND_REG_AX,~0xAD5); // AND AX,<mask off CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+8
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+8,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i / j, store result in asm_buf+0
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
- w=grind_buf_w__xor_Reg_Reg(w,GRIND_REG_DX,GRIND_REG_DX); // XOR (E)DX,(E)DX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__div_Reg(w,GRIND_REG_BX); // DIV (E)BX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+0,GRIND_REG_AX); // MOV [offset],(E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+24,GRIND_REG_DX); // MOV [offset],(E)DX
-
- // store state of EFLAGS now, in asm_buf+12
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+12,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // set EFLAGS to known state
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__or_Reg_const(w,GRIND_REG_AX,0xAD5); // OR AX,<set CF(0),PF(2),AF(4),ZF(6),SF(7),IF(9),OF(11)> 1010 1101 0101
- w=grind_buf_w__push_Reg(w,GRIND_REG_AX); // PUSH (E)AX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
-
- // store state of EFLAGS now, store result in asm_buf+16
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+16,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // asm_buf+0 = i / j, store result in asm_buf+4
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_AX,i); // MOV (E)AX,const
- w=grind_buf_w__mov_Reg_const(w,GRIND_REG_BX,j); // MOV (E)BX,const
- w=grind_buf_w__xor_Reg_Reg(w,GRIND_REG_DX,GRIND_REG_DX); // XOR (E)DX,(E)DX
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__div_Reg(w,GRIND_REG_BX); // DIV (E)BX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+4,GRIND_REG_AX); // MOV [offset],(E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+28,GRIND_REG_DX); // MOV [offset],(E)DX
-
- // store state of EFLAGS now, store result in asm_buf+20
- w=grind_buf_w__push_Flags(w); // PUSHF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__mov_memoff_from_reg(w,FP_OFF(asm_buf)+20,GRIND_REG_AX); // MOV [offset],(E)AX
-
- // restore FLAGS, EAX, DS, exit subroutine
- w=grind_buf_w__pop_Flags(w); // POPF(D)
- w=grind_buf_w__pop_Reg(w,GRIND_REG_DX); // POP (E)DX
- w=grind_buf_w__pop_Reg(w,GRIND_REG_BX); // POP (E)BX
- w=grind_buf_w__pop_Reg(w,GRIND_REG_AX); // POP (E)AX
- w=grind_buf_w__pop_Sreg(w,GRIND_SEG_DS); // POP DS
- *w++ = GRIND_RET_INS; // RET
-
- // SANITY CHECK
- if (w > (grind_buf + grind_buf_size)) {
- printf("<--BUFFER OVERRUN\n");
- grind_free();
- return 1;
- }
-
- // EXECUTE IT
- if (!grind_execute_buf()) {
- printf("<--FAIL\n");
- grind_free();
- return 1;
- }
-
- // note what checked
- {
- // what changed after init, before DIVs
- grind_imm_t chf = *((grind_imm_t*)(asm_buf+8)) ^ *((grind_imm_t*)(asm_buf+16));
- // what changed between DIVs. IF(9) is supposed to change, therefore the ^0x200. ideally chf2 == 0 unless emulation problems.
- grind_imm_t chf2 = *((grind_imm_t*)(asm_buf+12)) ^ *((grind_imm_t*)(asm_buf+20)) ^ 0x200;
- // what flags were changed by both DIV instructions
- grind_imm_t chbf = ((*((grind_imm_t*)(asm_buf+8)) ^ *((grind_imm_t*)(asm_buf+12))) |
- (*((grind_imm_t*)(asm_buf+16)) ^ *((grind_imm_t*)(asm_buf+20)))) &
- chf;
-
- if (*((grind_imm_t*)(asm_buf+0)) != *((grind_imm_t*)(asm_buf+4))) {
- printf("WARNING: Two DIV passes with different results 0x%x != 0x%x\n",
- *((grind_imm_t*)(asm_buf+0)),
- *((grind_imm_t*)(asm_buf+4)));
- }
- if (*((grind_imm_t*)(asm_buf+24)) != *((grind_imm_t*)(asm_buf+28))) {
- printf("WARNING: Two DIV passes with different remainders 0x%x != 0x%x\n",
- *((grind_imm_t*)(asm_buf+24)),
- *((grind_imm_t*)(asm_buf+28)));
- }
-
- // NTS: We want to know if EFLAGS differed after both DIV instructions to detect problems.
- // Executing the DIV instruction twice should show same results and same changes to the flags.
- printf("DIVw %3u / %-3u = %3u remainder %u\n",i,j,(unsigned int)(*((grind_imm_t*)(asm_buf+0))),(unsigned int)(*((grind_imm_t*)(asm_buf+24))));
- printf(" zero/set flags that changed: 0x%08x (wanted=0xAD5)\n",chf); // what flags we were able to change vs what we changed
- printf(" ...then after DIV: 0x%08x (^0x200 expect IF change)\n",chf2); // what differed between the two DIV instructions.
- printf(" flag changes (both): 0x%08x\n",chbf); // what was changed by DIV
- printf(" flag result: CF%u PF%u AF%u ZF%u SF%u TF%u IF%u DF%u OF%u\n",
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 0) & 1, // CF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 2) & 1, // PF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 4) & 1, // AF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 6) & 1, // ZF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 7) & 1, // SF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 8) & 1, // TF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 9) & 1, // IF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 10) & 1, // DF
- (((unsigned int)(*((grind_imm_t*)(asm_buf+12)))) >> 11) & 1); // OF
- }
- }
- }
-
- grind_unlock_buf();
- grind_free_buf();
- grind_free();
- return 0;
-}
-
-int main() {
- cpu_probe();
- if (!grind_init()) {
- printf("Failed to init grind library\n");
- return 1;
- }
-
- if (grind_selftest_buffer()) return 1;
- pause_if_tty();
- if (grind_selftest_bufwrite()) return 1;
- pause_if_tty();
- if (grind_selftest_nullret()) return 1;
- pause_if_tty();
- if (grind_DIVw()) return 1;
- pause_if_tty();
- if (grind_ADDw()) return 1;
- pause_if_tty();
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-echo Make sure you are running this from the dos86l or dos386f dir.\r
-echo Grind test in progress. Results will be written to root directory of this drive.\r
-rem MS-DOS doesn't support >> append mode. Argh.\r
-test >\GRIND1.TXT\r
-grind >\GRIND2.TXT\r
-copy \GRIND1.TXT+\GRIND2.TXT \GRIND.TXT\r
-del \GRIND1.TXT\r
-del \GRIND2.TXT\r
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/libgrind.h>
-
-grind_buf_ptr_t grind_buf = NULL;
-size_t grind_buf_size = 0;
-uint8_t grind_buf_init = 0;
-uint8_t grind_buf_lock = 0;
-
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
-HGLOBAL grind_buf_whnd = 0; // GlobalAlloc() return value
-uint16_t grind_buf_dsel = 0;
-uint16_t grind_buf_csel = 0;
-#endif
-
-int grind_init() {
-#if TARGET_MSDOS == 32 && defined(TARGET_WINDOWS) && defined(WIN386)
- // double-check: even though the Win386 extender does not alloc segment bases from linear addr zero,
- // our code assumes that at least the code and data 32-bit segments have the same base. is that true?
- // if not, this code won't work.
- {
- WORD s1=0,s2=0;
-
- __asm {
- mov s1,cs
- mov s2,ds
- }
-
- if (GetSelectorBase(s1) != GetSelectorBase(s2)) {
- MessageBox((HWND)NULL,"Win386 error: GRIND library not available. CS.base != DS.base","",MB_OK);
- return 0;
- }
- if (GetSelectorLimit(s1) > GetSelectorLimit(s2)) {
- MessageBox((HWND)NULL,"Win386 error: GRIND library not available. CS.limit > DS.limit","",MB_OK);
- return 0;
- }
- }
-#endif
-
- if (!grind_buf_init) {
- grind_buf_size = 512;
- grind_buf_init = 1;
- }
-
- return grind_buf_init;
-}
-
-int grind_alloc_buf() {
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
- if (grind_buf_whnd == 0) {
- if (grind_buf_size < 128) return 0;
- grind_buf_whnd = GlobalAlloc(GPTR,grind_buf_size);
- if (grind_buf_whnd == 0) return 0;
- }
-
- return (grind_buf_whnd != 0)?1:0;
-#else
- if (grind_buf == NULL) {
- if (grind_buf_size < 128) return 0;
-# ifdef GRIND_FAR
- grind_buf = _fmalloc(grind_buf_size);
-# else
- grind_buf = malloc(grind_buf_size);
-#endif
- }
-
- return (grind_buf != NULL)?1:0;
-#endif
-}
-
-int grind_lock_buf() {
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
- if (grind_buf_dsel == 0 && grind_buf_whnd != 0) {
- grind_buf = GlobalLock(grind_buf_whnd);
- if (grind_buf == NULL) return 0;
- grind_buf_dsel = FP_SEG(grind_buf);
- }
- if (grind_buf_csel == 0) {
- grind_buf_csel = AllocDStoCSAlias(grind_buf_dsel);
- if (grind_buf_csel == 0) {
- grind_unlock_buf();
- return 0;
- }
- }
-#endif
- grind_buf_lock = 1;
- return grind_buf_lock;
-}
-
-void grind_unlock_buf() {
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
- if (grind_buf_csel) {
- // NTS: Omitting the call to FreeSelector() doesn't seem to leak in Windows 3.1. Does GlobalAlloc
- // somehow track aliases to the segment? Seems like an invitation for bad coding practice to me.
- FreeSelector(grind_buf_csel);
- grind_buf_csel = 0;
- }
- if (grind_buf_dsel) {
- GlobalUnlock(grind_buf_whnd);
- grind_buf_dsel = 0;
- }
-#endif
- grind_buf_lock = 0;
-}
-
-void grind_free_buf() {
- if (grind_buf != NULL) {
- grind_unlock_buf();
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
- if (grind_buf_whnd) {
- GlobalFree(grind_buf_whnd);
- grind_buf_whnd = 0;
- }
-#else
-# ifdef GRIND_FAR
- _ffree(grind_buf);
-# else
- free(grind_buf);
-# endif
-#endif
- grind_buf = NULL;
- }
-}
-
-void grind_free() {
- grind_unlock_buf();
- grind_free_buf();
-}
-
-int grind_execute_buf() {
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
- void far *x;
-
- if (grind_buf_csel == 0) return 0;
-
- x = MK_FP(grind_buf_csel,FP_OFF(grind_buf));
- __asm callf [x]
-#else
- if (grind_buf == NULL) return 0;
-
-# ifdef GRIND_FAR
- __asm callf [grind_buf]
-# else
- __asm call [grind_buf]
-# endif
-#endif
-
- return 1;
-}
-
+++ /dev/null
-
-#ifndef __HW_CPU_LIBGRIND_H
-#define __HW_CPU_LIBGRIND_H
-
-#include <stdint.h>
-
-#include <hw/cpu/cpu.h>
-
-#if defined(TARGET_WINDOWS)
-# include <windows.h>
-#endif
-
-#if TARGET_MSDOS == 32
-# define GRIND_REGSIZE 32
-# define GRIND_CODE32
-typedef uint32_t grind_off_t;
-typedef uint16_t grind_seg_t;
-typedef uint32_t grind_imm_t;
-#else
-# define GRIND_REGSIZE 16
-# define GRIND_CODE16
-# define GRIND_FAR
-typedef uint16_t grind_off_t;
-typedef uint16_t grind_seg_t;
-typedef uint16_t grind_imm_t;
-#endif
-
-#ifdef GRIND_FAR
-typedef unsigned char far* grind_buf_ptr_t;
-# define GRIND_RET_INS (0xCB) /* RETF */
-#else
-typedef unsigned char* grind_buf_ptr_t;
-# define GRIND_RET_INS (0xC3) /* RET */
-#endif
-
-#define GRIND_INT3_INS (0xCC) /* INT 3 */
-
-#if TARGET_MSDOS == 16 && defined(TARGET_WINDOWS) /* For this to work in Windows 3.1, we need a code segment alias of our data segment */
-# define GRIND_NEED_CODE_ALIAS_SEL
-#endif
-
-extern grind_buf_ptr_t grind_buf;
-extern size_t grind_buf_size;
-extern uint8_t grind_buf_init;
-extern uint8_t grind_buf_lock;
-
-#ifdef GRIND_NEED_CODE_ALIAS_SEL
-extern HGLOBAL grind_buf_whnd;
-extern uint16_t grind_buf_dsel;
-extern uint16_t grind_buf_csel;
-#endif
-
-int grind_init();
-int grind_lock_buf();
-int grind_alloc_buf();
-void grind_unlock_buf();
-int grind_execute_buf();
-void grind_free_buf();
-void grind_free();
-
-// regs
-enum {
- GRIND_REG_AX=0,
- GRIND_REG_CX,
- GRIND_REG_DX,
- GRIND_REG_BX,
- GRIND_REG_SP,
- GRIND_REG_BP,
- GRIND_REG_SI,
- GRIND_REG_DI
-};
-
-// sregs
-enum {
- GRIND_SEG_ES=0,
- GRIND_SEG_CS,
- GRIND_SEG_SS,
- GRIND_SEG_DS
-};
-
-// PUSH sreg
-static inline grind_buf_ptr_t grind_buf_w__push_Sreg(grind_buf_ptr_t w,unsigned char sreg) {
- if (sreg >= 4) return w;
- *w++ = 0x06 + (sreg << 3);
- return w;
-}
-
-// PUSH (E)reg
-static inline grind_buf_ptr_t grind_buf_w__push_Reg(grind_buf_ptr_t w,unsigned char reg) {
- if (reg >= 8) return w;
- *w++ = 0x50 + (reg&7);
- return w;
-}
-
-// PUSHF(D)
-static inline grind_buf_ptr_t grind_buf_w__push_Flags(grind_buf_ptr_t w) {
- *w++ = 0x9C;
- return w;
-}
-
-// ADD (E)reg,const
-static inline grind_buf_ptr_t grind_buf_w__mov_Add_const(grind_buf_ptr_t w,unsigned char reg,unsigned int c) {
- if (reg >= 8) return w;
- if (reg == GRIND_REG_AX) {
- *w++ = 0x05; // ADD (E)AX,const
- }
- else {
- *w++ = 0x81; // ADD reg,const
- *w++ = (3 << 6) + (0/*ADD*/ << 3) + reg; // mod=3 reg=0 r/m=reg
- }
- *((grind_imm_t*)w) = c; w += sizeof(grind_imm_t);
- return w;
-}
-
-// SUB (E)reg,const
-static inline grind_buf_ptr_t grind_buf_w__mov_Sub_const(grind_buf_ptr_t w,unsigned char reg,unsigned int c) {
- if (reg >= 8) return w;
- if (reg == GRIND_REG_AX) {
- *w++ = 0x05+0x28; // SUB (E)AX,const
- }
- else {
- *w++ = 0x81; // SUB reg,const
- *w++ = (3 << 6) + (5/*SUB*/ << 3) + reg; // mod=3 reg=0 r/m=reg
- }
- *((grind_imm_t*)w) = c; w += sizeof(grind_imm_t);
- return w;
-}
-
-// OR (E)reg,const
-static inline grind_buf_ptr_t grind_buf_w__or_Reg_const(grind_buf_ptr_t w,unsigned char reg,unsigned int c) {
- if (reg >= 8) return w;
- if (reg == GRIND_REG_AX) {
- *w++ = 0x0D; // OR (E)AX,const
- }
- else {
- *w++ = 0x81; // OR reg,const
- *w++ = (3 << 6) + (1/*OR*/ << 3) + reg; // mod=3 reg=0 r/m=reg
- }
- *((grind_imm_t*)w) = c; w += sizeof(grind_imm_t);
- return w;
-}
-
-// AND (E)reg,const
-static inline grind_buf_ptr_t grind_buf_w__and_Reg_const(grind_buf_ptr_t w,unsigned char reg,unsigned int c) {
- if (reg >= 8) return w;
- if (reg == GRIND_REG_AX) {
- *w++ = 0x25; // AND (E)AX,const
- }
- else {
- *w++ = 0x81; // AND reg,const
- *w++ = (3 << 6) + (4/*AND*/ << 3) + reg; // mod=3 reg=0 r/m=reg
- }
- *((grind_imm_t*)w) = c; w += sizeof(grind_imm_t);
- return w;
-}
-
-// MOV (E)reg,const
-static inline grind_buf_ptr_t grind_buf_w__mov_Reg_const(grind_buf_ptr_t w,unsigned char reg,unsigned int c) {
- if (reg >= 8) return w;
- *w++ = 0xB8 + (reg&7);
- *((grind_imm_t*)w) = c; w += sizeof(grind_imm_t);
- return w;
-}
-
-// MOV (E)reg,const
-static inline grind_buf_ptr_t grind_buf_w__mov_Reg16_const(grind_buf_ptr_t w,unsigned char reg,uint16_t c) {
- if (reg >= 8) return w;
-#ifdef GRIND_CODE32
- *w++ = 0x66; // 32-bit data, override to 16-bit
-#endif
- *w++ = 0xB8 + (reg&7);
- *((uint16_t*)w) = c; w += sizeof(uint16_t);
- return w;
-}
-
-// MOV <seg>,<reg>
-static inline grind_buf_ptr_t grind_buf_w__mov_Seg_from_Reg(grind_buf_ptr_t w,unsigned char sreg,unsigned char reg) {
- if (sreg >= 4) return w;
- if (reg >= 8) return w;
- *w++ = 0x8E; // MOV Sreg,r/m16
- *w++ = (3 << 6) + (sreg << 3) + reg; // mod=3 reg=sreg r/m=reg
- return w;
-}
-
-// POPF(D)
-static inline grind_buf_ptr_t grind_buf_w__pop_Flags(grind_buf_ptr_t w) {
- *w++ = 0x9D;
- return w;
-}
-
-// POP (E)reg
-static inline grind_buf_ptr_t grind_buf_w__pop_Reg(grind_buf_ptr_t w,unsigned char reg) {
- if (reg >= 8) return w;
- *w++ = 0x58 + (reg&7);
- return w;
-}
-
-// POP sreg
-static inline grind_buf_ptr_t grind_buf_w__pop_Sreg(grind_buf_ptr_t w,unsigned char sreg) {
- if (sreg >= 4) return w;
- *w++ = 0x07 + (sreg << 3);
- return w;
-}
-
-// MOV [offset],reg
-static inline grind_buf_ptr_t grind_buf_w__mov_memoff_from_reg(grind_buf_ptr_t w,grind_off_t o,unsigned char reg) {
- if (reg == GRIND_REG_AX) {
- *w++ = 0xA3; // MOV [offset],(E)AX
- }
- else {
- *w++ = 0x89; // MOV [offset],(E)reg
-#ifdef GRIND_CODE32
- *w++ = (0 << 6) + (reg << 3) + (5); // mod=0 reg=reg r/m=5 32-bit encoding
-#else
- *w++ = (0 << 6) + (reg << 3) + (6); // mod=0 reg=reg r/m=6 16-bit encoding
-#endif
- }
- *((grind_off_t*)w) = o; w += sizeof(grind_off_t);
- return w;
-}
-
-// XOR reg,reg
-static inline grind_buf_ptr_t grind_buf_w__xor_Reg_Reg(grind_buf_ptr_t w,unsigned char reg1,unsigned char reg2) {
- if (reg1 >= 8 || reg2 >= 8) return w;
- *w++ = 0x31;
- *w++ = (3 << 6) + (reg2 << 3) + reg1; // mod=3 reg=reg2 r/m=reg1
- return w;
-}
-
-// DIV reg
-static inline grind_buf_ptr_t grind_buf_w__div_Reg(grind_buf_ptr_t w,unsigned char reg) {
- if (reg >= 8) return w;
- *w++ = 0xF7;
- *w++ = (3 << 6) + (6/*DIV*/ << 3) + reg; // mod=3 reg=6 r/m=reg1
- return w;
-}
-
-// MUL reg
-static inline grind_buf_ptr_t grind_buf_w__mul_Reg(grind_buf_ptr_t w,unsigned char reg) {
- if (reg >= 8) return w;
- *w++ = 0xF7;
- *w++ = (3 << 6) + (4/*MUL*/ << 3) + reg; // mod=3 reg=4 r/m=reg1
- return w;
-}
-
-#endif /* __HW_CPU_LIBGRIND_H */
-
+++ /dev/null
-/* mmx.c
- *
- * Test program: Proof of concept detection and use of the MMX extensions
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-static unsigned char temp[2048];
-static unsigned char *tempa;
-
-int main() {
- /* all we need is a 8-byte aligned pointer */
- /* NOTE: This alignment calculation works properly in both
- 16-bit real mode and 32-bit flat mode */
- tempa = temp; tempa += (8UL - (((unsigned long)tempa) & 7UL)) & 7UL;
-
- cpu_probe();
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
- if (cpu_v86_active) {
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
- }
- if (!(cpu_flags & CPU_FLAG_CPUID)) {
- printf(" - No CPUID present. How can you have MMX extensions without CPUID?\n");
- return 1;
- }
- if (!(cpu_cpuid_features.a.raw[2] & (1UL << 23UL))) {
- printf(" - Your CPU does not support MMX extensions\n");
- return 1;
- }
-
- /* NOTE: You can execute MMX instructions in real mode.
- You can also use them within the v8086 environment
- provided by EMM386.EXE. Just don't use 32-bit addressing
- when in v86 mode and you won't crash */
-
- *((uint64_t*)(tempa+0)) = 0x0011223344556677ULL;
- *((uint64_t*)(tempa+8)) = 0x1111111111111111ULL;
-
-#if TARGET_MSDOS == 32
- __asm {
- .686p
- .mmx
- mov esi,tempa
- movq mm0,[esi+8]
- paddb mm0,[esi+0]
- movq [esi+16],mm0
- psubusb mm0,[esi+8]
- movq [esi+24],mm0
- psubusb mm0,[esi+8]
- movq [esi+32],mm0
- }
-#elif defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .686p
- .mmx
- push ds
- lds si,tempa
- movq mm0,[si+8]
- paddb mm0,[si+0]
- movq [si+16],mm0
- psubusb mm0,[si+8]
- movq [si+24],mm0
- psubusb mm0,[si+8]
- movq [si+32],mm0
- pop ds
- }
-#else
- __asm {
- .686p
- .mmx
- mov si,tempa
- movq mm0,[si+8]
- paddb mm0,[si+0]
- movq [si+16],mm0
- psubusb mm0,[si+8]
- movq [si+24],mm0
- psubusb mm0,[si+8]
- movq [si+32],mm0
- }
-#endif
- __asm {
- .686p
- .mmx
- emms
- }
-
- printf("PADDB: %016llX + %016llX = %016llX\n",
- *((uint64_t*)(tempa+0)),
- *((uint64_t*)(tempa+8)),
- *((uint64_t*)(tempa+16)));
- printf("PSUBUSB: %016llX - %016llX = %016llX - %016llX = %016llX\n",
- *((uint64_t*)(tempa+16)),
- *((uint64_t*)(tempa+8)),
- *((uint64_t*)(tempa+24)),
- *((uint64_t*)(tempa+8)),
- *((uint64_t*)(tempa+32)));
-
- return 0;
-}
-
+++ /dev/null
-Failed experiments:
-
- - Direct entry into RING 3 via VCPI (PRO3VCPI.ASM)
- - Not going to work. VCPI servers assume you're entering into ring 0.
- - Entering with a ring 3 address directly is not possible because of VCPI's ring 0 selectors.
-
+++ /dev/null
-; prot286.asm
-;
-; Test program: 80286 protected mode
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 286 protected mode (and back)
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; SELECTORS
-NULL_SEL equ 0
-CODE_SEL equ 8
-DATA_SEL equ 16
-VIDEO_SEL equ 24
-MAX_SEL equ 32
-
-; ===== ENTRY POINT
- call cpu_is_286
- je is_286
- mov dx,str_cpu_not_286
- jmp exit2dos_with_message
-is_286:
-
-; ===== CHECK FOR VIRTUAL 8086 MODE
- smsw ax ; 386 or higher: If we're in real mode
- test al,1 ; and bit 0 is already set, we're in virtual 8086
- jz is_realmode ; and our switch to prot mode will cause problems.
- mov dx,str_cpu_v86_mode
- jmp exit2dos_with_message
-is_realmode:
-
-; ===== WE NEED TO PATCH SOME OF OUR OWN CODE
- mov ax,cs
- mov word [real_entry_patch+3],ax ; overwrite segment field of JMP SEG:OFF
-
-; ===== BUILD THE GLOBAL DESCRIPTOR TABLE AND GDTR REGISTER
- mov ax,cs
- mov bx,ax
- shr bx,12
- shl ax,4 ; BX:AX = 32-bit physical addr of our segment
- mov word [MY_PHYS_BASE],ax
- mov word [MY_PHYS_BASE+2],bx
-
- add ax,GDT
- adc bx,0 ; BX:AX += offset of GDT
-
- mov word [GDTR],MAX_SEL - 1
- mov word [GDTR+2],ax
- mov word [GDTR+4],bx ; GDTR: limit MAX_SEL-1 base=physical mem addr of GDT
-
- mov ax,word [MY_PHYS_BASE]
- mov bx,word [MY_PHYS_BASE+2]
- add ax,IDT
- adc bx,0
-
- mov word [IDTR],2047
- mov word [IDTR+2],ax
- mov word [IDTR+4],bx
-
- cld
-
-; zero IDT
- mov di,IDT
- mov cx,1023
- xor ax,ax
- rep stosw
-
- mov di,GDT
-; NULL selector
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
-; Code selector
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- xor ah,ah ; LIMIT[19:16] flags=0
- stosw
-; Data selector
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- xor ah,ah ; LIMIT[19:16] flags=0
- stosw
-; Data selector (video)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- xor ah,ah ; LIMIT[19:16] flags=0
- stosw
-
-; make sure the BIOS knows what to do and where to jump if we have to do the 286 reset method of
-; getting back to real mode
- cli
- mov al,0x0F
- out 70h,al
- mov al,0x0A
- out 71h,al
- push es
- mov ax,40h
- mov es,ax
- mov di,0x67 ; ES:DI = 0x40:0x67 BIOS RESET VECTOR
- mov ax,real_entry
- stosw
- mov ax,cs
- stosw
- pop es
-
- cli ; disable interrupts
- lgdt [GDTR] ; load into processor GDTR
- lidt [IDTR]
-
-; switch into protected mode
- mov ax,1
- lmsw ax
- jmp CODE_SEL:prot_entry
-prot_entry: mov ax,DATA_SEL ; now reload the segment registers
- mov ds,ax
- mov es,ax
- mov ss,ax
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- push es
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,vdraw_msg
- xor di,di
-vdraw1: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw1e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw1
-vdraw1e: pop es
-
-; switch back to real mode.
-; Unfortunately a true 286 system cannot switch back to real mode. The only way to do it is to
-; reset the CPU, having set special bytes into CMOS and a reset vector for the BIOS to jump to after
-; CPU reset.
-
-; one good way to do it is to purposely make the interrupt vector table unusable
- xor ax,ax
- mov di,IDTR
- mov word [di],ax
- mov word [di+2],ax
- mov word [di+4],ax
- lidt [IDTR]
-; then... use 386 instructions to clear protected mode. if we're running on an
-; actual 286, these instructions will trigger an invalid opcode exception,
-; which because of what we did to the IDTR, is not available. This causes a
-; double, and then triple fault which then causes the CPU to reset.
-;
-; It's a lot easier to code than trying every corner case between port 92h
-; and writing the keyboard controller. On 386 or higher systems, this code
-; executes perfectly and does not cause a fault and reset at all.
- xor eax,eax ; clear bit 0
- mov cr0,eax
-
-real_entry_patch:jmp 0x0000:real_entry ; the segment field is patched by code above
-real_entry: mov ax,cs
- mov ds,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; ===== REBUILD GDTR FOR PROPER REAL MODE OPERATION
- mov word [GDTR],0xFFFF
- mov word [GDTR+2],0
- mov word [GDTR+4],0 ; GDTR: limit 0xFFFF base 0x00000000
- lgdt [GDTR] ; load into processor GDTR
-
- mov word [IDTR],0xFFFF
- mov word [IDTR+2],0
- mov word [IDTR+4],0 ; IDTR: limit 0xFFFF base 0x00000000
- lidt [IDTR]
-
-; ====== PROVE WE MADE IT TO REAL MODE
- mov si,vdraw2_msg
- mov ax,0xB800
- mov es,ax
- mov di,80*2
-vdraw2: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw2e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw2
-vdraw2e: mov ax,cs
- mov es,ax
-
- sti
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-; 8086 test: EFLAGS will always have bits 12-15 set
-cpu_is_286: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_286_not
- xor ax,ax ; ZF=1
- ret
-cpu_is_286_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; strings
-str_cpu_not_286: db "286 or higher required$"
-str_cpu_v86_mode: db "Virtual 8086 mode detected$"
-vdraw_msg: db "This message was drawn on screen from 286 protected mode!",0
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-
-; THESE VARIABLES DO NOT EXIST IN THE ACTUAL .COM FILE.
-; They exist in the yet-uninitialized area of RAM just beyond the
-; end of the loaded COM file image.
- align 8
-RALLOC: db 0xAA
-GDTR equ RALLOC+0
-IDTR equ GDTR+8
-MY_PHYS_BASE equ IDTR+8
-GDT equ MY_PHYS_BASE+8
-IDT equ GDT+MAX_SEL
-
+++ /dev/null
-; prot386.asm
-;
-; Test program: 80386 protected mode
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 386 16-bit & 32-bit protected mode (and back)
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; SELECTORS
-NULL_SEL equ 0
-CODE_SEL equ 8
-DATA_SEL equ 16
-VIDEO_SEL equ 24
-CODE32_SEL equ 32
-DATA32_SEL equ 40
-MAX_SEL equ 48
-
-; ===== ENTRY POINT
- call cpu_is_386
- je is_386
- mov dx,str_cpu_not_386
- jmp exit2dos_with_message
-is_386:
-
-; ===== CHECK FOR VIRTUAL 8086 MODE
- smsw ax ; 386 or higher: If we're in real mode
- test al,1 ; and bit 0 is already set, we're in virtual 8086
- jz is_realmode ; and our switch to prot mode will cause problems.
- mov dx,str_cpu_v86_mode
- jmp exit2dos_with_message
-is_realmode:
-
-; ===== WE NEED TO PATCH SOME OF OUR OWN CODE
- mov ax,cs
- mov word [real_entry_patch+3],ax ; overwrite segment field of JMP SEG:OFF
-
-; ===== BUILD THE GLOBAL DESCRIPTOR TABLE AND GDTR REGISTER
- mov ax,cs
- mov bx,ax
- shr bx,12
- shl ax,4 ; BX:AX = 32-bit physical addr of our segment
- mov word [MY_PHYS_BASE],ax
- mov word [MY_PHYS_BASE+2],bx
-
- add ax,GDT
- adc bx,0 ; BX:AX += offset of GDT
-
- mov word [GDTR],MAX_SEL - 1
- mov word [GDTR+2],ax
- mov word [GDTR+4],bx ; GDTR: limit MAX_SEL-1 base=physical mem addr of GDT
-
- mov ax,word [MY_PHYS_BASE]
- mov bx,word [MY_PHYS_BASE+2]
- add ax,IDT
- adc bx,0
-
- mov word [IDTR],2047
- mov word [IDTR+2],ax
- mov word [IDTR+4],bx
-
- cld
-
-; zero IDT
- mov di,IDT
- mov cx,1023
- xor ax,ax
- rep stosw
-
- mov di,GDT
-; NULL selector
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
-; Code selector
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (video)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (32-bit)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; Data selector (32-bit)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-
-; load CPU registers
- cli ; disable interrupts
- lgdt [GDTR] ; load into processor GDTR
- lidt [IDTR]
-
-; switch into protected mode
- mov eax,0x00000001
- mov cr0,eax
- jmp CODE_SEL:prot_entry
-prot_entry: mov ax,DATA_SEL ; now reload the segment registers
- mov ds,ax
- mov es,ax
- mov ss,ax
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- push es
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,vdraw_msg
- xor di,di
-vdraw1: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw1e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw1
-vdraw1e: pop es
-
-; now, jump into 32-bit protected mode
- jmp CODE32_SEL:prot32_entry
-bits 32
-prot32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov esp,0xFFF0
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- mov esi,vdraw32_msg
- mov edi,0xB8000+(80*2)
- sub edi,[MY_PHYS_BASE]
-vdraw321: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw321e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw321
-vdraw321e:
-
-; jump 32-bit to 16-bit
- jmp CODE_SEL:prot32_to_prot
-bits 16
-prot32_to_prot: mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
-
-; switch back to real mode.
-; unlike the 286, switching back means clearing bit 0 of CR0
- xor eax,eax ; clear bit 0
- mov cr0,eax
-
-real_entry_patch:jmp 0x0000:real_entry ; the segment field is patched by code above
-real_entry: mov ax,cs
- mov ds,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; ===== REBUILD GDTR FOR PROPER REAL MODE OPERATION
- mov word [GDTR],0xFFFF
- mov word [GDTR+2],0
- mov word [GDTR+4],0 ; GDTR: limit 0xFFFF base 0x00000000
- lgdt [GDTR] ; load into processor GDTR
-
- mov word [IDTR],0xFFFF
- mov word [IDTR+2],0
- mov word [IDTR+4],0 ; IDTR: limit 0xFFFF base 0x00000000
- lidt [IDTR]
-
-; ====== PROVE WE MADE IT TO REAL MODE
- mov si,vdraw2_msg
- mov ax,0xB800
- mov es,ax
- mov di,80*4
-vdraw2: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw2e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw2
-vdraw2e: mov ax,cs
- mov es,ax
-
- sti
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-; 8086 test: EFLAGS will always have bits 12-15 set
-cpu_is_386: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_386_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_386_not
-; it's a 386
- xor ax,ax ; ZF=1
- ret
-cpu_is_386_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; strings
-str_cpu_not_386: db "386 or higher required$"
-str_cpu_v86_mode: db "Virtual 8086 mode detected$"
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-vdraw_msg: db "This message was drawn on screen from 386 16-bit protected mode!",0
-vdraw32_msg: db "This message was drawn on screen from 386 32-bit protected mode!",0
-
-; THESE VARIABLES DO NOT EXIST IN THE ACTUAL .COM FILE.
-; They exist in the yet-uninitialized area of RAM just beyond the
-; end of the loaded COM file image.
- align 8
-RALLOC: db 0xAA
-GDTR equ RALLOC+0
-IDTR equ GDTR+8
-MY_PHYS_BASE equ IDTR+8
-GDT equ MY_PHYS_BASE+8
-IDT equ GDT+MAX_SEL
-
+++ /dev/null
-; protdpmi.asm
-;
-; Test program: Protected mode via DPMI (DOS Protected Mode Interface)
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 386 16-bit protected mode (and back) using DPMI
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; ===== ENTRY POINT
- mov ax,cs
- mov ds,ax
- mov es,ax
- mov ss,ax
-
-; we need to use DOS memory allocation, so we first need to resize our
-; memory ownership down to the actual size of the COM file.
-; Windows NT/XP/etc. seem to assume the COM takes 64KB, while Windows 95
-; follows the DOS way and has the COM assume all memory. So for this
-; code to work under Win9x much less DOS we need to do this step.
- mov ah,0x4A ; INT 21h AH=4Ah resize memory block
- mov bx,cs
- mov es,bx ; ES=our PSP segment
- mov bx,ENDOI
- shr bx,4 ; in paragraphs, the size of this program + data
- int 21h
-
- mov [MY_SEGMENT],ax
- mov bx,ax
- shr bx,12
- shl ax,4
- mov [MY_PHYS_BASE+2],bx
- mov [MY_PHYS_BASE+0],ax
-
- mov ax,0x1687
- int 2Fh
- or ax,ax
- jz dpmi_present
- mov dx,str_cpu_need_dpmi
- jmp exit2dos_with_message
-dpmi_present:
- mov [dpmi_entry+0],di
- mov [dpmi_entry+2],es
- mov [dpmi_data_size],si
-
-; allocate private data for DPMI server, if needed
- mov word [dpmi_data_seg],0
- cmp word [dpmi_data_size],0
- jz dpmi_no_private
- mov ah,0x48
- mov bx,[dpmi_data_size] ; in paragraphs
- int 21h
- jnc .allocd
- mov dx,str_cpu_dpmi_private_alloc_fail
- jmp exit2dos_with_message
-.allocd: mov [dpmi_data_seg],ax
-dpmi_no_private:
-; at this point: either we allocated memory successfully, or the DPMI server does not need private data segment
-; make the jump
- mov es,[dpmi_data_seg]
- mov ax,1 ; 16-bit app
- call far word [dpmi_entry]
- jnc dpmi_ok
- mov dx,str_dpmi_entry_fail
- jmp exit2dos_with_message
-dpmi_ok:
-; save our protected mode side
- mov ax,cs
- mov [MY_CODE_SEL],ax
- mov ax,ds
- mov [MY_DATA_SEL],ax
-
-; we need a selector to draw on the screen with
- mov ax,0x0002
- mov bx,0xB800
- int 31h
- mov [vga_sel],ax
-
-; draw on the screen
- mov si,vdraw_msg
- xor di,di
- call vga_puts
-
-; now switch back to real mode
- mov ax,0x0306
- int 31h
- mov [raw_entry],cx
- mov [raw_entry+2],bx
- mov [raw_exit],edi
- mov [raw_exit+4],si
-
-; switch
- mov ax,[MY_SEGMENT] ; AX will become DS
- mov cx,ax ; CX will become ES
- mov dx,ax ; DX will become SS
- movzx ebx,sp ; EBX will become (E)SP
- mov si,ax ; SI will become CS
- mov edi,.realmode
- jmp far dword [raw_exit]
-.realmode:
-
-; we made it!
- mov si,vdraw2_msg
- mov di,80*2
- call vga_puts_real
-
-; jump back to protected mode
- mov ax,[MY_DATA_SEL] ; AX will become DS
- mov cx,ax ; CX will become ES
- mov dx,ax ; DX will become SS
- movzx ebx,sp ; EBX will become (E)SP
- mov si,[MY_CODE_SEL] ; SI will become CS
- mov edi,.protagain
- jmp far word [raw_entry]
-.protagain:
-
-; we made it!
- mov si,vdraw3_msg
- mov di,80*2*2
- call vga_puts
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-vga_puts_real:
-; DS:SI = what to put
-; DI = where to put it
- push es
- push ax
- push si
- push di
- cld
- mov ax,0xB800
- mov es,ax
-.l1: lodsb
- or al,al
- jz .le
- mov ah,0x1E
- stosw
- jmp .l1
-.le: pop di
- pop si
- pop ax
- pop es
- ret
-
-vga_puts:
-; DS:SI = what to put
-; DI = where to put it
- push es
- push ax
- push si
- push di
- cld
- mov ax,[vga_sel]
- mov es,ax
-.l1: lodsb
- or al,al
- jz .le
- mov ah,0x1E
- stosw
- jmp .l1
-.le: pop di
- pop si
- pop ax
- pop es
- ret
-
-; strings
-str_cpu_need_dpmi:db "DPMI server required$"
-str_cpu_dpmi_private_alloc_fail:db "Unable to allocate private data for DPMI$"
-str_dpmi_entry_fail:db "Unable to enter DPMI protected mode$"
-vdraw_msg: db "This message was drawn on screen from DPMI 16-bit protected mode!",0
-vdraw3_msg: db "This message was drawn on screen back into DPMI 16-bit protected mode!",0
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-
-; vars
- section .bss align=8
-dpmi_entry: resd 1
-raw_entry: resd 1
-raw_exit: resd 1
- resw 1
-dpmi_data_size: resw 1
-dpmi_data_seg: resw 1
-MY_PHYS_BASE: resd 1
-MY_CODE_SEL: resw 1
-MY_DATA_SEL: resw 1
-MY_SEGMENT: resd 1
-vga_sel: resw 1
-ENDOI: resb 1
-
+++ /dev/null
-; protvcpi.asm
-;
-; Test program: Protected mode via VCPI
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 386 16-bit protected mode (and back) using VCPI
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; SELECTORS
-NULL_SEL equ 0
-CODE_SEL equ 8
-DATA_SEL equ 16
-VIDEO_SEL equ 24
-CODE32_SEL equ 32
-DATA32_SEL equ 40
-VCPI0_SEL equ 48
-VCPI1_SEL equ 56
-VCPI2_SEL equ 64
-TSS_SEL equ 72
-TSS2_SEL equ 80
-MAX_SEL equ 88
-
-; ===== ENTRY POINT
- call cpu_is_386
- je is_386
- mov dx,str_cpu_not_386
- jmp exit2dos_with_message
-is_386:
-
-; ===== CHECK FOR VIRTUAL 8086 MODE. IN THIS CASE WE WANT IT, IT MEANS VCPI IS PRESENT
- smsw ax ; 386 or higher: If we're in real mode
- test al,1 ; and bit 0 is already set, we're in virtual 8086
- jnz isnt_realmode ; and our switch to prot mode will cause problems.
- mov dx,str_cpu_need_v86_mode
- jmp exit2dos_with_message
-isnt_realmode:
-
-; choose memory location for PAGE0, PAGEDIR. they must be 4K aligned
- xor ecx,ecx
- mov cx,cs
- shl ecx,4
-
- lea edi,[ecx+ENDOI]
- add edi,0xFFF
- and edi,0xF000
- sub edi,ecx
- mov dword [PAGE0],edi
- add edi,0x1000
- mov dword [PAGEDIR],edi
-
-; ===== CHECK FOR VALID INT 67h
- xor ax,ax
- mov es,ax
- mov ax,[es:(0x67*4)]
- or ax,[es:(0x67*4)+2]
- or ax,ax
- jnz int67_valid
- mov dx,str_cpu_need_int67
- jmp exit2dos_with_message
-
-; ===== CHECK FOR VCPI
-int67_valid: mov ax,0xDE00
- int 67h
- cmp ah,0
- jz vcpi_valid
- mov dx,str_cpu_need_vcpi
- jmp exit2dos_with_message
-
-; fill in the page table, get VCPI selectors, and entry point
-vcpi_valid: mov ax,0xDE01
- push ds
- pop es
- mov edi,[PAGE0]
- mov esi,GDT + VCPI0_SEL
- int 67h
- cmp ah,0
- jz vcpi_valid2
- mov dx,str_cpu_need_vcpi_info
- jmp exit2dos_with_message
-vcpi_valid2: mov dword [vcpi_entry],ebx
-
-; ===== zero both TSS
- cld
- push ds
- pop es
- xor ax,ax
-
- mov di,TSS1
- mov cx,104/2
- rep stosw
-
- mov di,TSS2
- mov cx,104/2
- rep stosw
-
-; ===== BUILD THE GLOBAL DESCRIPTOR TABLE AND GDTR REGISTER
- mov ax,cs
- mov word [MY_SEGMENT],ax
- mov word [MY_SEGMENT+2],0
- mov bx,ax
- shr bx,12
- shl ax,4 ; BX:AX = 32-bit physical addr of our segment
- mov word [MY_PHYS_BASE],ax
- mov word [MY_PHYS_BASE+2],bx
-
- add ax,GDT
- adc bx,0 ; BX:AX += offset of GDT
-
- mov word [GDTR],MAX_SEL - 1
- mov word [GDTR+2],ax
- mov word [GDTR+4],bx ; GDTR: limit MAX_SEL-1 base=physical mem addr of GDT
-
- mov ax,word [MY_PHYS_BASE]
- mov bx,word [MY_PHYS_BASE+2]
- add ax,IDT
- adc bx,0
-
- mov word [IDTR],2047
- mov word [IDTR+2],ax
- mov word [IDTR+4],bx
-
- cld
-
-; zero IDT
- mov di,IDT
- mov cx,1023
- xor ax,ax
- rep stosw
-
- mov di,GDT
-; NULL selector
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
-; Code selector
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (video)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (32-bit)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; Data selector (32-bit)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; VCPI0
- add di,8
-; VCPI1
- add di,8
-; VCPI2
- add di,8
-; TSS selector (TSS_SEL)
- mov ebx,[MY_PHYS_BASE]
- add ebx,TSS1
- mov ax,104-1
- stosw ; LIMIT
- mov ax,bx
- shr ebx,16
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89
- stosw ; BASE[23:16] access byte=data writeable non-busy TSS type 9
- mov al,0x0F
- mov ah,bh ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; TSS selector (TSS_VM86_SEL)
- mov ebx,[MY_PHYS_BASE]
- add ebx,TSS2
- mov ax,104-1
- stosw ; LIMIT
- mov ax,bx
- shr ebx,16
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89
- stosw ; BASE[23:16] access byte=data writeable non-busy TSS type 9
- mov al,0x0F
- mov ah,bh ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-
-; prepare page directory
- cli
- cld
- push ds
- pop es
- mov edi,[PAGEDIR]
- mov edx,[MY_PHYS_BASE]
-
- mov ebx,[PAGE0]
- lea eax,[edx+ebx+7]
- stosd
-
- xor eax,eax
- mov ecx,1023
- rep stosd
-
-; prepare to switch
- cli
- cld
- push ds
- pop es
- mov di,VCPI_SETUP
- mov edx,[MY_PHYS_BASE]
-
- mov ebx,[PAGEDIR]
- lea eax,[edx+ebx]
- mov dword [di+0],eax ; ESI+0 = CR3 register = (SEG<<4)+PAGE0
-
- lea eax,[edx+GDTR]
- mov dword [di+4],eax ; ESI+4 = GDTR
-
- lea eax,[edx+IDTR]
- mov dword [di+8],eax ; ESI+8 = IDTR
-
- mov word [di+0xC],0 ; ESI+C = LDTR
- mov word [di+0xE],TSS2_SEL ; ESI+E = TR
- mov dword [di+0x10],prot16_entry ; ESI+12 = prot16_entry
- mov dword [di+0x14],CODE_SEL ; ESI+10 = CS
-
-; =============== JUMP INTO PROTECTED MODE USING VCPI
- mov esi,VCPI_SETUP
- add esi,[MY_PHYS_BASE] ; ESI = *LINEAR* address (not DS:ESI!)
- mov ax,0xDE0C
- int 67h
-prot16_entry:
-
- mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- push es
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,vdraw_msg
- xor di,di
-vdraw1: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw1e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw1
-vdraw1e: pop es
-
-; now, jump into 32-bit protected mode
- jmp CODE32_SEL:prot32_entry
-bits 32
-prot32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov esp,0xFFF0
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- mov esi,vdraw32_msg
- mov edi,0xB8000+(80*2)
- sub edi,[MY_PHYS_BASE]
-vdraw321: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw321e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw321
-vdraw321e:
-
-; jump 32-bit to 16-bit
- jmp CODE_SEL:prot32_to_prot
-bits 16
-prot32_to_prot: mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
-
-; =============== JUMP OUT OF PROTECTED MODE USING VCPI
- mov ebx,esp
- xor eax,eax
- mov ax,[MY_SEGMENT]
- push eax ; SS:ESP+0x28 GS
- push eax ; SS:ESP+0x24 FS
- push eax ; SS:ESP+0x20 DS
- push eax ; SS:ESP+0x1C ES
- push eax ; SS:ESP+0x18 SS
- push ebx ; SS:ESP+0x14 ESP
- pushfd ; SS:ESP+0x10 EFLAGS
- push eax ; SS:ESP+0x0C CS
- push dword realmode_entry ; SS:ESP+0x08 EIP
- push dword VCPI0_SEL ; SS:ESP+0x04
- push dword [vcpi_entry] ; SS:ESP+0x00
- mov eax,0xDE0C ; 0xDE0C = switch to v86 mode
- jmp far dword [esp] ; simulate a CALL FAR (SS: override implied)
-
-; ====== PROVE WE MADE IT TO REAL MODE
-realmode_entry: mov si,vdraw2_msg
- mov ax,0xB800
- mov es,ax
- mov di,80*4
-vdraw2: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw2e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw2
-vdraw2e: mov ax,cs
- mov es,ax
-
- sti
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-; 8086 test: EFLAGS will always have bits 12-15 set
-cpu_is_386: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_386_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_386_not
-; it's a 386
- xor ax,ax ; ZF=1
- ret
-cpu_is_386_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; strings
-str_cpu_not_386: db "386 or higher required$"
-str_cpu_need_v86_mode: db "Virtual 8086 mode required (VCPI)$"
-str_cpu_need_int67:db "INT 67h service required$"
-str_cpu_need_vcpi:db "VCPI server required$"
-str_cpu_need_vcpi_info:db "VCPI server failed to return info$"
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-vdraw_msg: db "This message was drawn on screen from 386 16-bit protected mode!",0
-vdraw32_msg: db "This message was drawn on screen from 386 32-bit protected mode!",0
-
-; vars
- section .bss align=8
-vcpi_entry: resd 1
-GDTR: resq 1
-IDTR: resq 1
-MY_PHYS_BASE: resd 1
-MY_SEGMENT: resd 1
-GDT: resb MAX_SEL
-IDT: resb 8*256
-VCPI_SETUP: resb 0x80
-TSS1: resb 108
-TSS2: resb 108
-PAGEDIR: resd 1
-PAGE0: resd 1
-ENDOI: resd 1
-
+++ /dev/null
-/* rdtsc.c
- *
- * Test program: Detect and display the Pentium Time Stamp Counter using RDTSC.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <time.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/cpu/cpurdtsc.h>
-#ifndef TARGET_WINDOWS
-# include <hw/8254/8254.h>
-#endif
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-#if defined(TARGET_OS2) && TARGET_MSDOS == 32
-static ULONG GetMsCount() {
- ULONG ret=0;
- DosQuerySysInfo(QSV_MS_COUNT,QSV_MS_COUNT,&ret,sizeof(ret));
- return ret;
-}
-#endif
-
-int main() {
- rdtsc_t start,measure,ticks_per_sec;
- double t;
- int c;
-
- cpu_probe();
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
- if (cpu_v86_active)
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
-
- if (!(cpu_flags & CPU_FLAG_CPUID)) {
- printf(" - Your CPU doesn't support CPUID, how can it support RDTSC?\n");
- return 1;
- }
-
- if (!(cpu_cpuid_features.a.raw[2] & 0x10)) {
- printf(" - Your CPU does not support RDTSC\n");
- return 1;
- }
-
-#if defined(TARGET_OS2)
-# if TARGET_MSDOS == 32
- /* OS/2 32-bit: We can use DosQuerySysInfo() */
- printf("Measuring CPU speed, using DosQuerySysInfo(), over 3 seconds\n");
- {
- ULONG startTick,tmp;
- start = cpu_rdtsc();
- startTick = GetMsCount();
- do { tmp = GetMsCount();
- } while ((tmp - startTick) < 3000); /* NTS: <- I know this rolls over in 49 days,
- the math though should overflow the 32-bit integer and produce correct results anyway */
- measure = cpu_rdtsc();
-
- /* use the precise tick count to better compute ticks_per_sec */
- ticks_per_sec = ((measure - start) * 1000ULL) / ((rdtsc_t)(tmp - startTick));
- printf("Measurement: %lums = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec);
- printf(" From 0x%llX to 0x%llX\n",start,measure);
- }
-# else
- /* OS/2 16-bit: There is no API (that I know of) to get tick count. Use system clock. */
- printf("Measuring CPU speed, using system clock with 1-second resolution, across 3 seconds\n");
- {
- time_t startTick,tmp;
-
- /* wait for the immediate start of a one-second tick, then record RDTSC and count until 3 seconds */
- startTick = time(NULL);
- do { tmp = time(NULL); } while (tmp == startTick);
- start = cpu_rdtsc(); startTick = tmp;
-
- /* NOW! Count 3 seconds and measure CPU ticks */
- do { tmp = time(NULL);
- } while ((tmp - startTick) < 3);
- measure = cpu_rdtsc();
-
- /* use the precise tick count to better compute ticks_per_sec */
- ticks_per_sec = ((measure - start) * 1ULL) / ((rdtsc_t)(tmp - startTick));
- printf("Measurement: %lu seconds = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec);
- printf(" From 0x%llX to 0x%llX\n",start,measure);
- }
-# endif
-#elif defined(TARGET_WINDOWS)
-# if TARGET_MSDOS == 16
- /* Windows 2.x/3.0/3.1: Use GetTickCount() or
- * Windows 3.1: Use TOOLHELP.DLL TimerCount() which is more accurate (really?) */
- if (ToolHelpInit()) {
- TIMERINFO ti;
-
- ti.dwSize = sizeof(ti);
- printf("Measuring CPU speed, using TOOLHELP TimerCount() over 1 second\n");
- {
- DWORD startTick,tmp;
- start = cpu_rdtsc();
- if (!__TimerCount(&ti)) {
- printf("TimerCount() failed\n");
- return 1;
- }
- startTick = ti.dwmsSinceStart;
- do {
-# if defined(WIN_STDOUT_CONSOLE)
- _win_pump(); /* <- you MUST call this. The message pump must run, or else the timer won't advance and this loop will run forever.
- The fact that GetTickCount() depends on a working message pump under Windows 3.1 seems to be a rather serious
- oversight on Microsoft's part. Note that the problem described here does not apply to Windows 9x/ME. Also note
- the Toolhelp function TimerCount() relies on GetTickCount() as a basic for time (though Toolhelp uses VxD services
- or direct I/O port hackery to refine the timer count) */
-# endif
-
- if (!__TimerCount(&ti)) {
- printf("TimerCount() failed\n");
- return 1;
- }
-
- tmp = ti.dwmsSinceStart;
- } while ((tmp - startTick) < 1000); /* NTS: <- I know this rolls over in 49 days,
- the math though should overflow the 32-bit integer and produce correct results anyway */
- measure = cpu_rdtsc();
-
- /* use the precise tick count to better compute ticks_per_sec */
- ticks_per_sec = ((measure - start) * 1000ULL) / ((rdtsc_t)(tmp - startTick));
- printf("Measurement: %lums = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec);
- printf(" From 0x%llX to 0x%llX\n",start,measure);
- }
- }
- else {
-# else
- {
-# endif
- printf("Measuring CPU speed, using GetTickCount() over 3 second\n");
- {
- DWORD startTick,tmp;
- start = cpu_rdtsc();
- startTick = GetTickCount();
- /* NTS: Dunno yet about Windows 3.1, but Windows 95 seems to require we Yield(). If we don't, the GetTickCount() return
- * value never updates and we're forever stuck in a loop. */
- do {
-# if defined(WIN_STDOUT_CONSOLE)
- _win_pump(); /* <- you MUST call this. The message pump must run, or else the timer won't advance and this loop will run forever.
- The fact that GetTickCount() depends on a working message pump under Windows 3.1 seems to be a rather serious
- oversight on Microsoft's part. Note that the problem described here does not apply to Windows 9x/ME */
-# endif
- tmp = GetTickCount();
- } while ((tmp - startTick) < 3000); /* NTS: <- I know this rolls over in 49 days,
- the math though should overflow the 32-bit integer and produce correct results anyway */
- measure = cpu_rdtsc();
-
- /* use the precise tick count to better compute ticks_per_sec */
- ticks_per_sec = ((measure - start) * 1000ULL) / ((rdtsc_t)(tmp - startTick));
- printf("Measurement: %lums = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec);
- printf(" From 0x%llX to 0x%llX\n",start,measure);
- }
- }
-#else
- /* MS-DOS: Init the 8254 timer library for precise measurement */
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
-
- printf("Measuring CPU speed (relative to 8254 timer)\n");
-
- _cli();
- start = cpu_rdtsc();
- t8254_wait(t8254_us2ticks(1000000));
- measure = cpu_rdtsc();
- _sti();
-
- printf("Measurement: 1 sec = %lld ticks\n",(int64_t)(measure - start));
- printf(" From 0x%llX to 0x%llX\n",start,measure);
- ticks_per_sec = (measure - start);
-#endif
-
- if ((int64_t)ticks_per_sec < 0) {
- printf("Cannot determine CPU cycle count\n");
- ticks_per_sec = 100000ULL;
- }
-
- while (1) {
- measure = cpu_rdtsc();
- t = (double)((int64_t)(measure - start));
- t /= ticks_per_sec;
-
- printf("\x0D" "0x%llX = %.3f ",measure,t);
-#if !defined(WINFCON_STOCK_WIN_MAIN)
- fflush(stdout); /* FIXME: The fake console code should intercept fflush() too */
-#endif
-
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27)
- break;
- else if (c == 'r' || c == 'R') {
- if (c == 'r' || (cpu_flags & CPU_FLAG_DONT_WRITE_RDTSC)) {
- printf("\nI am not able to write the TSC register within this environment\nYou can force me by typing SHIFT+R, don't blame me when I crash...\n");
- }
- else {
- printf("\nUsing MSR to reset TSC to 0\n");
- /* demonstrating WRMSR to write the TSC (yes, you can!) */
- cpu_rdtsc_write(start = 0ULL);
- printf("Result: 0x%llX\n",cpu_rdtsc());
- }
- }
- else if (c == 's') {
- if (c == 's' && (cpu_flags & CPU_FLAG_DONT_WRITE_RDTSC)) {
- printf("\nI am not able to write the TSC register within this environment\nYou can force me by typing SHIFT+S, don't blame me when I crash...\n");
- }
- else {
- printf("\nUsing MSR to reset TSC to 0x123456789ABCDEF\n");
- /* demonstrating WRMSR to write the TSC (yes, you can!) */
- cpu_rdtsc_write(start = 0x123456789ABCDEFULL);
- printf("Result: 0x%llX\n",cpu_rdtsc());
- }
- }
- }
- }
- printf("\n");
-
- return 0;
-}
-
+++ /dev/null
-/* reset.c
- *
- * Test program: Various methods of resetting the system
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-/* NOTES: Most motherboards do the reset recovery thing quite well, and despite
- the age of the 286-style reset vector, most modern motherboards apparently
- support it. I have a Dell Optiplex Pentium III based system that emulates
- it quite well.
-
- Pentium III based Dell Optiplex:
- Supports all reset methods. 286 reset vector recovery works, though
- apparently it's not a full on reset because it doesn't seem to re-
- enable the Processor Serial Number. The piix:h reset option does not
- work in conjunction with the 286 reset vector, but it DOES reset the
- machine. The 32-bit build doesn't seem to be able to cause a soft
- reset via piix:s, apparently that only works from 16-bit real mode (?)
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <setjmp.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/8042/8042.h>
-#include <hw/8254/8254.h>
-
-enum {
- RESET_ANY=0, /* try any reset method */
- RESET_92h, /* reset via port 0x92 */
- RESET_KEYBOARD, /* reset via keyboard controller */
- RESET_PIIX_SOFT, /* reset via port 0xCF9 (Intel PIIX soft-reset) */
- RESET_PIIX_HARD, /* reset via port 0xCF9 (Intel PIIX hard-reset) */
- RESET_8086_ENTRY, /* soft "reset" real-mode jump to 0xFFFF:0x0000 */
- RESET_TRIPLE_FAULT /* reset by intentionally causing a triple fault */
-};
-
-enum {
- RECOV_IBM_286_BIOS=0
-};
-
-static void help() {
- fprintf(stderr,"reset [options]\n");
- fprintf(stderr,"Demonstrates causing a CPU reset by various methods\n");
- fprintf(stderr,"\n");
- fprintf(stderr," /92 Use port 92h (recommended)\n");
- fprintf(stderr," /k Use keyboard controller\n");
- fprintf(stderr," /piix:s Intel PIIX port CF9h (soft)\n");
- fprintf(stderr," /piix:h Intel PIIX port CF9h (hard)\n");
- fprintf(stderr," /8086 8086-style jump to BIOS entry point\n");
- fprintf(stderr," /tf Cause CPU triple fault\n");
- fprintf(stderr," /any Try all methods listed above\n");
- fprintf(stderr,"\n");
- fprintf(stderr,"If this program is successful, the next screen you will see\n");
- fprintf(stderr,"will be your BIOS counting RAM and whatever else it does on startup.\n");
- fprintf(stderr,"\n");
- fprintf(stderr,"Optionally, you can also request that this program try one of several\n");
- fprintf(stderr,"methods of resuming control of the CPU after reset, instead of actually\n");
- fprintf(stderr,"causing the whole system to reboot.\n");
- fprintf(stderr," /rc:286 IBM 286 BIOS reset vector recovery\n");
- fprintf(stderr,"\n");
- fprintf(stderr,"Override switches---USE AT YOUR OWN RISK:\n");
- fprintf(stderr," /rc:v86 Force recovery testing even if virtual 8086 mode is active\n");
-}
-
-void reset_92h() {
- unsigned char c;
-
- /* this is pretty easy: just set bit 0 to 1.
- it's said to have originated on IBM PS/2 hardware.
- virtually every emulator and motherboard since
- 1993 recognizes this in hardware as well, and you
- will also find the infamous A20 gate can be controlled
- from here as well. */
- /* But then again, I do have one Pentium motherboard (1995-ish)
- that doesn't have a port 0x92 and must be reset through the
- keyboard controller or the PIIX reset register. */
- /* NOTE: Some motherboards have hardware bugs where sometimes
- it can be already set, and setting has no effect, we
- must CLEAR THEN SET. Especially Dell brand computers... */
- c = inp(0x92);
- outp(0x92,c & 0xFE);
- c = inp(0x92);
- outp(0x92,c | 1);
-}
-
-void reset_keyboard() {
- unsigned char op=0x32;/* reasonable assumption */
- int i;
-
- k8042_drain_buffer();
-
- /* read the output byte from the keyboard controller */
- k8042_write_command(0xAD);
- k8042_drain_buffer();
-
- if (k8042_write_command(0xD0)) {
- i = k8042_read_output_wait();
- if (i >= 0) op = (unsigned char)i | 3;
- }
-
- k8042_write_command(0xAE);
- k8042_drain_buffer();
-
- /* now write it back with bit 0 clear to reset the CPU */
- for (i=0;i < 20;i++) {
- k8042_write_command(0xD1); /* write output port */
- k8042_write_data(op & 0xFE); /* reset CPU */
- k8042_drain_buffer();
- }
-
- /* are we still here? try pulsing commands */
- for (i=0;i < 20;i++) {
- k8042_write_command(0xFE);
- k8042_drain_buffer();
- }
-}
-
-void reset_piix_soft() {
- /* Intel PIIX/PIIX3 motherboards have their own reset register
- at 0xCF9 (smack-dab in the middle of the PCI configuration
- registers) which can be used to cause a soft or hard reset */
- outp(0xCF9,0);
- outp(0xCF9,4); /* soft reset, BIOS controlled */
-}
-
-void reset_piix_hard() {
- /* Intel PIIX/PIIX3 motherboards have their own reset register
- at 0xCF9 (smack-dab in the middle of the PCI configuration
- registers) which can be used to cause a soft or hard reset */
- outp(0xCF9,0);
- outp(0xCF9,6); /* hard reset */
-}
-
-void reset_triple_fault() {
- /* TODO */
-}
-
-void reset_8086_entry();
-
-jmp_buf recjmp;
-
-#if TARGET_MSDOS == 16
-void bios_reset_cb_e();
-void bios_reset_cb() {
- *((unsigned short far*)MK_FP(0xB800,0x0002)) = 0x1F31;
- longjmp(recjmp,1);
-}
-#endif
-
-int main(int argc,char **argv) {
-#if TARGET_MSDOS == 16
- unsigned char pic_a_mask,pic_b_mask;
-#endif
- int recovery = -1;
- int rec_v86 = 0;
- int how = -1;
- int keyb = 0;
- int i;
-
- if (argc < 2) {
- help();
- return 1;
- }
-
- for (i=1;i < argc;) {
- const char *a = argv[i++];
-
- if (*a == '/' || *a == '-') {
- do { a++; } while (*a == '/' || *a == '-');
-
- if (!strcmp(a,"92")) {
- how = RESET_92h;
- }
- else if (!strcmp(a,"k")) {
- how = RESET_KEYBOARD;
- }
- else if (!strcmp(a,"piix:s")) {
- how = RESET_PIIX_SOFT;
- }
- else if (!strcmp(a,"piix:h")) {
- how = RESET_PIIX_HARD;
- }
- else if (!strcmp(a,"8086")) {
- how = RESET_8086_ENTRY;
- }
- else if (!strcmp(a,"tf")) {
- how = RESET_TRIPLE_FAULT;
- }
- else if (!strcmp(a,"any")) {
- how = RESET_ANY;
- }
- else if (!strcmp(a,"rc:286")) {
- recovery = RECOV_IBM_286_BIOS;
- }
- else if (!strcmp(a,"rc:v86")) {
- rec_v86 = 1;
- }
- else {
- help();
- return 1;
- }
- }
- else {
- help();
- return 1;
- }
- }
-
- if (how < 0) {
- help();
- return 1;
- }
-
-#if TARGET_MSDOS == 32
- if (how == RESET_8086_ENTRY) {
- printf("8086 entry point reset not supported in 32-bit builds\n");
- return 1;
- }
- if (recovery >= 0) {
- printf("Recovery testing not supported in 32-bit builds\n");
- return 1;
- }
-#endif
-
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!(keyb=k8042_probe()))
- printf("Warning: unable to probe 8042 controller. Is it there?\n");
-
- cpu_probe();
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
- if (cpu_v86_active)
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
- if (cpu_flags & CPU_FLAG_FPU)
- printf(" - With FPU\n");
-
-#if TARGET_MSDOS == 16
- /* apparently this trick will work when EMM386.EXE is active,
- and it seems to be a very effective way for 16-bit DOS
- programs to escape it's virtual 8086 mode, BUT, it also
- seems to cause subtle memory corruption issues that
- cause erratic behavior and eventually a crash. So it's
- best not to allow it.
-
- I have no idea what this would cause if run under any other
- virtual 8086 like environment, but I'm pretty sure this would
- cause a nasty crash if we did this from within a Windows
- DOS Box!
-
- TODO: See if it is possible to eventually find out what the
- minor issues are, and whether this code can do some
- extra wizardry to compensate. */
- if (cpu_v86_active && !rec_v86 && recovery >= RECOV_IBM_286_BIOS) {
- printf("ERROR: Recovery mode testing is NOT a good idea when virtual 8086\n");
- printf(" mode is active, it causes too many subtle and bizarre erratic\n");
- printf(" problems with the surrounding DOS environment.\n");
- printf("\n");
- printf(" To use this mode, disable v8086 mode and try again. If EMM386.EXE\n");
- printf(" is resident, you can disable v8086 mode by typing 'EMM386 OFF'\n");
- return 1;
- }
-
- if (recovery == RECOV_IBM_286_BIOS) {
- unsigned short segs=0,segp=0,segds=0;
-
- __asm {
- mov ax,ss
- mov segs,ax
- mov ax,sp
- mov segp,ax
- mov ax,ds
- mov segds,ax
- }
-
- pic_a_mask = inp(0x21);
- pic_b_mask = inp(0xA1);
-
- *((unsigned short far*)MK_FP(0x40,0x67)) = FP_OFF(bios_reset_cb_e);
- *((unsigned short far*)MK_FP(0x40,0x69)) = FP_SEG(bios_reset_cb_e);
- /* store DS somewhere where our reset routine can find it */
- *((unsigned short far*)MK_FP(0x50,0x04)) = FP_OFF(bios_reset_cb);
- *((unsigned short far*)MK_FP(0x50,0x06)) = FP_SEG(bios_reset_cb);
- *((unsigned short far*)MK_FP(0x50,0x08)) = segp;
- *((unsigned short far*)MK_FP(0x50,0x0A)) = segs;
- *((unsigned short far*)MK_FP(0x50,0x0C)) = segds;
- /* now write the CMOS to tell the BIOS what we're doing */
- outp(0x70,0x0F);
- outp(0x71,0x0A);
- }
-#endif
-
- _cli();
- if (setjmp(recjmp)) {
-/* --> CPU execution will resume here longjmp() style if reset vector called */
- printf("Recovery successful\n");
- }
- else {
- if (how == RESET_ANY) {
- reset_92h();
- t8254_wait(t8254_us2ticks(250000));
- reset_keyboard();
- t8254_wait(t8254_us2ticks(250000));
- reset_piix_soft();
- t8254_wait(t8254_us2ticks(250000));
- reset_piix_hard();
- t8254_wait(t8254_us2ticks(250000));
- reset_triple_fault();
- t8254_wait(t8254_us2ticks(250000));
-#if TARGET_MSDOS == 16
- reset_8086_entry(); /* <- unless on ancient hardware, this is least likely to work */
-#endif
- }
- else if (how == RESET_92h) {
- reset_92h();
- }
- else if (how == RESET_KEYBOARD) {
- reset_keyboard();
- }
- else if (how == RESET_PIIX_SOFT) {
- reset_piix_soft();
- }
- else if (how == RESET_PIIX_HARD) {
- reset_piix_hard();
- }
- else if (how == RESET_TRIPLE_FAULT) {
- reset_triple_fault();
- }
-#if TARGET_MSDOS == 16
- else if (how == RESET_8086_ENTRY) {
- reset_8086_entry();
- }
-#endif
-
- /* We need a small pause here, some ancient 386 motherboards
- I own actually have quite a delay on them between reset
- and actually causing the CPU to reset, enough that on a
- very old OS I wrote, I had to stick a HLT instruction to
- prevent the CPU from running wild through my kernel during
- the 100-250ms it took for reset to actually happen. */
- for (i=0;i < 3;i++)
- t8254_wait(t8254_us2ticks(1000000));
-
- printf("* IF YOU CAN SEE THIS MESSAGE, RESET FAILED *\n");
- }
-
-#if TARGET_MSDOS == 16
- if (recovery == RECOV_IBM_286_BIOS) {
- /* clear the CMOS flag */
- outp(0x70,0x0F);
- outp(0x71,0x00);
- /* restore the PIC mask */
- outp(0x21,pic_a_mask);
- outp(0xA1,pic_b_mask);
- /* depending on the BIOS, we may be responsible for reenabling the keyboard
- and turning the clock lines back on */
- if (how == RESET_KEYBOARD) {
- /* read the output byte from the keyboard controller */
- k8042_write_command(0xAD);
- k8042_drain_buffer();
-
- /* now write it back with bit 0 clear to reset the CPU */
- for (i=0;i < 20;i++) {
- k8042_write_command(0xD1); /* write output port */
- k8042_write_data(0x33); /* keep A20 on, CPU on, disable inhibition */
- k8042_drain_buffer();
- }
-
- k8042_write_command(0xAE);
- k8042_drain_buffer();
- }
- }
-#endif
-
- return 0;
-}
-
+++ /dev/null
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%if TARGET_MSDOS == 16
-global reset_8086_entry_
-reset_8086_entry_:
- cli
- jmp 0xFFFF:0x0000
-%endif
-
-%if TARGET_MSDOS == 16
-global bios_reset_cb_e_
-bios_reset_cb_e_:
- cli
-; DEBUG: Prove our routine is executing properly by drawing on VGA RAM
- mov ax,0xB800
- mov ds,ax
- mov word [0],0x1E30
-; now load state from 0x50:0x04 where the setup put it
- mov ax,0x50
- mov ds,ax
- mov ax,[0x08]
- mov sp,ax
- mov ax,[0x0A]
- mov ss,ax
- mov bx,[0x0C]
- push word [ds:0x06]
- push word [ds:0x04]
- mov ds,bx
- mov es,bx
- retf
-%endif
-
+++ /dev/null
-/* sse.c
- *
- * Test program: Detecting and using the SSE extensions
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/cpusse.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-static unsigned char temp[2048];
-static unsigned char *tempa;
-
-int main() {
- /* all we need is a 16-byte aligned pointer */
- /* NOTE: This alignment calculation works properly in both
- 16-bit real mode and 32-bit flat mode */
- tempa = temp; tempa += (16UL - (((unsigned long)tempa) & 15UL)) & 15UL;
-
- cpu_probe();
- probe_dos();
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
- if (cpu_v86_active) {
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
- }
-
- if (!cpu_check_sse_is_usable() && cpu_sse_usable_can_turn_on) {
- printf("SSE not available yet, but I can switch it on. Doing so now...\n");
- printf("Reason: %s\n",cpu_sse_unusable_reason);
- printf("Detection method: %s\n",cpu_sse_usable_detection_method);
-
- if (!cpu_sse_enable()) {
- printf("Nope, cannot enable.\n");
- return 1;
- }
- }
-
- if (!cpu_check_sse_is_usable()) {
- printf("SSE not available.\n");
- printf("Reason: %s\n",cpu_sse_unusable_reason);
- printf("Detection method: %s\n",cpu_sse_usable_detection_method);
- printf("can turn off: %d\n",cpu_sse_usable_can_turn_off);
- printf("can turn on: %d\n",cpu_sse_usable_can_turn_on);
- return 1;
- }
-
- printf("SSE available, detection method: %s\n",cpu_sse_usable_detection_method);
- printf("can turn off: %d\n",cpu_sse_usable_can_turn_off);
- printf("can turn on: %d\n",cpu_sse_usable_can_turn_on);
-
- /* NOTE: Contrary to first impressions, you can enable
- and execute SSE instructions from 16-bit real
- mode. Just be careful you don't modify the CR4
- register or use 32-bit addressing when EMM386.EXE
- is resident and active. */
-
- *((uint64_t*)(tempa+0)) = 0x0011223344556677ULL;
- *((uint64_t*)(tempa+8)) = 0x8899AABBCCDDEEFFULL;
- *((uint64_t*)(tempa+16)) = 0x1111111111111111ULL;
- *((uint64_t*)(tempa+24)) = 0x1111111111111111ULL;
-
-#if TARGET_MSDOS == 32
- __asm {
- .686p
- .xmm
- mov esi,tempa
- movaps xmm0,[esi]
- andps xmm0,[esi+16]
- movaps [esi+32],xmm0
- }
-#elif defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .686p
- .xmm
- push es
- les si,tempa
- movaps xmm0,es:[si]
- andps xmm0,es:[si+16]
- movaps es:[si+32],xmm0
- pop es
- }
-#else
- __asm {
- .686p
- .xmm
- mov si,tempa
- movaps xmm0,[si]
- andps xmm0,[si+16]
- movaps [si+32],xmm0
- }
-#endif
-
- printf("ANDPS: %016llX%016llX & %016llX%016llX =\n %016llX%016llX\n",
- *((uint64_t*)(tempa+8)),
- *((uint64_t*)(tempa+0)),
- *((uint64_t*)(tempa+24)),
- *((uint64_t*)(tempa+16)),
- *((uint64_t*)(tempa+40)),
- *((uint64_t*)(tempa+32)));
-
-/* second test: the first revision of SSE has heavy emphasis on floating
- point, so let's do some test floating point math */
- ((float*)(tempa))[0] = 2.0;
- ((float*)(tempa))[1] = 3.0;
- ((float*)(tempa))[2] = 5.0;
- ((float*)(tempa))[3] = 7.0;
-
- ((float*)(tempa))[4] = 3.0;
- ((float*)(tempa))[5] = 2.0;
- ((float*)(tempa))[6] = 1.5;
- ((float*)(tempa))[7] = 1.0;
-
-#if TARGET_MSDOS == 32
- __asm {
- .686p
- .xmm
- mov esi,tempa
- movaps xmm0,[esi]
- mulps xmm0,[esi+16]
- movaps [esi+32],xmm0
- }
-#elif defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .686p
- .xmm
- push es
- les si,tempa
- movaps xmm0,es:[si]
- mulps xmm0,es:[si+16]
- movaps es:[si+32],xmm0
- pop es
- }
-#else
- __asm {
- .686p
- .xmm
- mov si,tempa
- movaps xmm0,[si]
- mulps xmm0,[si+16]
- movaps [si+32],xmm0
- }
-#endif
-
- printf("MULPS: %.1f * %.1f, %.1f * %.1f, %.1f * %.1f, %.1f * %.1f\n",
- ((float*)(tempa))[0],((float*)(tempa))[4],
- ((float*)(tempa))[1],((float*)(tempa))[5],
- ((float*)(tempa))[2],((float*)(tempa))[6],
- ((float*)(tempa))[3],((float*)(tempa))[7]);
- printf(" = %.1f %.1f %.1f %.1f\n",
- ((float*)(tempa))[ 8],((float*)(tempa))[ 9],
- ((float*)(tempa))[10],((float*)(tempa))[11]);
-
- return 0;
-}
-
+++ /dev/null
-/* sseoff.c
- *
- * Test program: Detecting SSE extensions, and switching them off
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/cpusse.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- cpu_probe();
- probe_dos();
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
- if (cpu_v86_active) {
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
- }
-
- if (!cpu_check_sse_is_usable()) {
- printf("SSE not available to turn off.\n");
- printf("Reason: %s\n",cpu_sse_unusable_reason);
- printf("Detection method: %s\n",cpu_sse_usable_detection_method);
- printf("can turn off: %d\n",cpu_sse_usable_can_turn_off);
- printf("can turn on: %d\n",cpu_sse_usable_can_turn_on);
- return 1;
- }
-
- printf("SSE available, detection method: %s\n",cpu_sse_usable_detection_method);
- printf("can turn off: %d\n",cpu_sse_usable_can_turn_off);
- printf("can turn on: %d\n",cpu_sse_usable_can_turn_on);
-
- if (!cpu_sse_usable_can_turn_off) {
- printf("I can't turn SSE off, giving up\n");
- return 1;
- }
-
- if (!cpu_sse_disable()) {
- printf("Failed to turn off SSE\n");
- return 1;
- }
-
- printf("SSE is now disabled.\n");
- return 0;
-}
-
+++ /dev/null
-/* test.c
- *
- * Test program: Detecting and displaying CPU information
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/cpu/cpup3sn.h>
-#include <hw/cpu/cpuidext.h>
-#include <hw/dos/doswin.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-static char cpu_cpuid_ext_cache_tbl_to_str__cache_tbl_info[32];
-const char *cpu_cpuid_ext_cache_tbl_to_str(unsigned char c) {
- if (c == 1) {
- return "Direct";
- }
- else if (c == 0xFF) {
- return "Full assoc";
- }
- else if (c > 1) {
- sprintf(cpu_cpuid_ext_cache_tbl_to_str__cache_tbl_info,"%u-way assoc",c);
- return cpu_cpuid_ext_cache_tbl_to_str__cache_tbl_info;
- }
- return "Reserved";
-}
-
-const char *cpu_cpuid_ext_cache_tbl_l2_to_str(unsigned char c) {
- switch (c) {
- case 0x00: return "Disabled";
- case 0x01: return "Direct";
- case 0x02: return "2-way assoc";
- case 0x04: return "4-way assoc";
- case 0x06: return "8-way assoc";
- case 0x08: return "16-way assoc";
- case 0x0A: return "32-way assoc";
- case 0x0B: return "48-way assoc";
- case 0x0C: return "64-way assoc";
- case 0x0D: return "96-way assoc";
- case 0x0E: return "128-way assoc";
- case 0x0F: return "Fully assoc";
- };
-
- return "??";
-}
-
-static void pause_if_tty() {
- unsigned char c;
- if (isatty(1)) { do { read(0,&c,1); } while (c != 13); }
-}
-
-int main() {
- unsigned char c;
- unsigned short w;
-
- cpu_probe();
- printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level));
-
- if (cpu_v86_active)
- printf(" - Your CPU is currently running me in virtual 8086 mode\n");
- if (cpu_flags & CPU_FLAG_PROTECTED_MODE)
- printf(" - Your CPU is currently running in protected mode\n");
- if (cpu_flags & CPU_FLAG_PROTECTED_MODE_32)
- printf(" - Your CPU is currently running in 32-bit protected mode\n");
-
- if (cpu_flags & CPU_FLAG_CPUID) {
- printf(" - With CPUID (Vendor='%s' MaxID=0x%lX)\n",cpu_cpuid_vendor,cpu_cpuid_max);
- printf(" - Features A=0x%08lX,B=0x%08lX,D=0x%08lX,C=0x%08lX\n",
- cpu_cpuid_features.a.raw[0],
- cpu_cpuid_features.a.raw[1],
- cpu_cpuid_features.a.raw[2],
- cpu_cpuid_features.a.raw[3]);
-
- printf(" - Step %lu Model %lu Family %lu ProcType %lu ExtModel %lu ExtFamily %lu\n",
- cpu_cpuid_features.a.raw[0]&0xFUL,
- (cpu_cpuid_features.a.raw[0]>>4UL)&0xFUL,
- (cpu_cpuid_features.a.raw[0]>>8UL)&0xFUL,
- (cpu_cpuid_features.a.raw[0]>>12UL)&0x3UL,
- (cpu_cpuid_features.a.raw[0]>>16UL)&0xFUL,
- (cpu_cpuid_features.a.raw[0]>>20UL)&0xFFUL);
-
- printf(" - ");
-#define X(b,t) if (cpu_cpuid_features.a.raw[2] & (1UL << ((unsigned long)(b)))) printf("%s ",t);
- X(0,"FPU");
- X(1,"VME");
- X(2,"DE");
- X(3,"PSE");
- X(4,"TSC");
- X(5,"MSR");
- X(6,"PAE");
- X(7,"MCE");
- X(8,"CX8");
- X(9,"APIC");
- X(11,"SEP");
- X(12,"MTRR");
- X(13,"PGE");
- X(14,"MCA");
- X(15,"CMOV");
- X(16,"PAT");
- X(17,"PSE36");
- X(18,"PSN");
- X(19,"CLFLUSH");
- X(21,"DTS");
- X(22,"ACPI");
- X(23,"MMX");
- X(24,"FXSR");
- X(25,"SSE");
- X(26,"SSE2");
- X(27,"SS");
- X(28,"HT");
- X(29,"TM");
- X(30,"IA64");
- X(31,"PBE");
-#undef X
-#define X(b,t) if (cpu_cpuid_features.a.raw[3] & (1UL << ((unsigned long)(b)))) printf("%s ",t);
- X(0,"PNI");
- X(1,"PCLMULQDQ");
- X(2,"DTES64");
- X(3,"MONITOR");
- X(4,"DS_CPL");
- X(5,"VMX");
- X(6,"SMX");
- X(7,"EST");
- X(8,"TM2");
- X(9,"SSSE3");
- X(10,"CID");
- X(12,"FMA");
- X(13,"CX16");
- X(14,"XTPR");
- X(15,"PDCM");
- X(17,"PCID");
- X(18,"DCA");
- X(19,"SSE4_1");
- X(20,"SSE4_2");
- X(21,"X2APIC");
- X(22,"MOVBE");
- X(23,"POPCNT");
- X(24,"TSCDEADLINE");
- X(25,"AES");
- X(26,"XSAVE");
- X(27,"OXSAVE");
- X(28,"AVX");
- X(29,"F16C");
- X(30,"RDRND");
- X(31,"HYPERVISOR");
-#undef X
- printf("\n");
- }
- if (cpu_flags & CPU_FLAG_FPU) printf(" - With FPU\n");
-
- if (cpu_cpuid_features.a.raw[2] & (1UL << 18UL)) {
- cpu_ask_serial();
- printf(" - Processor serial 0x%08lX,0x%08lX,0x%08lX,0x%08lX\n",
- cpu_serial.raw[0],cpu_serial.raw[1],
- cpu_serial.raw[2],cpu_serial.raw[3]);
- }
-
- if (cpu_extended_cpuid_probe()) {
- assert(cpu_cpuid_ext_info != NULL);
- printf(" - With extended CPUID (Brand='%s' MaxID=0x%lX)\n",cpu_cpuid_ext_info->brand,cpu_cpuid_ext_info->cpuid_max);
- printf(" - Extended Features A=0x%08lX,B=0x%08lX,C=0x%08lX,D=0x%08lX\n",
- cpu_cpuid_ext_info->features.a.raw[0],
- cpu_cpuid_ext_info->features.a.raw[1],
- cpu_cpuid_ext_info->features.a.raw[2],
- cpu_cpuid_ext_info->features.a.raw[3]);
-#define X(b,t) if (cpu_cpuid_ext_info->features.a.raw[2] & (1UL << ((unsigned long)(b)))) printf("%s ",t);
- /* TODO: What about Intel processors? */
- X(0,"LAHF/SAHF");
- X(1,"CmpLegacy");
- X(2,"SVM");
- X(3,"ExtAPICSpc");
- X(4,"AltMovCr8"); /* apparently "lock mov cr0" -> "mov cr8" ? Ick... */
- X(5,"ABM");
- X(6,"SSE4A");
- X(7,"MisalignSSE");
- X(8,"PREFETCH");
- X(9,"OSVW");
- X(10,"IBS");
- X(11,"XOP");
- X(12,"SKINIT");
- X(13,"WDT");
- X(15,"LWP");
- X(16,"FMA4");
- X(19,"NodeID");
- X(21,"TBM");
- X(22,"TopoExt");
-#undef X
-#define X(b,t) if (cpu_cpuid_ext_info->features.a.raw[3] & (1UL << ((unsigned long)(b)))) printf("%s ",t);
- /* TODO: What about Intel processors? */
- X(0,"FPU");
- X(1,"VME");
- X(2,"DE");
- X(3,"PSE");
- X(4,"TSC");
- X(5,"MSR");
- X(6,"PAE");
- X(7,"MCE");
- X(8,"CMPXCHG8B");
- X(9,"APIC");
- X(11,"SYSCALL");
- X(12,"MTRR");
- X(13,"PGE");
- X(14,"MCA");
- X(15,"CMOV");
- X(16,"PAT");
- X(17,"PSE36");
- X(20,"NX");
- X(22,"MMXExt");
- X(23,"MMX");
- X(24,"FXSR");
- X(25,"FFXSR");
- X(26,"PAGE1GB");
- X(27,"RDTSCP");
- X(29,"LONGMODE");
- X(30,"3DNOWEXT");
- X(31,"3DNOW");
-#undef X
- printf("\n");
-
- if (cpu_cpuid_ext_info_has_cache_tlb_l1) {
- pause_if_tty();
-
- printf(" - L1 Cache & TLB IDs\n");
-
- /*-----------------------------------------------------*/
- printf(" 2MB & 4MB:\n");
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[0] >> 24UL);
- printf(" cache data: %s ",cpu_cpuid_ext_cache_tbl_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[0] >> 16UL);
- printf("(%u entries)\n",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[0] >> 8UL);
- printf(" cache code: %s ",cpu_cpuid_ext_cache_tbl_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[0] >> 0UL);
- printf("(%u entries)\n",c);
-
- /*-----------------------------------------------------*/
- printf(" 4KB:\n");
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[1] >> 24UL);
- printf(" cache data: %s ",cpu_cpuid_ext_cache_tbl_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[1] >> 16UL);
- printf("(%u entries)\n",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[1] >> 8UL);
- printf(" cache code: %s ",cpu_cpuid_ext_cache_tbl_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[1] >> 0UL);
- printf("(%u entries)\n",c);
-
- /*-----------------------------------------------------*/
- printf(" Data cache:\n");
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[2] >> 24UL);
- printf(" %uKB",(unsigned int)c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[2] >> 16UL);
- printf(" %s",cpu_cpuid_ext_cache_tbl_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[2] >> 8UL);
- printf(" %u lines/tag",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[2] >> 0UL);
- printf(" %u bytes/cache line\n",c);
-
- /*-----------------------------------------------------*/
- printf(" Code cache:\n");
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[3] >> 24UL);
- printf(" %uKB",(unsigned int)c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[3] >> 16UL);
- printf(" %s",cpu_cpuid_ext_cache_tbl_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[3] >> 8UL);
- printf(" %u lines/tag",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb.a.raw[3] >> 0UL);
- printf(" %u bytes/cache line\n",c);
- }
-
- if (cpu_cpuid_ext_info_has_cache_tlb_l2) {
- printf(" - L2 Cache & TLB IDs\n");
-
- /*-----------------------------------------------------*/
- printf(" 2MB & 4MB:\n");
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[0] >> 28UL) & 0xF;
- printf(" cache data: %s ",cpu_cpuid_ext_cache_tbl_l2_to_str(c));
-
- w = (unsigned short)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[0] >> 16UL) & 0xFFFU;
- printf("(%u entries)\n",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[0] >> 12UL) & 0xF;
- printf(" cache code: %s ",cpu_cpuid_ext_cache_tbl_l2_to_str(c));
-
- w = (unsigned short)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[0] >> 0UL) & 0xFFFU;
- printf("(%u entries)\n",c);
-
- /*-----------------------------------------------------*/
- printf(" 4KB:\n");
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[1] >> 28UL) & 0xF;
- printf(" cache data: %s ",cpu_cpuid_ext_cache_tbl_l2_to_str(c));
-
- w = (unsigned short)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[1] >> 16UL) & 0xFFFU;
- printf("(%u entries)\n",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[1] >> 12UL) & 0xF;
- printf(" cache code: %s ",cpu_cpuid_ext_cache_tbl_l2_to_str(c));
-
- w = (unsigned short)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[1] >> 0UL) & 0xFFFU;
- printf("(%u entries)\n",c);
-
- /*-----------------------------------------------------*/
- printf(" Cache:\n");
-
- w = (unsigned short)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[2] >> 16UL);
- printf(" %luKB",(unsigned long)w);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[2] >> 12UL) & 0xF;
- printf(" %s",cpu_cpuid_ext_cache_tbl_l2_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[2] >> 8UL) & 0xF;
- printf(" %u lines/tag",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[2] >> 0UL);
- printf(" %u bytes/cache line\n",c);
- }
-
- if (cpu_cpuid_ext_info_has_cache_tlb_l2) {
- printf(" - L3 Cache & TLB IDs\n");
-
- /*-----------------------------------------------------*/
- printf(" Cache:\n");
-
- w = (unsigned short)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[3] >> 18UL);
- printf(" %luKB",(unsigned long)w * 512UL); /* <- REALLY?!? */
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[3] >> 12UL) & 0xF;
- printf(" %s",cpu_cpuid_ext_cache_tbl_l2_to_str(c));
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[3] >> 8UL) & 0xF;
- printf(" %u lines/tag",c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->cache_tlb_l2.a.raw[3] >> 0UL);
- printf(" %u bytes/cache line\n",c);
- }
-
- if (cpu_cpuid_ext_info_has_apm && cpu_cpuid_ext_info->apm.a.raw[0] != 0UL) {
- pause_if_tty();
-
- printf(" - Advanced Power Management\n");
-#define X(b,t) if (cpu_cpuid_ext_info->apm.a.raw[0] & (1UL << ((unsigned long)(b)))) printf("%s ",t);
- /* TODO: What about Intel processors? */
- X(0,"TempSensor");
- X(1,"FID");
- X(2,"VID");
- X(3,"ThermalTrip");
- X(4,"HwThermalControl");
- X(6,"100MHzMultiplierControl");
- X(7,"HwPStateControl");
- X(8,"InvariantTSC");
- X(9,"CorePerfBoost");
- X(10,"ROEffectiveFreqIf");
-#undef X
- printf("\n");
- }
-
- if (cpu_cpuid_ext_info_has_longmode) {
- pause_if_tty();
-
- printf(" - Long Mode\n");
-
- printf(" Address space: ");
-
- c = (unsigned char)(cpu_cpuid_ext_info->longmode.a.raw[0] >> 16UL);
- if (c != 0) printf("Guest: %u bits ",(unsigned int)c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->longmode.a.raw[0] >> 8UL);
- printf("Linear: %u bits ",(unsigned int)c);
-
- c = (unsigned char)(cpu_cpuid_ext_info->longmode.a.raw[0] >> 0UL);
- printf("Physical: %u bits ",(unsigned int)c);
-
- printf("\n");
-
- {
- unsigned int max,num;
-
- max = num = (unsigned int)((cpu_cpuid_ext_info->longmode.a.raw[2] >> 0UL) & 0xFFUL) + 1U;
- if (((cpu_cpuid_ext_info->longmode.a.raw[2] >> 12) & 0xF) != 0)
- max = 2 << ((cpu_cpuid_ext_info->longmode.a.raw[2] >> 12) & 0xF);
-
- printf(" Cores: %u (out of possible %u)\n",num,max);
- }
- }
- }
-
- cpu_extended_cpuid_info_free();
- return 0;
-}
-
+++ /dev/null
--fr=nul -fo=dos386f/.obj -i=.. -i../.. -e=2 -zq -mf -d0 -bt=dos -oilrtfm -wx -fp3 -3r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=386 -DMMODE=f -q apiclib.c
+++ /dev/null
-; tss.asm
-;
-; Test program: 80386 task switching (Task State Segments)
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 386 16-bit protected mode (and back)
-; while playing with the Task State Segment mechanism.
-; note that the 286 TSS is very similar (with different values
-; for the TYPE fields in the GDT, and different register layout)
-; so I will not (yet) bother making a 286 version.
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; SELECTORS
-NULL_SEL equ 0
-CODE_SEL equ 8
-DATA_SEL equ 16
-VIDEO_SEL equ 24
-CODE32_SEL equ 32
-DATA32_SEL equ 40
-TSS_SEL equ 48
-TSS_2_SEL equ 56
-LDT_SEL equ 64
-MAX_SEL equ 72
-
-; ===== ENTRY POINT
- call cpu_is_386
- je is_386
- mov dx,str_cpu_not_386
- jmp exit2dos_with_message
-is_386:
-
-; ===== CHECK FOR VIRTUAL 8086 MODE
- smsw ax ; 386 or higher: If we're in real mode
- test al,1 ; and bit 0 is already set, we're in virtual 8086
- jz is_realmode ; and our switch to prot mode will cause problems.
- mov dx,str_cpu_v86_mode
- jmp exit2dos_with_message
-is_realmode:
-
-; ===== WE NEED TO PATCH SOME OF OUR OWN CODE
- mov ax,cs
- mov word [real_entry_patch+3],ax ; overwrite segment field of JMP SEG:OFF
-
-; ===== BUILD THE GLOBAL DESCRIPTOR TABLE AND GDTR REGISTER
- mov ax,cs
- mov bx,ax
- shr bx,12
- shl ax,4 ; BX:AX = 32-bit physical addr of our segment
- mov word [MY_PHYS_BASE],ax
- mov word [MY_PHYS_BASE+2],bx
-
- add ax,GDT
- adc bx,0 ; BX:AX += offset of GDT
-
- mov word [GDTR],MAX_SEL - 1
- mov word [GDTR+2],ax
- mov word [GDTR+4],bx ; GDTR: limit MAX_SEL-1 base=physical mem addr of GDT
-
- mov ax,word [MY_PHYS_BASE]
- mov bx,word [MY_PHYS_BASE+2]
- add ax,IDT
- adc bx,0
-
- mov word [IDTR],2047
- mov word [IDTR+2],ax
- mov word [IDTR+4],bx
-
- cld
-
-; zero IDT
- mov di,IDT
- mov cx,1023
- xor ax,ax
- rep stosw
-
- mov di,GDT
-; NULL selector (NULL_SEL)
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
-; Code selector (CODE_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (VIDEO_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (32-bit) (CODE32_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; Data selector (32-bit) (DATA32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_SEL)
- mov ax,TSS_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_2_SEL)
- mov ax,TSS_AREA_2_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA_2
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS non busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; LDT selector (32-bit) (LDT_SEL)
- mov ax,LDT_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,LDT_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x82 ; present, non-segment, type=2 (LDT)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-
-; load CPU registers
- cli ; disable interrupts
- lgdt [GDTR] ; load into processor GDTR
- lidt [IDTR]
-
-; switch into protected mode
- mov eax,0x00000001
- mov cr0,eax
- jmp CODE_SEL:prot_entry
-prot_entry: mov ax,DATA_SEL ; now reload the segment registers
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; load LDT
- mov ax,LDT_SEL
- lldt ax
-
-; zero the first TSS
- cld
- mov edi,TSS_AREA
- mov ecx,TSS_AREA_SIZE / 4
- xor eax,eax
- rep stosd
-
-; zero the second TSS
- cld
- mov edi,TSS_AREA_2
- mov ecx,TSS_AREA_2_SIZE / 4
- xor eax,eax
- rep stosd
-
-; set up the task register. for now, leave it at the first one.
- mov ax,TSS_SEL
- ltr ax
-
-; prepare the second one
- cld
- xor eax,eax ; prepare EAX=0
- mov ebx,eax
- mov ecx,0x12345678 ; check value
- mov edi,TSS_AREA_2
- stosd ; TSS+0x00 = back link
- mov ax,0xF000
- stosd ; TSS+0x04 = ESP0
- mov ax,DATA_SEL
- stosd ; TSS+0x08 = SS0
- mov ax,0xF000
- stosd ; TSS+0x0C = ESP1
- mov ax,DATA_SEL
- stosd ; TSS+0x10 = SS1
- mov ax,0xF000
- stosd ; TSS+0x14 = ESP2
- mov ax,DATA_SEL
- stosd ; TSS+0x18 = SS2
- xor ax,ax
- stosd ; TSS+0x1C = CR3
- mov eax,tss_jump_1
- stosd ; TSS+0x20 = EIP
- pushfd
- pop eax
- stosd ; TSS+0x24 = EFLAGS
- xor eax,eax
- stosd ; TSS+0x28 = EAX
- stosd ; TSS+0x2C = ECX
- stosd ; TSS+0x30 = EDX
- stosd ; TSS+0x34 = EBX
- mov ax,0xF000
- stosd ; TSS+0x38 = ESP
- xor ax,ax
- stosd ; TSS+0x3C = EBP
- stosd ; TSS+0x40 = ESI
- stosd ; TSS+0x44 = EDI
- mov ax,DATA_SEL
- stosd ; TSS+0x48 = ES
- mov ax,CODE_SEL
- stosd ; TSS+0x4C = CS
- mov ax,DATA_SEL
- stosd ; TSS+0x50 = SS
- stosd ; TSS+0x54 = DS
- stosd ; TSS+0x58 = FS
- stosd ; TSS+0x5C = GS
- mov ax,LDT_SEL
- stosd ; TSS+0x60 = LDT selector (meh, I don't use it anyway)
- xor ax,ax
- stosd ; TSS+0x64 = I/O map base=0, T=0
-
-; now, SWITCH!
- jmp TSS_2_SEL:0
-
-; TSS switch should end up HERE.
-; Task register now points to TSS_2_SEL as active task.
-; TEST: If the CPU truly loaded state from TSS_2_SEL, all general regs should be zero
-tss_jump_1: or eax,ebx
- or eax,ecx
- or eax,edx
- or eax,esi
- or eax,edi
- jz tss_jump_1_zero
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E30 ; '0'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_zero:
-; TEST: All segment registers except CS should be DATA_SEL
- mov ax,ds
- sub ax,DATA_SEL
-
- mov bx,es
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,fs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,gs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,ss
- sub bx,DATA_SEL
- or ax,bx
-
- jz tss_jump_1_sreg_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E31 ; '1'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_sreg_ok:
-
-; if the CPU truly saved state into TSS_SEL, the memory location
-; corresponding to ECX should be 0x12345678 (because we loaded ECX
-; with that value prior to switching state, remember?)
- cmp dword [TSS_AREA+0x2C],0x12345678
- jz tss_jump_1_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E32 ; '2'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_ecx_ok:
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- push es
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,vdraw_msg
- xor di,di
-vdraw1: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw1e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw1
-vdraw1e: pop es
-
-; now, jump into 32-bit protected mode
- jmp CODE32_SEL:prot32_entry
-bits 32
-prot32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov esp,0xFFF0
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- mov esi,vdraw32_msg
- mov edi,0xB8000+(80*2)
- sub edi,[MY_PHYS_BASE]
-vdraw321: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw321e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw321
-vdraw321e:
-
-; jump 32-bit to 16-bit
- jmp CODE_SEL:prot32_to_prot
-bits 16
-prot32_to_prot: mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
-
-; active task is TSS_2_SEL. Prove we can switch tasks again by modifying
-; EIP in TSS_SEL, then switching tasks.
- mov dword [TSS_AREA+0x20],tss_jump_2
- jmp TSS_SEL:0
-tss_jump_2:
-
-; having switched back to TSS_SEL, the value we left in ECX should still
-; be there.
- cmp ecx,0x12345678
- jz tss_jump_2_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E33 ; '3'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_2_ecx_ok:
-
-; switch back to real mode.
-; unlike the 286, switching back means clearing bit 0 of CR0
- xor eax,eax ; clear bit 0
- mov cr0,eax
-
-real_entry_patch:jmp 0x0000:real_entry ; the segment field is patched by code above
-real_entry: mov ax,cs
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; ===== REBUILD GDTR FOR PROPER REAL MODE OPERATION
- mov word [GDTR],0xFFFF
- mov word [GDTR+2],0
- mov word [GDTR+4],0 ; GDTR: limit 0xFFFF base 0x00000000
- lgdt [GDTR] ; load into processor GDTR
-
- mov word [IDTR],0xFFFF
- mov word [IDTR+2],0
- mov word [IDTR+4],0 ; IDTR: limit 0xFFFF base 0x00000000
- lidt [IDTR]
-
-; ====== PROVE WE MADE IT TO REAL MODE
- mov si,vdraw2_msg
- mov ax,0xB800
- mov es,ax
- mov di,80*4
-vdraw2: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw2e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw2
-vdraw2e: mov ax,cs
- mov es,ax
-
- sti
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-; 8086 test: EFLAGS will always have bits 12-15 set
-cpu_is_386: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_386_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_386_not
-; it's a 386
- xor ax,ax ; ZF=1
- ret
-cpu_is_386_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; strings
-str_cpu_not_386: db "386 or higher required$"
-str_cpu_v86_mode: db "Virtual 8086 mode detected$"
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-vdraw_msg: db "This message was drawn on screen from 386 16-bit protected mode!",0
-vdraw32_msg: db "This message was drawn on screen from 386 32-bit protected mode!",0
-
-; THESE VARIABLES DO NOT EXIST IN THE ACTUAL .COM FILE.
-; They exist in the yet-uninitialized area of RAM just beyond the
-; end of the loaded COM file image.
- align 8
-RALLOC: db 0xAA
-GDTR equ RALLOC+0
-IDTR equ GDTR+8
-MY_PHYS_BASE equ IDTR+8
-GDT equ MY_PHYS_BASE+8
-IDT equ GDT+MAX_SEL
- IDT_SIZE equ 2048
-TSS_AREA equ IDT+IDT_SIZE
- TSS_AREA_SIZE equ 2048
-TSS_AREA_2 equ TSS_AREA+TSS_AREA_SIZE
- TSS_AREA_2_SIZE equ 2048
-LDT_AREA equ TSS_AREA_2+TSS_AREA_2_SIZE
- LDT_AREA_SIZE equ 64
-
+++ /dev/null
-; tssring.asm
-;
-; Test program: 80386 task switching (Task State Segments) to jump privilege levels
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 386 16-bit protected mode (and back)
-; while playing with the Task State Segment mechanism to
-; demonstrate hopping between "ring 0" and "ring 3".
-; note that the 286 TSS is very similar (with different values
-; for the TYPE fields in the GDT, and different register layout)
-; so I will not (yet) bother making a 286 version.
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; SELECTORS
-NULL_SEL equ 0
-CODE_SEL equ 8
-DATA_SEL equ 16
-VIDEO_SEL equ 24
-CODE32_SEL equ 32
-DATA32_SEL equ 40
-TSS_SEL equ 48
-TSS_2_SEL equ 56
-TSS_3_SEL equ 64
-LDT_SEL equ 72
-CODE_SEL3 equ 80
-DATA_SEL3 equ 88
-VIDEO_SEL3 equ 96
-MAX_SEL equ 104
-
-; ===== ENTRY POINT
- call cpu_is_386
- je is_386
- mov dx,str_cpu_not_386
- jmp exit2dos_with_message
-is_386:
-
-; ===== CHECK FOR VIRTUAL 8086 MODE
- smsw ax ; 386 or higher: If we're in real mode
- test al,1 ; and bit 0 is already set, we're in virtual 8086
- jz is_realmode ; and our switch to prot mode will cause problems.
- mov dx,str_cpu_v86_mode
- jmp exit2dos_with_message
-is_realmode:
-
-; ===== WE NEED TO PATCH SOME OF OUR OWN CODE
- mov ax,cs
- mov word [real_entry_patch+3],ax ; overwrite segment field of JMP SEG:OFF
-
-; ===== BUILD THE GLOBAL DESCRIPTOR TABLE AND GDTR REGISTER
- mov ax,cs
- mov bx,ax
- shr bx,12
- shl ax,4 ; BX:AX = 32-bit physical addr of our segment
- mov word [MY_PHYS_BASE],ax
- mov word [MY_PHYS_BASE+2],bx
-
- add ax,GDT
- adc bx,0 ; BX:AX += offset of GDT
-
- mov word [GDTR],MAX_SEL - 1
- mov word [GDTR+2],ax
- mov word [GDTR+4],bx ; GDTR: limit MAX_SEL-1 base=physical mem addr of GDT
-
- mov ax,word [MY_PHYS_BASE]
- mov bx,word [MY_PHYS_BASE+2]
- add ax,IDT
- adc bx,0
-
- mov word [IDTR],2047
- mov word [IDTR+2],ax
- mov word [IDTR+4],bx
-
- cld
-
-; zero IDT
- mov di,IDT
- mov cx,1023
- xor ax,ax
- rep stosw
-
- mov di,GDT
-; NULL selector (NULL_SEL)
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
-; Code selector (CODE_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (VIDEO_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (32-bit) (CODE32_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9E
- stosw ; BASE[23:16] access byte=executable readable conforming
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; Data selector (32-bit) (DATA32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_SEL)
- mov ax,TSS_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_2_SEL)
- mov ax,TSS_AREA_2_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA_2
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS non busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_3_SEL)
- mov ax,TSS_AREA_3_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA_3
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS non busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; LDT selector (32-bit) (LDT_SEL)
- mov ax,LDT_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,LDT_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x82 ; present, non-segment, type=2 (LDT)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; Code selector (CODE_SEL3)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0xFA
- stosw ; BASE[23:16] access byte=executable readable DPL=3
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA_SEL3)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0xF2
- stosw ; BASE[23:16] access byte=data writeable DPL=3
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (VIDEO_SEL3)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0xF2
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-
-; load CPU registers
- cli ; disable interrupts
- lgdt [GDTR] ; load into processor GDTR
- lidt [IDTR]
-
-; switch into protected mode
- mov eax,0x00000001
- mov cr0,eax
- jmp CODE_SEL:prot_entry
-prot_entry: mov ax,DATA_SEL ; now reload the segment registers
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; load LDT
- mov ax,LDT_SEL
- lldt ax
-
-; zero the first TSS
- cld
- mov edi,TSS_AREA
- mov ecx,TSS_AREA_SIZE / 4
- xor eax,eax
- rep stosd
-
-; zero the second TSS
- cld
- mov edi,TSS_AREA_2
- mov ecx,TSS_AREA_2_SIZE / 4
- xor eax,eax
- rep stosd
-
-; set up the task register. for now, leave it at the first one.
- mov ax,TSS_SEL
- ltr ax
-
-; prepare the second one
- cld
- xor eax,eax ; prepare EAX=0
- mov ebx,eax
- mov ecx,0x12345678 ; check value
- mov edi,TSS_AREA_2
- stosd ; TSS+0x00 = back link
- mov ax,0xF000
- stosd ; TSS+0x04 = ESP0
- mov ax,DATA_SEL
- stosd ; TSS+0x08 = SS0
- mov ax,0xF000
- stosd ; TSS+0x0C = ESP1
- mov ax,DATA_SEL
- stosd ; TSS+0x10 = SS1
- mov ax,0xF000
- stosd ; TSS+0x14 = ESP2
- mov ax,DATA_SEL
- stosd ; TSS+0x18 = SS2
- xor ax,ax
- stosd ; TSS+0x1C = CR3
- mov eax,tss_jump_1
- stosd ; TSS+0x20 = EIP
- pushfd
- pop eax
- stosd ; TSS+0x24 = EFLAGS
- xor eax,eax
- stosd ; TSS+0x28 = EAX
- stosd ; TSS+0x2C = ECX
- stosd ; TSS+0x30 = EDX
- stosd ; TSS+0x34 = EBX
- mov ax,0xF000
- stosd ; TSS+0x38 = ESP
- xor ax,ax
- stosd ; TSS+0x3C = EBP
- stosd ; TSS+0x40 = ESI
- stosd ; TSS+0x44 = EDI
- mov ax,DATA_SEL
- stosd ; TSS+0x48 = ES
- mov ax,CODE_SEL
- stosd ; TSS+0x4C = CS
- mov ax,DATA_SEL
- stosd ; TSS+0x50 = SS
- stosd ; TSS+0x54 = DS
- stosd ; TSS+0x58 = FS
- stosd ; TSS+0x5C = GS
- mov ax,LDT_SEL
- stosd ; TSS+0x60 = LDT selector (meh, I don't use it anyway)
- xor ax,ax
- stosd ; TSS+0x64 = I/O map base=0, T=0
-
-; now, SWITCH!
- jmp TSS_2_SEL:0
-
-; TSS switch should end up HERE.
-; Task register now points to TSS_2_SEL as active task.
-; TEST: If the CPU truly loaded state from TSS_2_SEL, all general regs should be zero
-tss_jump_1: or eax,ebx
- or eax,ecx
- or eax,edx
- or eax,esi
- or eax,edi
- jz tss_jump_1_zero
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E30 ; '0'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_zero:
-; TEST: All segment registers except CS should be DATA_SEL
- mov ax,ds
- sub ax,DATA_SEL
-
- mov bx,es
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,fs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,gs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,ss
- sub bx,DATA_SEL
- or ax,bx
-
- jz tss_jump_1_sreg_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E31 ; '1'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_sreg_ok:
-
-; if the CPU truly saved state into TSS_SEL, the memory location
-; corresponding to ECX should be 0x12345678 (because we loaded ECX
-; with that value prior to switching state, remember?)
- cmp dword [TSS_AREA+0x2C],0x12345678
- jz tss_jump_1_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E32 ; '2'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_ecx_ok:
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- push es
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,vdraw_msg
- xor di,di
-vdraw1: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw1e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw1
-vdraw1e: pop es
-
-; now, jump into 32-bit protected mode
- jmp CODE32_SEL:prot32_entry
-bits 32
-prot32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov esp,0xFFF0
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- mov esi,vdraw32_msg
- mov edi,0xB8000+(80*2)
- sub edi,[MY_PHYS_BASE]
-vdraw321: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw321e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw321
-vdraw321e:
-
-; jump 32-bit to 16-bit
- jmp CODE_SEL:prot32_to_prot
-bits 16
-prot32_to_prot: mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
-
-; prepare the third one---ring 3
- cld
- xor eax,eax ; prepare EAX=0
- mov ebx,eax
- mov ecx,0x12345678 ; check value
- mov edi,TSS_AREA_3
- stosd ; TSS+0x00 = back link
- mov ax,0xF000
- stosd ; TSS+0x04 = ESP0
- mov ax,DATA_SEL
- stosd ; TSS+0x08 = SS0
- mov ax,0xF000
- stosd ; TSS+0x0C = ESP1
- mov ax,DATA_SEL
- stosd ; TSS+0x10 = SS1
- mov ax,0xF000
- stosd ; TSS+0x14 = ESP2
- mov ax,DATA_SEL
- stosd ; TSS+0x18 = SS2
- xor ax,ax
- stosd ; TSS+0x1C = CR3
- mov eax,tss_jump_3
- stosd ; TSS+0x20 = EIP
- pushfd
- pop eax
- stosd ; TSS+0x24 = EFLAGS
- xor eax,eax
- stosd ; TSS+0x28 = EAX
- stosd ; TSS+0x2C = ECX
- stosd ; TSS+0x30 = EDX
- stosd ; TSS+0x34 = EBX
- mov ax,0xF000
- stosd ; TSS+0x38 = ESP
- xor ax,ax
- stosd ; TSS+0x3C = EBP
- stosd ; TSS+0x40 = ESI
- stosd ; TSS+0x44 = EDI
- mov ax,DATA_SEL3 | 3
- stosd ; TSS+0x48 = ES
- mov ax,CODE_SEL3 | 3
- stosd ; TSS+0x4C = CS
- mov ax,DATA_SEL3 | 3
- stosd ; TSS+0x50 = SS
- stosd ; TSS+0x54 = DS
- stosd ; TSS+0x58 = FS
- stosd ; TSS+0x5C = GS
- mov ax,LDT_SEL
- stosd ; TSS+0x60 = LDT selector (meh, I don't use it anyway)
- xor ax,ax
- stosd ; TSS+0x64 = I/O map base=0, T=0
-; Call the TSS, so that we can IRET to return to RING 0
- call TSS_3_SEL:0
- jmp skip_tss_3
-
-; now we are 16-bit RING 3
-tss_jump_3: mov ax,VIDEO_SEL3 ; PROVE IT
- mov es,ax ; BY WRITING TO SCREEN
- mov si,vdraw3_msg
- mov di,80*4
- cld
-vdraw3: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw3e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw3
-vdraw3e:
-
-; return from ring 3
- iret
-
-; TSS RING-3 test COMPLETE
-skip_tss_3:
-
-; active task is TSS_2_SEL. Prove we can switch tasks again by modifying
-; EIP in TSS_SEL, then switching tasks.
- mov dword [TSS_AREA+0x20],tss_jump_2
- jmp TSS_SEL:0
-tss_jump_2:
-
-; having switched back to TSS_SEL, the value we left in ECX should still
-; be there.
- cmp ecx,0x12345678
- jz tss_jump_2_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E33 ; '3'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_2_ecx_ok:
-
-; switch back to real mode.
-; unlike the 286, switching back means clearing bit 0 of CR0
- xor eax,eax ; clear bit 0
- mov cr0,eax
-
-real_entry_patch:jmp 0x0000:real_entry ; the segment field is patched by code above
-real_entry: mov ax,cs
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; ===== REBUILD GDTR FOR PROPER REAL MODE OPERATION
- mov word [GDTR],0xFFFF
- mov word [GDTR+2],0
- mov word [GDTR+4],0 ; GDTR: limit 0xFFFF base 0x00000000
- lgdt [GDTR] ; load into processor GDTR
-
- mov word [IDTR],0xFFFF
- mov word [IDTR+2],0
- mov word [IDTR+4],0 ; IDTR: limit 0xFFFF base 0x00000000
- lidt [IDTR]
-
-; ====== PROVE WE MADE IT TO REAL MODE
- mov si,vdraw2_msg
- mov ax,0xB800
- mov es,ax
- mov di,80*6
-vdraw2: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw2e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw2
-vdraw2e: mov ax,cs
- mov es,ax
-
- sti
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-; 8086 test: EFLAGS will always have bits 12-15 set
-cpu_is_386: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_386_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_386_not
-; it's a 386
- xor ax,ax ; ZF=1
- ret
-cpu_is_386_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; strings
-str_cpu_not_386: db "386 or higher required$"
-str_cpu_v86_mode: db "Virtual 8086 mode detected$"
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-vdraw3_msg: db "This message was drawn on screen from 386 16-bit protected mode, ring 3!",0
-vdraw_msg: db "This message was drawn on screen from 386 16-bit protected mode!",0
-vdraw32_msg: db "This message was drawn on screen from 386 32-bit protected mode!",0
-
-; THESE VARIABLES DO NOT EXIST IN THE ACTUAL .COM FILE.
-; They exist in the yet-uninitialized area of RAM just beyond the
-; end of the loaded COM file image.
- align 8
-RALLOC: db 0xAA
-GDTR equ RALLOC+0
-IDTR equ GDTR+8
-MY_PHYS_BASE equ IDTR+8
-GDT equ MY_PHYS_BASE+8
-IDT equ GDT+MAX_SEL
- IDT_SIZE equ 2048
-TSS_AREA equ IDT+IDT_SIZE
- TSS_AREA_SIZE equ 2048
-TSS_AREA_2 equ TSS_AREA+TSS_AREA_SIZE
- TSS_AREA_2_SIZE equ 2048
-TSS_AREA_3 equ TSS_AREA_2+TSS_AREA_2_SIZE
- TSS_AREA_3_SIZE equ 2048
-LDT_AREA equ TSS_AREA_3+TSS_AREA_3_SIZE
- LDT_AREA_SIZE equ 64
-
+++ /dev/null
-; v86.asm
-;
-; Test program: 80386 virtual 8086 mode
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; proot of concept:
-; switching the CPU into 386 16-bit protected mode (and back)
-; while playing with the Task State Segment mechanism to
-; demonstrate hopping between "ring 0" and "ring 3".
-; also to play around with "virtual 8086" mode.
-bits 16 ; 16-bit real mode
-org 0x100 ; MS-DOS .COM style
-
-; assume ES == DS and SS == DS and DS == CS
-
-; SELECTORS
-NULL_SEL equ 0
-CODE_SEL equ 8
-DATA_SEL equ 16
-VIDEO_SEL equ 24
-CODE32_SEL equ 32
-DATA32_SEL equ 40
-TSS_SEL equ 48
-TSS_2_SEL equ 56
-TSS_3_SEL equ 64
-LDT_SEL equ 72
-CODE_SEL3 equ 80
-DATA_SEL3 equ 88
-VIDEO_SEL3 equ 96
-MAX_SEL equ 104
-
-; ===== ENTRY POINT
- call cpu_is_386
- je is_386
- mov dx,str_cpu_not_386
- jmp exit2dos_with_message
-is_386:
-
-; ===== CHECK FOR VIRTUAL 8086 MODE
- smsw ax ; 386 or higher: If we're in real mode
- test al,1 ; and bit 0 is already set, we're in virtual 8086
- jz is_realmode ; and our switch to prot mode will cause problems.
- mov dx,str_cpu_v86_mode
- jmp exit2dos_with_message
-is_realmode:
-
-; ===== WE NEED TO PATCH SOME OF OUR OWN CODE
- mov ax,cs
- mov word [real_entry_patch+3],ax ; overwrite segment field of JMP SEG:OFF
-
-; ===== BUILD THE GLOBAL DESCRIPTOR TABLE AND GDTR REGISTER
- mov ax,cs
- mov bx,ax
- shr bx,12
- shl ax,4 ; BX:AX = 32-bit physical addr of our segment
- mov word [MY_PHYS_BASE],ax
- mov word [MY_PHYS_BASE+2],bx
-
- add ax,GDT
- adc bx,0 ; BX:AX += offset of GDT
-
- mov word [GDTR],MAX_SEL - 1
- mov word [GDTR+2],ax
- mov word [GDTR+4],bx ; GDTR: limit MAX_SEL-1 base=physical mem addr of GDT
-
- mov ax,word [MY_PHYS_BASE]
- mov bx,word [MY_PHYS_BASE+2]
- add ax,IDT
- adc bx,0
-
- mov word [IDTR],2047
- mov word [IDTR+2],ax
- mov word [IDTR+4],bx
-
- cld
-
-; zero IDT
- mov di,IDT
- mov cx,1023
- xor ax,ax
- rep stosw
-
- mov di,GDT
-; NULL selector (NULL_SEL)
- xor ax,ax
- stosw
- stosw
- stosw
- stosw
-; Code selector (CODE_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (VIDEO_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (32-bit) (CODE32_SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x9E
- stosw ; BASE[23:16] access byte=executable readable conforming
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; Data selector (32-bit) (DATA32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=granular 32-bit BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_SEL)
- mov ax,TSS_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_2_SEL)
- mov ax,TSS_AREA_2_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA_2
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS non busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; TSS selector (32-bit) (TSS_3_SEL)
- mov ax,TSS_AREA_3_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,TSS_AREA_3
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x89 ; present, non-segment, type=9 (TSS non busy)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; LDT selector (32-bit) (LDT_SEL)
- mov ax,LDT_AREA_SIZE - 1
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- mov bx,[MY_PHYS_BASE+2]
- add ax,LDT_AREA
- adc bx,0
- stosw ; BASE[15:0]
- mov al,bl
- mov ah,0x82 ; present, non-segment, type=2 (LDT)
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x00
- mov ah,bh ; LIMIT[19:16] flags=granular BASE[31:24]
- stosw
-; Code selector (CODE_SEL3)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0xFA
- stosw ; BASE[23:16] access byte=executable readable DPL=3
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA_SEL3)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[MY_PHYS_BASE]
- stosw ; BASE[15:0]
- mov al,[MY_PHYS_BASE+2]
- mov ah,0xF2
- stosw ; BASE[23:16] access byte=data writeable DPL=3
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (VIDEO_SEL3)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,0x8000
- stosw ; BASE[15:0]
- mov al,0x0B ; BASE=0xB8000
- mov ah,0xF2
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[MY_PHYS_BASE+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-
-; load CPU registers
- cli ; disable interrupts
- lgdt [GDTR] ; load into processor GDTR
- lidt [IDTR]
-
-; switch into protected mode
- mov eax,0x00000001
- mov cr0,eax
- jmp CODE_SEL:prot_entry
-prot_entry: mov ax,DATA_SEL ; now reload the segment registers
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; load LDT
- mov ax,LDT_SEL
- lldt ax
-
-; zero the first TSS
- cld
- mov edi,TSS_AREA
- mov ecx,TSS_AREA_SIZE / 4
- xor eax,eax
- rep stosd
-
-; zero the second TSS
- cld
- mov edi,TSS_AREA_2
- mov ecx,TSS_AREA_2_SIZE / 4
- xor eax,eax
- rep stosd
-
-; set up the task register. for now, leave it at the first one.
- mov ax,TSS_SEL
- ltr ax
-
-; prepare the second one
- cld
- xor eax,eax ; prepare EAX=0
- mov ebx,eax
- mov ecx,0x12345678 ; check value
- mov edi,TSS_AREA_2
- stosd ; TSS+0x00 = back link
- mov ax,0xF000
- stosd ; TSS+0x04 = ESP0
- mov ax,DATA_SEL
- stosd ; TSS+0x08 = SS0
- mov ax,0xF000
- stosd ; TSS+0x0C = ESP1
- mov ax,DATA_SEL
- stosd ; TSS+0x10 = SS1
- mov ax,0xF000
- stosd ; TSS+0x14 = ESP2
- mov ax,DATA_SEL
- stosd ; TSS+0x18 = SS2
- xor ax,ax
- stosd ; TSS+0x1C = CR3
- mov eax,tss_jump_1
- stosd ; TSS+0x20 = EIP
- pushfd
- pop eax
- stosd ; TSS+0x24 = EFLAGS
- xor eax,eax
- stosd ; TSS+0x28 = EAX
- stosd ; TSS+0x2C = ECX
- stosd ; TSS+0x30 = EDX
- stosd ; TSS+0x34 = EBX
- mov ax,0xF000
- stosd ; TSS+0x38 = ESP
- xor ax,ax
- stosd ; TSS+0x3C = EBP
- stosd ; TSS+0x40 = ESI
- stosd ; TSS+0x44 = EDI
- mov ax,DATA_SEL
- stosd ; TSS+0x48 = ES
- mov ax,CODE_SEL
- stosd ; TSS+0x4C = CS
- mov ax,DATA_SEL
- stosd ; TSS+0x50 = SS
- stosd ; TSS+0x54 = DS
- stosd ; TSS+0x58 = FS
- stosd ; TSS+0x5C = GS
- mov ax,LDT_SEL
- stosd ; TSS+0x60 = LDT selector (meh, I don't use it anyway)
- xor ax,ax
- stosd ; TSS+0x64 = I/O map base=0, T=0
-
-; now, SWITCH!
- jmp TSS_2_SEL:0
-
-; TSS switch should end up HERE.
-; Task register now points to TSS_2_SEL as active task.
-; TEST: If the CPU truly loaded state from TSS_2_SEL, all general regs should be zero
-tss_jump_1: or eax,ebx
- or eax,ecx
- or eax,edx
- or eax,esi
- or eax,edi
- jz tss_jump_1_zero
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E30 ; '0'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_zero:
-; TEST: All segment registers except CS should be DATA_SEL
- mov ax,ds
- sub ax,DATA_SEL
-
- mov bx,es
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,fs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,gs
- sub bx,DATA_SEL
- or ax,bx
-
- mov bx,ss
- sub bx,DATA_SEL
- or ax,bx
-
- jz tss_jump_1_sreg_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E31 ; '1'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_sreg_ok:
-
-; if the CPU truly saved state into TSS_SEL, the memory location
-; corresponding to ECX should be 0x12345678 (because we loaded ECX
-; with that value prior to switching state, remember?)
- cmp dword [TSS_AREA+0x2C],0x12345678
- jz tss_jump_1_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E32 ; '2'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_1_ecx_ok:
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- push es
- mov ax,VIDEO_SEL
- mov es,ax
- mov si,vdraw_msg
- xor di,di
-vdraw1: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw1e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw1
-vdraw1e: pop es
-
-; now, jump into 32-bit protected mode
- jmp CODE32_SEL:prot32_entry
-bits 32
-prot32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov esp,0xFFF0
-
-; draw directly onto VGA alphanumeric RAM at 0xB8000
- cld
- mov esi,vdraw32_msg
- mov edi,0xB8000+(80*2)
- sub edi,[MY_PHYS_BASE]
-vdraw321: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw321e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw321
-vdraw321e:
-
-; jump 32-bit to 16-bit
- jmp CODE_SEL:prot32_to_prot
-bits 16
-prot32_to_prot: mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
-
-; prepare IDT for our virtual 8086 shenanigans ahead
- mov si,IDT + (0x3*8) ; INT 3h in case v86 mode doesn't trigger GPF
- mov word [si+0],tss_3_fail ; base[15:0]
- mov word [si+2],CODE_SEL
- mov word [si+4],0x8E00 ; P=1 DPL=0 32-bit interrupt gate
- mov word [si+6],0x0000 ; base[31:16]
-
- mov si,IDT + (0xD*8) ; INT Dh for v86 GPF fault
- mov word [si+0],tss_3_complete ; base[15:0]
- mov word [si+2],CODE_SEL
- mov word [si+4],0x8E00 ; P=1 DPL=0 32-bit interrupt gate
- mov word [si+6],0x0000 ; base[31:16]
-
-; prepare the third one---ring 3. it will be virtual 8086 mode.
- cld
- xor eax,eax ; prepare EAX=0
- mov ebx,eax
- mov ecx,0x12345678 ; check value
- mov edi,TSS_AREA_3
- stosd ; TSS+0x00 = back link
- mov ax,0xF000
- stosd ; TSS+0x04 = ESP0
- mov ax,DATA_SEL
- stosd ; TSS+0x08 = SS0
- mov ax,0xF000
- stosd ; TSS+0x0C = ESP1
- mov ax,DATA_SEL
- stosd ; TSS+0x10 = SS1
- mov ax,0xF000
- stosd ; TSS+0x14 = ESP2
- mov ax,DATA_SEL
- stosd ; TSS+0x18 = SS2
- xor ax,ax
- stosd ; TSS+0x1C = CR3
- mov eax,tss_jump_3
- stosd ; TSS+0x20 = EIP
- pushfd
- pop eax
- or eax,0x20000 ; set bit 17 = VM
- stosd ; TSS+0x24 = EFLAGS
- xor eax,eax
- stosd ; TSS+0x28 = EAX
- stosd ; TSS+0x2C = ECX
- stosd ; TSS+0x30 = EDX
- stosd ; TSS+0x34 = EBX
- mov ax,0xF000
- stosd ; TSS+0x38 = ESP
- xor ax,ax
- stosd ; TSS+0x3C = EBP
- stosd ; TSS+0x40 = ESI
- stosd ; TSS+0x44 = EDI
- mov ax,word [real_entry_patch+3] ; our real-mode segment
- stosd ; TSS+0x48 = ES
- stosd ; TSS+0x4C = CS
- stosd ; TSS+0x50 = SS
- stosd ; TSS+0x54 = DS
- stosd ; TSS+0x58 = FS
- stosd ; TSS+0x5C = GS
- xor ax,ax
- stosd ; TSS+0x60 = LDT selector (meh, I don't use it anyway)
- xor ax,ax
- stosd ; TSS+0x64 = I/O map base=0, T=0
-; Call the TSS, so that we can IRET to return to RING 0
- jmp TSS_3_SEL:0
-
-; now we are 16-bit RING 3 virtual 8086 mode
-tss_jump_3: mov ax,0xB800 ; PROVE IT
- mov es,ax ; BY WRITING TO SCREEN
- mov si,vdraw3_msg
- mov di,80*4
- cld
-vdraw3: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw3e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw3
-vdraw3e:
-
-; cause an interrupt exception to jump back into protected mode
- int 3 ; will cause INT 0x0D not INT 0x03 due to virtual 8086 mode
- jmp short $
-; if INT 3 actually fired execution will land here---because it's WRONG
-tss_3_fail:
- mov ax,DATA_SEL
- mov es,ax
- mov word [es:0],0x4E39 ; '9'
- mov al,3
- out 61h,al
- jmp short $
-
-; TSS RING-3 test COMPLETE (back into 16-bit protected mode). Switch back to TSS_2.
-; NOTE this is where execution is directed for a GPF, But instead of cleaning up
-; the stack we just discard it all and continue on. A real v86 monitor would
-; return execution to whatever real-mode code they want to execute and handle all
-; traps to I/O and interrupt.
-tss_3_complete:
- mov ax,DATA_SEL
- mov ds,ax
- mov es,ax
- mov dword [TSS_AREA_2+0x20],tss_3_complete_2
- jmp TSS_2_SEL:0
-tss_3_complete_2:
-
-; active task is TSS_2_SEL. Prove we can switch tasks again by modifying
-; EIP in TSS_SEL, then switching tasks.
- mov dword [TSS_AREA+0x20],tss_jump_2
- jmp TSS_SEL:0
-tss_jump_2:
-
-; having switched back to TSS_SEL, the value we left in ECX should still
-; be there.
- cmp ecx,0x12345678
- jz tss_jump_2_ecx_ok
-
- mov ax,VIDEO_SEL
- mov es,ax
- mov word [es:0],0x4E33 ; '3'
- mov al,3
- out 61h,al ; turn on bell
- hlt
-tss_jump_2_ecx_ok:
-
-; switch back to real mode.
-; unlike the 286, switching back means clearing bit 0 of CR0
- xor eax,eax ; clear bit 0
- mov cr0,eax
-
-real_entry_patch:jmp 0x0000:real_entry ; the segment field is patched by code above
-real_entry: mov ax,cs
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov ss,ax
- mov sp,0xFFF0
-
-; ===== REBUILD GDTR FOR PROPER REAL MODE OPERATION
- mov word [GDTR],0xFFFF
- mov word [GDTR+2],0
- mov word [GDTR+4],0 ; GDTR: limit 0xFFFF base 0x00000000
- lgdt [GDTR] ; load into processor GDTR
-
- mov word [IDTR],0xFFFF
- mov word [IDTR+2],0
- mov word [IDTR+4],0 ; IDTR: limit 0xFFFF base 0x00000000
- lidt [IDTR]
-
-; ====== PROVE WE MADE IT TO REAL MODE
- mov si,vdraw2_msg
- mov ax,0xB800
- mov es,ax
- mov di,80*6
-vdraw2: lodsb ; AL = DS:SI++
- or al,al
- jz vdraw2e
- mov ah,0x1E
- stosw ; ES:DI = AX, DI += 2
- jmp vdraw2
-vdraw2e: mov ax,cs
- mov es,ax
-
- sti
-
-; ===== DONE
- jmp exit2dos
-
-; ===== EXIT TO DOS WITH ERROR MESSAGE DS:DX
-exit2dos_with_message:
- mov ah,9
- int 21h
-; ===== EXIT TO DOS
-exit2dos: mov ax,4C00h
- int 21h
-
-; 8086 test: EFLAGS will always have bits 12-15 set
-cpu_is_386: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_386_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_386_not
-; it's a 386
- xor ax,ax ; ZF=1
- ret
-cpu_is_386_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; strings
-str_cpu_not_386: db "386 or higher required$"
-str_cpu_v86_mode: db "Virtual 8086 mode detected$"
-vdraw2_msg: db "This message was drawn on screen back from real mode!",0
-vdraw3_msg: db "This message was drawn on screen from virtual 8086 mode!",0
-vdraw_msg: db "This message was drawn on screen from 386 16-bit protected mode!",0
-vdraw32_msg: db "This message was drawn on screen from 386 32-bit protected mode!",0
-
-; THESE VARIABLES DO NOT EXIST IN THE ACTUAL .COM FILE.
-; They exist in the yet-uninitialized area of RAM just beyond the
-; end of the loaded COM file image.
- align 8
-RALLOC: db 0xAA
-GDTR equ RALLOC+0
-IDTR equ GDTR+8
-MY_PHYS_BASE equ IDTR+8
-GDT equ MY_PHYS_BASE+8
-IDT equ GDT+MAX_SEL
- IDT_SIZE equ 2048
-TSS_AREA equ IDT+IDT_SIZE
- TSS_AREA_SIZE equ 2048
-TSS_AREA_2 equ TSS_AREA+TSS_AREA_SIZE
- TSS_AREA_2_SIZE equ 2048
-TSS_AREA_3 equ TSS_AREA_2+TSS_AREA_2_SIZE
- TSS_AREA_3_SIZE equ 2048
-LDT_AREA equ TSS_AREA_3+TSS_AREA_3_SIZE
- LDT_AREA_SIZE equ 64
-
+++ /dev/null
-; v86kern.asm
-;
-; Test program: Proof-of-concept minimalist virtual 8086 "monitor"
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-; MODE: 16-bit real mode MS-DOS .COM executable
-; *THIS CODE IS OBSOLETE*
-; Assumes DS == ES == SS
-
-; NOTES:
-; - This works... for the most part.
-; - Somehow this works even with DOSBox's funky ROM-based interrupt emulation
-; - The emulation provided is sufficient for real-mode exceptions including INT 3h debug and
-; INT 1h trace. It also handles the correct exception to permit v86 programs to use the
-; FPU if present.
-; FIXME:
-; - Privileged instructions like mov cr0,<reg> trigger an exception and this program makes no
-; attempt to emulate those instructions.
-; - This code makes no attempt to emulate the LDT manipulation that most BIOS implementations
-; apparently like to do when handling INT 15H extended memory copy. Programs that use extended
-; memory via HIMEM.SYS or via INT 15H will crash.
-; - For reasons unknown to me, running this under Windows 95 pure DOS mode is crashy. It will run
-; for awhile but eventually, things will hang. Under QEMU, running another program or a 3rd
-; will trigger a sudden reset, which mirrors behavior seen on an actual Pentium system. For
-; other unknown reasons, Bochs and DOSBox run this code just fine.
-; - Whatever the BIOS does in response to CTRL+ALT+DEL it doesn't work well when we are active.
-;
-; This code manages virtual 8086 mode in a suboptimal way. A better implementation is provided in
-; v86kern2.asm
-;
-; FIXME: Okay now this is crashing. Why?
-
-; Standard selectors in protected mode
-NULL_SEL equ (0 << 3)
-CODE16_SEL equ (1 << 3)
-DATA16_SEL equ (2 << 3)
-CODE32_SEL equ (3 << 3)
-DATA32_SEL equ (4 << 3)
-FLAT16_SEL equ (5 << 3)
-FLAT32_SEL equ (6 << 3)
-LDT_SEL equ (7 << 3)
-TSS_SEL equ (8 << 3)
-TSS_VM86_SEL equ (9 << 3)
-MAX_SEL equ (10 << 3)
-
-; We reprogram the PIC to direct IRQ 0-15 to this base interrupt
-IRQ_BASE_INT equ 0x68
-RM_INT_API equ 0x66
-
-; Extensible virtual 8086 mode kernel for DOS
-; (C) 2011 Jonathan Campbell
-
- bits 16
- section .code
- [map v86kern.map]
- org 0x100
-
-; ============= ENTRY POINT
- mov ax,cs
- mov word [my_realmode_seg],ax
- mov bp,stack_base
- mov sp,stack_init ; SP is normally at 0xFFF0 so move it back down
- mov word [himem_sys_buffer_handle],0
- mov byte [user_req_unload],0
- mov byte [user_req_iopl],3
- mov byte [irq_pending],0
- mov byte [i_am_tsr],0
- mov byte [v86_if],0
- jmp _entry
-
-; ============= CPU DETECT
-cpu_is_386: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_386_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_386_not
-; it's a 386
- xor ax,ax ; ZF=1
- ret
-cpu_is_386_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; ============= EXIT WITH MESSAGE ($-terminated string at DS:DX)
-_exit_with_msg: mov ah,9
- int 21h ; fall through to _exit
-; ============= EXIT
-_exit: mov ax,cs
- mov ds,ax
- cmp word [himem_sys_buffer_handle],0 ; if there is a handle to free, then do it
- jz .no_handle
- mov ah,0Dh ; HIMEM.SYS function 0Dh unlock memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
- mov ah,0Ah ; HIMEM.SYS function 0Ah free memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
-.no_handle: mov ax,4C00h
- int 21h
-
-; ============= PROGRAM STARTS HERE
-_entry: call parse_argv
- jz .argv_ok
- mov dx,str_help
- call _exit_with_msg
-.argv_ok: call cpu_is_386 ; CHECK: 386 or higher
- jz .is386
- mov dx,str_require_386
- jmp _exit_with_msg
-.is386: cmp byte [user_req_unload],0; CHECK: Did user request that we unload?
- jz .not_unload
- jmp unload_this_program
-.not_unload: smsw ax ; CHECK: Virtual 8086 mode not already enabled
- test al,1
- jz .not_v86
- mov dx,str_v86_detected
- jmp _exit_with_msg
-.not_v86: cmp dword [himem_sys_buffer_size],64*1024 ; CHECK: buffer size is 64KB or larger
- jge .buffer_size_large_enough
- mov dx,str_buffer_too_small
- jmp _exit_with_msg
-.buffer_size_large_enough:
- cmp dword [himem_sys_buffer_size],16*1024*1024
- jle .buffer_size_small_enough
- mov dx,str_buffer_too_large
- jmp _exit_with_msg
-.buffer_size_small_enough:
- mov ax,4300h ; CHECK: HIMEM.SYS is present
- int 2Fh
- cmp al,80h
- jz .yes_himem_sys
- mov dx,str_need_himem_sys
- jmp _exit_with_msg
-.yes_himem_sys: mov ax,4310h ; Get HIMEM.SYS entry point (cannot fail)
- int 2Fh
- mov word [himem_sys_entry],bx
- mov word [himem_sys_entry+2],es
- mov ah,5h ; HIMEM.SYS Local Enable A20
- call far word [himem_sys_entry]
- cmp ax,1
- jz .yes_himem_a20
- mov dx,str_himem_a20_error
- jmp _exit_with_msg
-.yes_himem_a20: mov ah,09h ; HIMEM.SYS allocate block
- cli ; <- in case BIOS interrupts do not save upper 16 bits
- mov edx,[himem_sys_buffer_size]
- add edx,1023
- shr edx,10 ; EDX = (X BYTES+1023)/1024 KB
- call far word [himem_sys_entry]
- cmp ax,1
- jz .yes_himem_buf
- mov dx,str_himem_alloc_err
- jmp _exit_with_msg
-.yes_himem_buf: mov word [himem_sys_buffer_handle],dx ; store memory handle
- mov ah,0Ch ; HIMEM.SYS lock memory block
- call far word [himem_sys_entry] ; NOTE: DX = memory handle (still)
- cmp ax,1
- jz .yes_himem_lock
- mov dx,str_himem_lock_err
- jmp _exit_with_msg
-.yes_himem_lock:mov word [himem_sys_buffer_phys],bx ; store DX:BX physical memory address
- mov word [himem_sys_buffer_phys+2],dx
-
-; choose where things go within the buffer
-; = 104 bytes for main TSS
- mov eax,[himem_sys_buffer_phys]
- mov [tss_phys_base],eax
- add eax,128
-; = 8192+104 bytes for VM86 TSS
- mov [tss_vm86_phys_base],eax
- add eax,8192+128
-; = 4096 for kernel 32 stack
- mov [kern32_stack_base],eax
- add eax,4096
- lea ebx,[eax-8]
- mov [kern32_stack_top],ebx
-; = store it for future allocation
- mov [buffer_alloc],eax
-
-; PRINT "BUFFER AT: " + *((DWORD*)himem_sys_buffer_phys) + "\n"
- mov dx,str_buffer_at
- call dos_puts
- cli
- mov eax,[himem_sys_buffer_phys]
- mov di,scratch_str
- call eax_to_hex_16_dos
- mov dx,di
- call dos_puts
-
- cli
- mov eax,[himem_sys_buffer_phys]
- add eax,[himem_sys_buffer_size]
- dec eax
- mov byte [scratch_str],'-'
- mov di,scratch_str+1
- call eax_to_hex_16_dos
- mov dx,scratch_str
- call dos_puts
-
- mov dx,str_crlf
- call dos_puts
-
- xor eax,eax
- mov ax,cs
- mov es,ax
- shl eax,4
- mov dword [my_phys_base],eax
-
-; clear the IDT and GDT
- cld
- xor ax,ax
-
- mov cx,MAX_SEL / 2
- mov di,gdt
- rep stosw
-
-; prepare the IDTR and GDTR.
-; real mode versions: limit=0xFFFF base=0
- xor eax,eax
- dec ax ; AX = 0xFFFF
- mov word [idtr_real],ax
- mov word [gdtr_real],ax
- inc ax
- mov dword [idtr_real+2],eax
- mov dword [gdtr_real+2],eax
-; protected mode GDTR limit=MAX_SEL-1 base=(code segment)+var
- mov word [gdtr_pmode],MAX_SEL - 1
- mov word [idtr_pmode],(256 << 3) - 1
- mov eax,[my_phys_base]
- add eax,gdt
- mov dword [gdtr_pmode+2],eax
- mov eax,[my_phys_base]
- add eax,idt
- mov dword [idtr_pmode+2],eax
-
-; build the GDT
- cld
- lea di,[gdt+CODE16_SEL]
-; Code selector (CODE_16SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA16_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (CODE_32SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0xCF
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (FLAT16_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- xor ax,ax
- stosw ; BASE[15:0]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x8F
- xor ah,ah
- stosw
-; Data selector (FLAT32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- xor ax,ax
- stosw ; BASE[15:0]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- xor ah,ah
- stosw
-; LDT selector (LDT_SEL)
- mov ax,7 ; I have no use for the LDT
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x82
- stosw ; BASE[23:16] access byte=data writeable LDT type 2
- mov al,0x0F
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; TSS selector (TSS_SEL)
- mov ax,104-1
- stosw ; LIMIT
- mov ax,[tss_phys_base]
- stosw ; BASE[15:0]
- mov al,[tss_phys_base+2]
- mov ah,0x89
- stosw ; BASE[23:16] access byte=data writeable non-busy TSS type 9
- mov al,0x0F
- mov ah,[tss_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; TSS selector (TSS_VM86_SEL)
- mov ax,104+8192-1
- stosw ; LIMIT
- mov ax,[tss_vm86_phys_base]
- stosw ; BASE[15:0]
- mov al,[tss_vm86_phys_base+2]
- mov ah,0x89
- stosw ; BASE[23:16] access byte=data writeable non-busy TSS type 9
- mov al,0x0F
- mov ah,[tss_vm86_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-
-; prepare the CPU registers
- lidt [idtr_pmode]
- lgdt [gdtr_pmode]
-
-; enter protected mode
- mov eax,1
- mov cr0,eax
- jmp CODE16_SEL:pmode16_entry
-pmode16_entry: mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,stack_init
-
-; load task register
- mov ax,TSS_SEL
- ltr ax
-
-; load LDT
- mov ax,LDT_SEL
- lldt ax
-
-; now enter 32-bit protected mode
- jmp CODE32_SEL:pmode32_entry
- bits 32
-pmode32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov ax,FLAT32_SEL
- mov fs,ax
- mov gs,ax
- mov esp,stack_init
-; at this point: we are in 32-bit protected mode!
-
-; ============= setup the TSS representing our task (for when we return)
- cld
- mov edi,[tss_phys_base]
- sub edi,[my_phys_base]
-
- xor eax,eax ; TSS+0x00 = no backlink
- stosd
- mov eax,[kern32_stack_top] ; TSS+0x04 = ESP for CPL0
- sub eax,[my_phys_base]
- stosd
- mov eax,DATA32_SEL ; TSS+0x08 = SS for CPL0
- stosd
- mov eax,[kern32_stack_top] ; TSS+0x0C = ESP for CPL1
- sub eax,[my_phys_base]
- stosd
- mov eax,DATA32_SEL ; TSS+0x10 = SS for CPL1
- stosd
- mov eax,[kern32_stack_top] ; TSS+0x14 = ESP for CPL2
- sub eax,[my_phys_base]
- stosd
- mov eax,DATA32_SEL ; TSS+0x18 = SS for CPL2
- stosd
- xor eax,eax ; TSS+0x1C = CR3
- stosd
- mov eax,vm86_entry ; TSS+0x20 = EIP
- stosd
- mov eax,0x00000002 ; TSS+0x24 = EFLAGS VM=0
- stosd
- xor eax,eax ; TSS+0x28 = EAX
- stosd
- xor eax,eax ; TSS+0x2C = ECX
- stosd
- xor eax,eax ; TSS+0x30 = EDX
- stosd
- xor eax,eax ; TSS+0x34 = EBX
- stosd
- mov eax,stack_init_vm86 ; TSS+0x38 = ESP
- stosd
- xor eax,eax ; TSS+0x3C = EBP
- stosd
- xor eax,eax ; TSS+0x40 = ESI
- stosd
- xor eax,eax ; TSS+0x44 = EDI
- stosd
- mov ax,DATA32_SEL ; TSS+0x48 = ES
- stosd
- mov ax,CODE32_SEL ; TSS+0x4C = CS
- stosd
- mov ax,DATA32_SEL ; TSS+0x50 = SS
- stosd
- mov ax,DATA32_SEL ; TSS+0x54 = DS
- stosd
- mov ax,DATA32_SEL ; TSS+0x58 = FS
- stosd
- mov ax,DATA32_SEL ; TSS+0x5C = GS
- stosd
- xor eax,eax ; TSS+0x60 = LDTR
- stosd
- mov eax,(104 << 16) ; TSS+0x64 = I/O map base
- stosd
-
-; ============= setup the TSS representing the virtual 8086 mode task
- cld
- mov edi,[tss_vm86_phys_base]
- sub edi,[my_phys_base]
-
- xor eax,eax ; TSS+0x00 = no backlink
- stosd
- mov eax,[kern32_stack_top] ; TSS+0x04 = ESP for CPL0
- sub eax,[my_phys_base]
- stosd
- mov eax,DATA32_SEL ; TSS+0x08 = SS for CPL0
- stosd
- mov eax,[kern32_stack_top] ; TSS+0x0C = ESP for CPL1
- sub eax,[my_phys_base]
- stosd
- mov eax,DATA32_SEL ; TSS+0x10 = SS for CPL1
- stosd
- mov eax,[kern32_stack_top] ; TSS+0x14 = ESP for CPL2
- sub eax,[my_phys_base]
- stosd
- mov eax,DATA32_SEL ; TSS+0x18 = SS for CPL2
- stosd
- xor eax,eax ; TSS+0x1C = CR3
- stosd
- mov eax,vm86_entry ; TSS+0x20 = EIP
- stosd
- mov eax,0x00020202 ; TSS+0x24 = EFLAGS VM=1 IOPL=N IF=1
- movzx ebx,byte [user_req_iopl]
- and bl,3
- shl ebx,12
- or eax,ebx ; EFLAGS |= user_req_iopl << 12
- stosd
- xor eax,eax ; TSS+0x28 = EAX
- stosd
- xor eax,eax ; TSS+0x2C = ECX
- stosd
- xor eax,eax ; TSS+0x30 = EDX
- stosd
- xor eax,eax ; TSS+0x34 = EBX
- stosd
- mov eax,stack_init ; TSS+0x38 = ESP
- stosd
- xor eax,eax ; TSS+0x3C = EBP
- stosd
- xor eax,eax ; TSS+0x40 = ESI
- stosd
- xor eax,eax ; TSS+0x44 = EDI
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x48 = ES
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x4C = CS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x50 = SS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x54 = DS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x58 = FS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x5C = GS
- stosd
- xor eax,eax ; TSS+0x60 = LDTR
- stosd
- mov eax,(104 << 16) ; TSS+0x64 = I/O map base
- stosd
- xor eax,eax
- mov ecx,8192 >> 2 ; TSS+0x68 = I/O permission map (pre-set to all open)
- rep stosd
-
-; set up the IDT
- cld
-
- mov ecx,0x100
- mov edi,idt
-.idtdef: mov ax,fault_no_int ; no interrupt assigned procedure
- stosw ; base[15:0]
- mov ax,CODE32_SEL
- stosw
- mov ax,0x8E00 ; DPL=3
- stosw
- xor ax,ax
- stosw
- loop .idtdef
-
- mov esi,fault_routines
- mov ecx,0x20
- mov edi,idt
-.idtsetup: lodsw
- stosw ; base[15:0]
- mov ax,CODE32_SEL
- stosw
- mov ax,0x8E00 ; DPL=3
- stosw
- xor ax,ax
- stosw
- loop .idtsetup
-
- cld
- mov esi,irq_routines
- mov ecx,0x10
- mov edi,idt + (IRQ_BASE_INT*8)
-.idtsetup2: lodsw
- stosw ; base[15:0]
- mov ax,CODE32_SEL
- stosw
- mov ax,0x8E00 ; you must set DPL=3
- stosw
- xor ax,ax
- stosw
- loop .idtsetup2
-
-; next we need to reprogram the PIC so that IRQ 0-7 do not conflict with the CPU exceptions.
-; note for stability we only reprogram first PIC, since we do not relocate the 2nd PIC.
- mov al,0x10 ; ICW1 A0=0
- out 20h,al
- mov al,IRQ_BASE_INT ; ICW2 A0=1
- out 21h,al
- mov al,0x04 ; ICW3 A0=1 slave on IRQ 2
- out 21h,al
-
-; jump into virtual 8086 mode
- jmp TSS_VM86_SEL:0
-
-; =============== IRQ handler code
-
-int_rm_map: db 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F
- db 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
-
-irq_priority: db 0,1,8,9,10,11,12,13,14,15,2,3,4,5,6,7
- ; ^ 16 entries, reflecting IRQ 8-15 -> IRQ 2 (slave PIC) and IRQ 0-7 (master PIC) cascade
-
-; EAX = IRQ that fired
-; [ESP+0] = old EAX
-; [ESP+4] = EIP
-; [ESP+8] = CS
-; [ESP+12] = EFLAGS
-; [ESP+16] = ESP
-; [ESP+20] = SS
-; [ESP+24] = ES
-; [ESP+28] = DS
-; [ESP+32] = FS
-; [ESP+36] = GS
-irq_general: test dword [esp+12],0x20000 ; did the interrupt happen while in v86 mode?
- jnz .reflect_v86
-; this happened while NOT in v86 mode. We should still reflect it back to v86 mode.
-; ----------------------TODO--------------------
- call fault_collect_regs
- mov edx,0x00
- mov esi,str_irq_1
- jmp fault_jmp_unhandled
-; ----------------------------------------------
-; CPU was in v86 mode. Modify stack pointer to reflect the interrupt.
-.reflect_v86: test dword [esp+12],0x200 ; are interrupts enabled in the vm?
- jz .reflect_v86_pending ; if not, then we need to note it and reflect later
- push ebx
- push ecx
- mov bx,FLAT32_SEL ; NTS: Don't worry about saving ES. The CPU saved
- mov ds,bx ; it as part of the v86 -> interrupt transition.
- xor ebx,ebx
- mov ecx,ebx
- mov bl,[cs:int_rm_map+eax] ; IRQ -> interrupt
- mov ebx,[ebx*4] ; interrupt -> realmode vector
- mov ax,[esp+20+8] ; fetch SS
- shl eax,4 ; EAX = SS*16
- mov cx,[esp+16+8] ; fetch SP
- sub cx,6 ; SP -= 6
- add eax,ecx ; EAX = SS*16 + SP
- mov [esp+16+8],cx ; store modified SP back
-; EBX = realmode interrupt vector
-; EAX = stack pointer (physical mem addr)
- mov cx,[esp+4+8] ; fetch EIP
- mov word [eax+0],cx ; SS:SP = offset
- mov cx,[esp+8+8] ; fetch CS
- mov word [eax+2],cx ; SS:SP+2 = segment
- mov cx,[esp+12+8] ; fetch FLAGS
- mov word [eax+4],cx ; SS:SP+4 = flags
- mov [esp+4+8],bx ; overwrite IP = offset of vector
- shr ebx,16
- mov [esp+8+8],bx ; overwrite CS = segment of vector
-
-; *DEBUG*
- inc word [0xB8000]
-
- pop ecx
- pop ebx
- pop eax
- iret
-; v86 mode, but interrupts are disabled
-.reflect_v86_pending:
- push ebx
- push ecx
- mov bx,DATA32_SEL
- mov ds,bx
- mov cl,al ; CL = IRQ
- mov eax,1
- shl eax,cl ; EAX = 1 << IRQ
- or word [irq_pending],ax ; irq_pending |= 1 << IRQ
- pop ecx
- pop ebx
- pop eax
- iret
-
-irq_0: push eax
- mov eax,0
- jmp irq_general
-
-irq_1: push eax
- mov eax,1
- jmp irq_general
-
-irq_2: push eax
- mov eax,2
- jmp irq_general
-
-irq_3: push eax
- mov eax,3
- jmp irq_general
-
-irq_4: push eax
- mov eax,4
- jmp irq_general
-
-irq_5: push eax
- mov eax,5
- jmp irq_general
-
-irq_6: push eax
- mov eax,6
- jmp irq_general
-
-irq_7: push eax
- mov eax,7
- jmp irq_general
-
-irq_8: push eax
- mov eax,8
- jmp irq_general
-
-irq_9: push eax
- mov eax,9
- jmp irq_general
-
-irq_10: push eax
- mov eax,10
- jmp irq_general
-
-irq_11: push eax
- mov eax,11
- jmp irq_general
-
-irq_12: push eax
- mov eax,12
- jmp irq_general
-
-irq_13: push eax
- mov eax,13
- jmp irq_general
-
-irq_14: push eax
- mov eax,14
- jmp irq_general
-
-irq_15: push eax
- mov eax,15
- jmp irq_general
-
-; =============== GENERAL PURPOSE "NO INTERRUPT ASSIGNED" HANDLER
-fault_no_int: iret
-
-fault_x86_vector:db 0
-; =============== REFLECT EXCEPTION TO REAL MODE
-fault_v86_reflect:
- push eax
- push ebx
- push ecx
- mov bx,FLAT32_SEL ; NTS: Don't worry about saving ES. The CPU saved
- mov ds,bx ; it as part of the v86 -> interrupt transition.
- xor ebx,ebx
- mov ecx,ebx
- mov bl,[cs:fault_x86_vector]; what interrupt is involved?
- mov ebx,[ebx*4] ; interrupt -> realmode vector
- mov ax,[esp+20+8] ; fetch SS
- shl eax,4 ; EAX = SS*16
- mov cx,[esp+16+8] ; fetch SP
- sub cx,6 ; SP -= 6
- add eax,ecx ; EAX = SS*16 + SP
- mov [esp+16+8],cx ; store modified SP back
-; EBX = realmode interrupt vector
-; EAX = stack pointer (physical mem addr)
- mov cx,[esp+4+8] ; fetch EIP
- mov word [eax+0],cx ; SS:SP = offset
- mov cx,[esp+8+8] ; fetch CS
- mov word [eax+2],cx ; SS:SP+2 = segment
- mov cx,[esp+12+8] ; fetch FLAGS
- mov word [eax+4],cx ; SS:SP+4 = flags
- mov [esp+4+8],bx ; overwrite IP = offset of vector
- shr ebx,16
- mov [esp+8+8],bx ; overwrite CS = segment of vector
-; if this is INT 0x01 we also need to clear the TF bit
- cmp byte [cs:fault_x86_vector],1
- jnz .not_int1
- and word [esp+12+8],~0x100 ; clear TF
-.not_int1:
-
-; *DEBUG*
- inc word [0xB8002]
-
- pop ecx
- pop ebx
- pop eax
- iret
-
-; =============== FAULT HANDLER CODE
-fault_0x00: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x00
- mov esi,str_fault_0x00
- jmp fault_jmp_unhandled
-
-fault_0x01: test dword [esp+8],0x20000 ; did it happen from within v86 mode?
- jnz .reflect_v86
- push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x01
- mov esi,str_fault_0x01
- jmp fault_jmp_unhandled
-.reflect_v86: mov byte [ss:fault_x86_vector],0x01 ; reflect to INT 0x01
- jmp fault_v86_reflect
-
-fault_0x02: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x02
- mov esi,str_fault_0x02
- jmp fault_jmp_unhandled
-
-fault_0x03: test dword [esp+8],0x20000 ; did it happen from within v86 mode?
- jnz .reflect_v86
- push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x03
- mov esi,str_fault_0x03
- jmp fault_jmp_unhandled
-.reflect_v86: mov byte [ss:fault_x86_vector],0x03 ; reflect to INT 0x03
- jmp fault_v86_reflect
-
-fault_0x04: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x04
- mov esi,str_fault_0x04
- jmp fault_jmp_unhandled
-
-fault_0x05: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x05
- mov esi,str_fault_0x05
- jmp fault_jmp_unhandled
-
-fault_0x06: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x06
- mov esi,str_fault_0x06
- jmp fault_jmp_unhandled
-
-fault_0x07: push eax
- mov eax,cr0
- test eax,0x08 ; is this a result of CR0.TS being set?
- pop eax
- jz .not_cr0_ts
-; very likely a real-mode DOS application executed floating point instructions, and
-; the task switch into vm86 mode left bit 3 (CR0.TS) set. Clear it and return. This
-; is necessary to allow the DOS system to use floating point, even on 486/Pentium and
-; higher systems where the FPU is integral to the CPU. Even for simple instructions
-; like FSTSW/FNSTSW.
- clts
- iret
-; if the exception did NOT involve that bit, then yes, it's something to halt on
-.not_cr0_ts: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x07
- mov esi,str_fault_0x07
- jmp fault_jmp_unhandled
-
-fault_0x08: call fault_collect_regs
- mov edx,0x08
- mov esi,str_fault_0x08
- jmp fault_jmp_unhandled
-
-fault_0x09: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x09
- mov esi,str_fault_0x09
- jmp fault_jmp_unhandled
-
-fault_0x0A: call fault_collect_regs
- mov edx,0x0A
- mov esi,str_fault_0x0A
- jmp fault_jmp_unhandled
-
-fault_0x0B: call fault_collect_regs
- mov edx,0x0B
- mov esi,str_fault_0x0B
- jmp fault_jmp_unhandled
-
-fault_0x0C: call fault_collect_regs
- mov edx,0x0C
- mov esi,str_fault_0x0C
- jmp fault_jmp_unhandled
-
-fault_0x0E: call fault_collect_regs
- mov edx,0x0E
- mov esi,str_fault_0x0E
- jmp fault_jmp_unhandled
-
-fault_0x0F: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x0F
- mov esi,str_fault_0x0F
- jmp fault_jmp_unhandled
-
-fault_0x10: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x10
- mov esi,str_fault_0x10
- jmp fault_jmp_unhandled
-
-fault_0x11: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x11
- mov esi,str_fault_0x11
- jmp fault_jmp_unhandled
-
-fault_0x12: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x12
- mov esi,str_fault_0x12
- jmp fault_jmp_unhandled
-
-fault_0x13: push dword 0 ; ERROR CODE
- call fault_collect_regs
- mov edx,0x13
- mov esi,str_fault_0x13
- jmp fault_jmp_unhandled
-
-fault_0x14: call fault_collect_regs
- mov edx,0x14
- jmp fault_jmp_unhandled_unknown
-
-fault_0x15: call fault_collect_regs
- mov edx,0x15
- jmp fault_jmp_unhandled_unknown
-
-fault_0x16: call fault_collect_regs
- mov edx,0x16
- jmp fault_jmp_unhandled_unknown
-
-fault_0x17: call fault_collect_regs
- mov edx,0x17
- jmp fault_jmp_unhandled_unknown
-
-fault_0x18: call fault_collect_regs
- mov edx,0x18
- jmp fault_jmp_unhandled_unknown
-
-fault_0x19: call fault_collect_regs
- mov edx,0x19
- jmp fault_jmp_unhandled_unknown
-
-fault_0x1A: call fault_collect_regs
- mov edx,0x1A
- jmp fault_jmp_unhandled_unknown
-
-fault_0x1B: call fault_collect_regs
- mov edx,0x1B
- jmp fault_jmp_unhandled_unknown
-
-fault_0x1C: call fault_collect_regs
- mov edx,0x1C
- jmp fault_jmp_unhandled_unknown
-
-fault_0x1D: call fault_collect_regs
- mov edx,0x1D
- jmp fault_jmp_unhandled_unknown
-
-fault_0x1E: call fault_collect_regs
- mov edx,0x1E
- jmp fault_jmp_unhandled_unknown
-
-fault_0x1F: call fault_collect_regs
- mov edx,0x1F
- jmp fault_jmp_unhandled_unknown
-
-fault_jmp_unhandled_unknown:
- mov esi,str_fault_unknown
- jmp fault_jmp_unhandled
-
-; ============= EXCEPTION HANDLER: INT 0x0D GENERAL PROTECTION FAULT
-; If caused by v8086 mode:
-; [ESP+0] = error code
-; [ESP+4] = EIP
-; [ESP+8] = CS
-; [ESP+12] = EFLAGS
-; [ESP+16] = ESP
-; [ESP+20] = SS
-; [ESP+24] = ES
-; [ESP+28] = DS
-; [ESP+32] = FS
-; [ESP+36] = GS
-; Else, only the error code, EIP, CS, EFLAGS fields are present.
-; If not from ring 0, then ESP, SS are as well.
-fault_0x0D: test dword [esp+12],0x20000 ; [ESP+12] = EFLAGS. Is bit 17 (VM) set?
- jz .not_vm86_related
-
-; at this point, we know this is the processor trapping CLI/STI or anything that a v86 monitor needs to know.
-; so the next thing we do is examine the opcode at CS:IP to determine what the code is trying to do, and how
-; to emulate it. Note the CS:IP off stack are REAL MODE addresses.
- pushad
- mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
-
- xor eax,eax
- mov ebx,eax
- mov ax,[esp+0x20+8] ; CS ON STACK
- shl eax,4
- add bx,[esp+0x20+4] ; EIP ON STACK
- add eax,ebx
- sub eax,[my_phys_base] ; REMEMBER our data segment is relative to the COM.
- ; ALSO KNOW most x86 processors will wrap addresses like
- ; 0xFFFFF000 back around to 0 (32-bit overflow) with nonzero
- ; segment bases.
-
- mov eax,[eax] ; fetch 4 bytes at CS:IP
- mov [v86_raw_opcode],eax ; store for reference
-
- cmp al,0xFA ; CLI?
- jz .v86_cli
- cmp al,0xFB ; STI?
- jz .v86_sti
- cmp al,0xF4 ; HLT? (apparently, yes, that causes a GPF from v86 mode)
- jz .v86_hlt
- cmp al,0xCD ; INT X (AH=interrupt)
- jz .v86_int
- cmp al,0xCC ; INT 3
- jz .v86_int3
- cmp al,0xCF ; IRET
- jz .v86_iret
- cmp al,0x9C ; PUSHF 16-bit
- jz .v86_pushf
- cmp al,0x9D ; POPF 16-bit
- jz .v86_popf
- cmp ax,0x9C66 ; PUSHFD 32-bit
- jz .v86_pushfd
- cmp ax,0x9D66 ; POPFD 32-bit
- jz .v86_popfd
- jmp .v86_unknown
-
-.v86_complete_and_check_pending_irq: ; <----------- COMPLETION, PLUS CHECK IF INTERRUPTS ENABLED, PENDING IRQs
- test word [esp+0x20+12],0x200 ; are interrupts enabled (IF=1)
- jz .v86_complete
-; interrupts enabled, are there pending IRQs?
- cmp word [irq_pending],0
- jz .v86_complete
-; for each pending IRQ, stuff the stack with an interrupt frame.
-; this must be done in the order the PIC would do based on IRQ priority.
- cld
- mov ecx,16
- mov esi,irq_priority
-.v86_complete_and_check_pending_irq_scan:
- xor eax,eax
- lodsb
- mov ebx,1
- push ecx
- mov cl,al ; <- NTS: bits 8-31 should be zero because we inited ECX == 16
- shl ebx,cl
- pop ecx
- test word [irq_pending],bx ; if (irq_pending & (1 << AL)) ...
- jnz .v86_complete_and_check_pending_irq_found
- loop .v86_complete_and_check_pending_irq_scan
-; FALL THROUGH TO COMPLETION
-.v86_complete: popad
-.v86_complete_no_popad:
- add esp,4 ; dump error code (usually zero)
- iret
-
-; we found a pending IRQ. EBX = 1 << IRQ, EAX = IRQ
-.v86_complete_and_check_pending_irq_found:
- push ecx
- xor word [irq_pending],bx ; clear the bit
-
- movzx ebx,al ; EBX = interrupt number
- mov eax,FLAT32_SEL
- mov es,ax ; we'll need flat mode for this
- mov bl,[int_rm_map+ebx] ; IRQ -> interrupt
- ; store CS:IP and FLAGS on 16-bit stack, decrement stack pointer. DO NOT MODIFY EBX
- sub word [esp+0x20+4+16],6 ; (E)SP -= 6
- mov ax,word [esp+0x20+4+20] ; AX = SS (upper bits should be zero)
- shl eax,4 ; AX *= 16
- xor ecx,ecx
- mov cx,word [esp+0x20+4+16] ; CX = SP
- add eax,ecx ; AX += SP AX = (SS*16)+SP
- mov cx,word [esp+0x20+4+4] ; IP
- mov word [es:eax],cx ; SS:SP+0 = IP
- mov cx,word [esp+0x20+4+8] ; CS
- mov word [es:eax+2],cx ; SS:SP+2 = CS
- mov cx,word [esp+0x20+4+12] ; FLAGS
- mov word [es:eax+4],cx ; SS:SP+4 = FLAGS
- ; replace CS:IP with values from real-mode interrupt table (EBX = interrupt vector)
- mov ax,[es:(ebx*4)] ; read from real-mode interrupt table (offset)
- mov word [esp+0x20+4+4],ax ; replace EIP
- mov ax,[es:(ebx*4)+2] ; .... (segment)
- mov word [esp+0x20+4+8],ax ; replace CS
-
- pop ecx
- dec ecx
- jz .v86_complete
- jmp .v86_complete_and_check_pending_irq_scan
-
-; EXCEPTION HANDLING REACHES HERE IF IT TURNS OUT VM86 MODE WAS NOT INVOLVED
-.not_vm86_related:
- call fault_collect_regs
- mov edx,0x0D ; INT 0x0D General Protection Fault
- mov esi,str_fault_0x0D
- jmp fault_jmp_unhandled
-; V86 IRET
-.v86_iret: mov eax,FLAT32_SEL
- mov es,ax ; we'll need flat mode for this
- ; retrieve CS:IP and FLAGS from 16-bit stack, increment stack pointer
- mov ax,word [esp+0x20+20] ; AX = SS (upper bits should be zero)
- shl eax,4 ; AX *= 16
- xor ecx,ecx
- mov cx,word [esp+0x20+16] ; CX = SP
- add eax,ecx ; AX += SP AX = (SS*16)+SP
-
- mov cx,word [es:eax] ; IP = SS:SP+0
- mov word [esp+0x20+4],cx ; IP
-
- mov cx,word [es:eax+2] ; CS = SS:SP+2
- mov word [esp+0x20+8],cx ; CS
-
- mov cx,word [es:eax+4] ; FLAGS = SS:SP+4
- mov word [esp+0x20+12],cx ; FLAGS
-
- add word [esp+0x20+16],6 ; (E)SP += 6
- jmp .v86_complete
-; V86 INT 66h
-.v86_int_api: popad
- cmp eax,0xAABBAA55
- jz .v86_int_api_detect
- cmp eax,0xAABBAABB
- jz .v86_int_api_unload
- int 3
-.v86_int_api_detect:
- mov eax,0xBBAABB33
- jmp .v86_complete_no_popad
-.v86_int_api_unload:
- mov ax,word [esp+4] ; save IP
- mov bx,word [esp+8] ; save CS
- mov [unload_int_ret+0],ax
- mov [unload_int_ret+2],bx
-
- mov ax,word [esp+16] ; save SP
- mov bx,word [esp+20] ; save SS
- mov [unload_int_stk+0],ax
- mov [unload_int_stk+2],bx
-
- jmp v86_api_exit
-; V86 INT 3 (AL = 0xCC)
-.v86_int3: mov ah,0x03 ; convert to INT 3 (CD 03)
- inc dword [esp+0x20+4] ; step past (EIP++)
- jmp short .v86_int_n
-; V86 INT x (AL = 0xCD AH = N)
-.v86_int: add dword [esp+0x20+4],2 ; EIP += 2
-; V86 INT REFLECTION TO REAL MODE
-.v86_int_n: movzx ebx,ah ; EBX = interrupt number
- ; *DEBUG*
- cmp bl,RM_INT_API
- jz .v86_int_api
- ; *END DEBUG*
- mov eax,FLAT32_SEL
- mov es,ax ; we'll need flat mode for this
- ; store CS:IP and FLAGS on 16-bit stack, decrement stack pointer. DO NOT MODIFY EBX
- sub word [esp+0x20+16],6 ; (E)SP -= 6
- mov ax,word [esp+0x20+20] ; AX = SS (upper bits should be zero)
- shl eax,4 ; AX *= 16
- xor ecx,ecx
- mov cx,word [esp+0x20+16] ; CX = SP
- add eax,ecx ; AX += SP AX = (SS*16)+SP
- mov cx,word [esp+0x20+4] ; IP
- mov word [es:eax],cx ; SS:SP+0 = IP
- mov cx,word [esp+0x20+8] ; CS
- mov word [es:eax+2],cx ; SS:SP+2 = CS
- mov cx,word [esp+0x20+12] ; FLAGS
- mov word [es:eax+4],cx ; SS:SP+4 = FLAGS
- ; replace CS:IP with values from real-mode interrupt table (EBX = interrupt vector)
- mov ax,[es:(ebx*4)] ; read from real-mode interrupt table (offset)
- mov word [esp+0x20+4],ax ; replace EIP
- mov ax,[es:(ebx*4)+2] ; .... (segment)
- mov word [esp+0x20+8],ax ; replace CS
- jmp .v86_complete
-; V86 CLI
-.v86_cli: inc dword [esp+0x20+4] ; step past (EIP++)
- and word [esp+0x20+12],~0x200
- jmp .v86_complete_and_check_pending_irq
-; V86 STI
-.v86_sti: inc dword [esp+0x20+4] ; step past (EIP++)
- or word [esp+0x20+12],0x200
- jmp .v86_complete_and_check_pending_irq
-; V86 HLT
-.v86_hlt: inc dword [esp+0x20+4] ; step past (EIP++)
- test word [esp+0x20+12],0x200
- jz .v86_hlt_with_cli
- jmp .v86_complete_and_check_pending_irq
-; V86 HLT with interrupts disabled
-.v86_hlt_with_cli:
- popad ; undo v86 check stack
- call fault_collect_regs
- mov edx,0x0D
- mov esi,str_v86_hlt_cli
- jmp fault_jmp_unhandled
-; V86 PUSHF
-.v86_pushf: mov eax,FLAT32_SEL
- mov es,ax
- inc dword [esp+0x20+4] ; step past (EIP++)
- sub word [esp+0x20+16],2 ; (E)SP -= 2
- mov ax,word [esp+0x20+20] ; AX = SS (upper bits should be zero)
- shl eax,4 ; AX *= 16
- xor ecx,ecx
- mov cx,word [esp+0x20+16] ; CX = SP
- add eax,ecx ; AX += SP AX = (SS*16)+SP
- mov cx,word [esp+0x20+12] ; FLAGS
- mov word [es:eax],cx ; SS:SP+0 = FLAGS
- jmp .v86_complete
-; V86 PUSHFD
-.v86_pushfd: mov eax,FLAT32_SEL
- mov es,ax
- add dword [esp+0x20+4],2 ; step past (EIP += 2)
- sub word [esp+0x20+16],4 ; (E)SP -= 4
- mov ax,word [esp+0x20+20] ; AX = SS (upper bits should be zero)
- shl eax,4 ; AX *= 16
- xor ecx,ecx
- mov cx,word [esp+0x20+16] ; CX = SP
- add eax,ecx ; AX += SP AX = (SS*16)+SP
- mov ecx,dword [esp+0x20+12] ; EFLAGS
- mov dword [es:eax],ecx ; SS:SP+0 = FLAGS
- jmp .v86_complete
-; V86 POPF
-.v86_popf: mov eax,FLAT32_SEL
- mov es,ax
- inc dword [esp+0x20+4] ; step past (EIP++)
- mov ax,word [esp+0x20+20] ; AX = SS (upper bits should be zero)
- shl eax,4 ; AX *= 16
- xor ecx,ecx
- mov cx,word [esp+0x20+16] ; CX = SP
- add eax,ecx ; AX += SP AX = (SS*16)+SP
- mov cx,word [es:eax] ; FLAGS = SS:SP+0
- mov word [esp+0x20+12],cx ; FLAGS
- add word [esp+0x20+16],2 ; (E)SP += 2
- jmp .v86_complete_and_check_pending_irq
-; V86 POPFD
-.v86_popfd: mov eax,FLAT32_SEL
- mov es,ax
- add dword [esp+0x20+4],2 ; step past (EIP += 2)
- mov ax,word [esp+0x20+20] ; AX = SS (upper bits should be zero)
- shl eax,4 ; AX *= 16
- xor ecx,ecx
- mov cx,word [esp+0x20+16] ; CX = SP
- add eax,ecx ; AX += SP AX = (SS*16)+SP
- mov ecx,dword [es:eax] ; EFLAGS = SS:SP+0
- or ecx,0x20000 ; make sure the VM bit is set
- mov dword [esp+0x20+12],ecx ; EFLAGS
- add word [esp+0x20+16],4 ; (E)SP += 4
- jmp .v86_complete_and_check_pending_irq
-; UNKNOWN OPCODE AT CS:IP in V8086 MODE
-.v86_unknown: popad ; undo v86 check stack
- add esp,4 ; toss real error code
- push dword [v86_raw_opcode] ; the "ERROR CODE" are the 4 bytes at CS:IP
- call fault_collect_regs
- mov edx,0x0D
- mov esi,str_v86_unknown
- jmp fault_jmp_unhandled
-; API CALL TO SHUTDOWN VM86 MONITOR
-v86_api_exit: mov ax,FLAT32_SEL
- mov es,ax
- mov ax,DATA32_SEL
- mov ds,ax
-; FIXME: I give up... why does JMPing to TSS_SEL:0 cause random crashes in VirtualBox?
- jmp _exit_from_prot32 ; and then begin shutdown of this program
-
-; ========== FAULT COLLECTION ROUTINE. SS:ESP should point to fault. If the exception does not push an error code,
-; then the caller must push a dummy error code
-fault_collect_regs:
- push ds
- push eax
- push ebx
- mov ax,ds
- mov bx,ax
- mov ax,DATA32_SEL
- mov ds,ax
- mov word [unhandled_fault_var_ds],bx
- pop ebx
-
- mov eax,[esp+4+8+0] ; ERROR CODE ON STACK +2 DWORDs PUSHED
- mov dword [unhandled_fault_var_errcode],eax
-
- mov eax,[esp+4+8+4] ; EIP ON STACK
- mov dword [unhandled_fault_var_eip],eax
-
- mov eax,[esp+4+8+8] ; CS ON STACK
- mov word [unhandled_fault_var_cs],ax
-
- mov eax,[esp+4+8+12] ; EFLAGS ON STACK
- mov dword [unhandled_fault_var_eflags],eax
-
- call .retr_stack_ptr
-
- pop eax
-
- mov dword [unhandled_fault_var_eax],eax
- mov dword [unhandled_fault_var_ebx],ebx
- mov dword [unhandled_fault_var_ecx],ecx
- mov dword [unhandled_fault_var_edx],edx
- mov dword [unhandled_fault_var_esi],esi
- mov dword [unhandled_fault_var_edi],edi
- mov dword [unhandled_fault_var_ebp],ebp
-
- mov eax,cr0
- mov dword [unhandled_fault_var_cr0],eax
- mov eax,cr3
- mov dword [unhandled_fault_var_cr3],eax
- mov eax,cr4
- mov dword [unhandled_fault_var_cr4],eax
- mov ax,es
- mov word [unhandled_fault_var_es],ax
- mov ax,fs
- mov word [unhandled_fault_var_fs],ax
- mov ax,gs
- mov word [unhandled_fault_var_gs],ax
- pop ds
- ret
-; if privilege escalation was involved (stack switching) then retrieve SS:ESP at fault from the stack frame.
-; else retrieve from actual SS:ESP registers
-.retr_stack_ptr:
- test word [unhandled_fault_var_cs],3 ; if code segment is nonzero
- jz .retr_stack_ptr_ring_0
-
- mov eax,[esp+4+4+8+16] ; ESP ON STACK
- mov dword [unhandled_fault_var_esp],eax
-
- mov eax,[esp+4+4+8+20] ; SS ON STACK
- mov word [unhandled_fault_var_ss],ax
-
- ret
-.retr_stack_ptr_ring_0:
- lea eax,[esp+4+4+8+16] ; +4 our call frame, +8 PUSH DS,EAX +16 GPF stack frame
- mov dword [unhandled_fault_var_esp],eax
-
- mov eax,ss ; SS ON STACK
- mov word [unhandled_fault_var_ss],ax
-
- ret
-
-fault_jmp_unhandled:
- jmp CODE16_SEL:.thunk16
- bits 16
-.thunk16: mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,stack_init
- jmp unhandled_fault_errcode
- bits 32
-
-; ============= cleanup, exit to DOS (from 32-bit protected mode)
-_exit_from_prot32:
- jmp CODE16_SEL:.entry16
- bits 16
-.entry16: mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov esp,stack_init
-
-; ============= cleanup, exit to DOS (from 16-bit protected mode)
-_exit_from_prot16:
- mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,stack_init
- ; overwrite the far jmp's segment value
- mov ax,[my_realmode_seg]
- mov word [.real_hackme+3],ax
- lidt [idtr_real]
- lgdt [gdtr_real]
- xor eax,eax
- mov cr0,eax
-.real_hackme: jmp 0:.real_entry
-.real_entry: mov ax,[my_realmode_seg]
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,stack_init
-
-; reprogram the PIC back to what normal DOS expects: IRQ 0-7 => INT 8-15
- mov al,0x10 ; ICW1 A0=0
- out 20h,al
- mov al,0x08 ; ICW2 A0=1
- out 21h,al
- mov al,0x04 ; ICW3 A0=1 slave on IRQ 2
- out 21h,al
-
-; remove our INT 66h API
- xor ax,ax
- mov es,ax
- mov word [es:(RM_INT_API*4)],ax
- mov word [es:(RM_INT_API*4)+2],ax
-
-; free HIMEM.SYS blocks
- mov ah,0Dh ; HIMEM.SYS function 0Dh unlock memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
- mov ah,0Ah ; HIMEM.SYS function 0Ah free memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
-
-; if we already exited as a TSR...
- test byte [i_am_tsr],1
- jnz .tsr_exit
-
-; time to exit to DOS
- mov dx,str_exit_to_dos
- jmp _exit_with_msg
-
-; ============= ALTERNATE EXIT IF WE ALREADY EXITED AS TSR
-.tsr_exit:
- mov ax,cs
- mov es,ax ; ES = our code segment which is also our PSP segment
- mov ah,0x49 ; function 49h free memory block
- clc
- int 21h
- jnc .tsr_exit_free_ok
- mov dx,str_cannot_free_self
- call dos_puts
-.tsr_exit_free_ok:
- cli
- mov ax,[cs:unload_int_stk+0] ; offset
- add ax,6 ; discard prior frame
- mov sp,ax
- mov ax,[cs:unload_int_stk+2] ; segment
- mov ss,ax
-
- mov dx,str_exit_to_dos
- call dos_puts
-
- jmp far word [cs:unload_int_ret]
-
-; ============= UNHANDLED FAULT HANDLER (16-bit code)
-; input: EDX = Number of interrupt
-; DS:SI = Textual string of fault
-; ESP = Stack containing:
-;
-unhandled_fault_errcode:
- cli
- mov ax,DATA16_SEL
- mov ds,ax
-
- mov ax,[cs:my_realmode_seg]
- mov word [.real16jmp+3],ax
-
- mov ax,FLAT16_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
-
- lgdt [cs:gdtr_real]
- lidt [cs:idtr_real]
-
- ; crash-thunk to real mode
- xor eax,eax
- mov cr0,eax
-.real16jmp: jmp 0:.real16
-.real16: mov ax,[cs:my_realmode_seg]
- mov ds,ax
- mov ss,ax
- xor ax,ax
- mov es,ax
-
- mov ax,3
- int 10h
-
- cld
- mov ax,0x4E20
- mov ecx,80*25
- mov edi,0xB8000
- a32 rep stosw
-
- ; print exception name on screen
- mov edi,0xB8000
- call .unhandled_print
- mov al,' ' ; +space plus AH still contains upper byte from .unhandled_print
- a32 stosw
-
- ; then the number (in EDX) write to DS:DI
- mov eax,edx
- push edi
- mov edi,scratch_str
- call eax_to_hex_16_dos
- lea si,[di+6] ; only the last two hex digits
- pop edi
- call .unhandled_print
-
- ; print the registers.
- ; during this loop: SI = print list EDI = location on screen to draw [ESP] = location on screen of row start
- mov edi,0xB8000+(160*2) ; two lines down
- push edi
- mov si,printlist_32
-.regprint32: lodsw
- or ax,ax
- jz .regprint32e ; AX=0 STOP
- dec ax
- jz .regprint32nl ; AX=1 GO TO NEW LINE
- push si
- mov si,ax ; SI=AX=address of variable name
- inc si
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (':')
- a32 stosw
- lodsw ; SI=address of variable
- push si
- mov si,ax
- mov eax,[si]
- push edi
- mov edi,scratch_str
- call eax_to_hex_16_dos
- mov esi,edi
- pop edi
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (' ')
- a32 stosw
- jmp .regprint32
-.regprint32nl: pop edi
- add edi,160 ; move to next line, save back to [ESP]
- push edi
- jmp .regprint32
-.regprint32e: pop edi
-
- add edi,160 ; next line...
-
- mov si,printlist_16
-.regprint16: lodsw
- or ax,ax
- jz .regprint16e ; AX=0 STOP
- dec ax
- jz .regprint16nl ; AX=1 GO TO NEW LINE
- push si
- mov si,ax ; SI=AX=address of variable name
- inc si
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (':')
- a32 stosw
- lodsw ; SI=address of variable
- push si
- mov si,ax
- xor eax,eax
- mov ax,[si]
- push edi
- mov edi,scratch_str
- call eax_to_hex_16_dos
- lea esi,[edi+4]
- pop edi
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (' ')
- a32 stosw
- jmp .regprint16
-.regprint16nl: pop edi
- add edi,160 ; move to next line, save back to [ESP]
- push edi
- jmp .regprint16
-.regprint16e: mov si,str_mode_prot ; CPU mode
- test dword [unhandled_fault_var_eflags],0x20000
- jz .regprint_cpu_mode_not_v86
- mov si,str_mode_v86
-.regprint_cpu_mode_not_v86:
- call .unhandled_print
- pop edi
-
- mov al,020h
-
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
-
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
-
- sti
- jmp short $
-; ===== print on screen from DS:SI to ES:EDI
-.unhandled_print:
- lodsb
- cmp al,'$'
- jz .unhandled_printe
- mov ah,0x4E
- a32 stosw
- jmp .unhandled_print
-.unhandled_printe:
- ret
-
-; ============= Entry point (virtual 8086 mode)
-vm86_entry: cli ; make sure the v86 monitor handles CLI
- sti ; ...and STI
- pushf ; ...and PUSHF
- popf ; ...and POPF
- pushfd ; ...32-bit PUSHF
- popfd ; ...32-bit POPF
- in al,21h ; ...IN?
- out 21h,al ; ...OUT?
-
- ; NOW MAKE SURE PUSHF/POPF STORE THE VALUE ON-STACK LIKE THEY'RE SUPPOSED TO
- mov bx,sp
- mov word [ss:bx-2],0x5A5A
- pushf
- mov bx,sp
- cmp word [ss:bx],0x5A5A
- jnz .pushf_ok ; if the value DIDN'T CHANGE then the monitor failed to write FLAGS to stack
- mov ax,0
- jmp vm86_errcode
-.pushf_ok:
-
- ; DOES POPF WORK?
- mov ax,0x492
- push ax
- popf
- pushf
- pop ax
- and ax,0xFD6
- cmp ax,0x492
- jz .popf_ok
- mov ax,1
- jmp vm86_errcode
-.popf_ok:
-
- ; TEST 32-bit PUSHF
- mov bx,sp
- mov dword [ss:bx-4],0x5A5A5A5A
- pushfd
- mov bx,sp
- cmp dword [ss:bx],0x5A5A5A5A
- jnz .pushfd_ok ; if the value DIDN'T CHANGE then the monitor failed to write FLAGS to stack
- mov ax,2
- jmp vm86_errcode
-.pushfd_ok:
-
- ; DOES POPFD WORK?
- mov eax,0x492
- push eax
- popfd
- pushfd
- pop eax
- and eax,0xFD6
- cmp eax,0x492
- jz .popfd_ok
- mov ax,3
- jmp vm86_errcode
-.popfd_ok:
-
- ; IF I CLEAR INTERRUPT (CLI) AND THEN EXECUTE AN INTERRUPT, DOES IT COME BACK ENABLED?
- cli
- mov ah,0x0F ; INT 10 AH=0x0F which has no visisible effect
- int 10h
- pushf
- pop ax
- test ax,0x200
- jz .int_doesnt_enable
- mov ax,4
- jmp vm86_errcode
-.int_doesnt_enable:
-
- ; HELLO WORLD!
- mov si,str_vm86_hello
- call bios_puts
-
- ; TEST DEFERRED IRQ MECHANISM BY DELIBERATLEY HALTING FOR AWHILE
- cli
- mov ecx,0x1000000 ; delibrate slow countdown loop
-.l1: dec ecx
- jnz .l1
- sti
-
- ; for my next trick, I will exit to DOS as a TSR
- ; and allow the user to run the whole DOS kernel this way :)
- mov es,[cs:0x2C] ; locate our environment block and free it
- mov ah,0x49 ; function 49h free memory block
- int 21h
- jnc .env_free_ok
- mov ax,4
- jmp vm86_errcode
-.env_free_ok: mov word [cs:0x2C],0 ; rub out the ENV block
-
- ; setup our INT 66h API
- xor ax,ax
- mov es,ax
- mov word [es:(RM_INT_API*4)],realmode_api_entry
- mov ax,cs
- mov word [es:(RM_INT_API*4)+2],ax
-
- ; finally, terminate and stay resident
- mov byte [i_am_tsr],1
- mov edx,the_end ; DX = memory in paragraphs to save
- add edx,15
- shr edx,4
- add edx,16 ; <-- FIXME: IS THIS NECESSARY
- mov ah,0x31 ; function 31h terminate and stay resident
- int 21h
-
-; ============= "Secret Handshake" to exit back into the v86 monitor and shutdown the program (virtual 8086 mode)
-; TODO: Remove this, call into RM_INT_API instead
-vm86_exit: mov eax,0xAABBAABB
- int RM_INT_API
- hlt
-
-; ============= If any of our self-test fails, we draw DIRECTLY ON VGA RAM and hike back into the vm86 monitor ASAP.
-; if self-tests fail chances are calling the BIOS/DOS will cause major problems. AX=CODE
-vm86_errcode: mov bx,0xB800
- mov es,bx
- and ax,0xF
- or ax,0x4E30 ; AX = VGA alphanumeric code for that number
- mov [es:160],ax
- jmp vm86_exit
-
-; ============= Real-mode API entry (reflect to v86 monitor by executing an INT)
-; this would allow the trick to work even for programs that direct-call instead
-realmode_api_entry:
- int RM_INT_API
- iret
-
-; ============= Parse command line (from PSP segment)
-parse_argv: cld
- mov si,81h
-.scan: lodsb
- or al,al
- jz .done
- cmp al,0Dh
- jz .done
- cmp al,20h
- jz .scan
- cmp al,'-'
- jz .switch
- cmp al,'/'
- jz .switch
- ; FALL THROUGH WITH ZF=0 to return
-.done: ret
- ; AT THIS POINT: SI = just after the / or - in the switch
-.switch: lodsb
- cmp al,'?'
- jz .help
- cmp al,'A'
- jb .unknown_switch
- cmp al,'Z'
- ja .unknown_switch
- ; the A-Z switches are allowed to have "=NNNN" after them where N is some integer in hex or decimal
- sub al,'A'
- mov bl,al
- xor bh,bh ; BX = index into lookup table
- add bx,bx
- jmp word [bx+.switch_az]
-.fail: mov al,1
-.help: or al,al ; AL != 0 => ZF=0
- ret
-.unknown_switch:mov dx,str_unknown_switch
- call dos_puts
- lea dx,[si-2] ; step back two chars
- mov byte [si],'$'
- call dos_puts
- mov dx,str_crlf
- call dos_puts
- jmp .fail
-; ========== Switches CALL here if they need a numeric value to follow.
-; returns to caller if so, parsing as 16-bit integer returned in EAX. Else,
-; it discards the return address and jumps to the 'needs param' error message.
-.switch_needs_equ_check:
- cmp byte [si],'='
- jnz .switch_needs_equ_check_fail
- inc si
- cli
- xor eax,eax
- call ax_strtol_16
- ret
-.switch_needs_equ_check_fail:
- add sp,2 ; fall through
-.switch_needs_equ:
- mov dx,str_needs_equals
- call dos_puts
- jmp .fail
-; ========== /B=<number>
-.switch_buffer_size:
- call .switch_needs_equ_check
- shl eax,10
- mov [himem_sys_buffer_size],eax
- jmp .scan
-; ========== /U
-.switch_unload: mov byte [user_req_unload],1
- jmp .scan
-; ========== /I
-.switch_iopl: mov byte [user_req_iopl],0
- jmp .scan
-; switch A-Z jump table
-.switch_az: dw .unknown_switch ; /A
- dw .switch_buffer_size ; /B=<number>
- dw .unknown_switch ; /C
- dw .unknown_switch ; /D
- dw .unknown_switch ; /E
- dw .unknown_switch ; /F
- dw .unknown_switch ; /G
- dw .unknown_switch ; /H
- dw .switch_iopl ; /I
- dw .unknown_switch ; /J
- dw .unknown_switch ; /K
- dw .unknown_switch ; /L
- dw .unknown_switch ; /M
- dw .unknown_switch ; /N
- dw .unknown_switch ; /O
- dw .unknown_switch ; /P
- dw .unknown_switch ; /Q
- dw .unknown_switch ; /R
- dw .unknown_switch ; /S
- dw .unknown_switch ; /T
- dw .switch_unload ; /U
- dw .unknown_switch ; /V
- dw .unknown_switch ; /W
- dw .unknown_switch ; /X
- dw .unknown_switch ; /Y
- dw .unknown_switch ; /Z
-
-irq_routines: dw irq_0
- dw irq_1
- dw irq_2
- dw irq_3
- dw irq_4
- dw irq_5
- dw irq_6
- dw irq_7
- dw irq_8
- dw irq_9
- dw irq_10
- dw irq_11
- dw irq_12
- dw irq_13
- dw irq_14
- dw irq_15
-
-fault_routines: dw fault_0x00
- dw fault_0x01
- dw fault_0x02
- dw fault_0x03
- dw fault_0x04
- dw fault_0x05
- dw fault_0x06
- dw fault_0x07
- dw fault_0x08
- dw fault_0x09
- dw fault_0x0A
- dw fault_0x0B
- dw fault_0x0C
- dw fault_0x0D
- dw fault_0x0E
- dw fault_0x0F
- dw fault_0x10
- dw fault_0x11
- dw fault_0x12
- dw fault_0x13
- dw fault_0x14
- dw fault_0x15
- dw fault_0x16
- dw fault_0x17
- dw fault_0x18
- dw fault_0x19
- dw fault_0x1A
- dw fault_0x1B
- dw fault_0x1C
- dw fault_0x1D
- dw fault_0x1E
- dw fault_0x1F
-
-
-; register print list
-printlist_32: dw str_eax, unhandled_fault_var_eax
- dw str_ebx, unhandled_fault_var_ebx
- dw str_ecx, unhandled_fault_var_ecx
- dw str_edx, unhandled_fault_var_edx
- dw str_esi, unhandled_fault_var_esi
- dw str_edi, unhandled_fault_var_edi
- dw 1
- dw str_ebp, unhandled_fault_var_ebp
- dw str_esp, unhandled_fault_var_esp
- dw str_eip, unhandled_fault_var_eip
- dw str_eflags, unhandled_fault_var_eflags
- dw str_errcode, unhandled_fault_var_errcode
- dw str_cr0, unhandled_fault_var_cr0
- dw 1
- dw str_cr3, unhandled_fault_var_cr3
- dw str_cr4, unhandled_fault_var_cr4
- dw 0
-printlist_16: dw str_cs, unhandled_fault_var_cs
- dw str_ds, unhandled_fault_var_ds
- dw str_es, unhandled_fault_var_es
- dw str_fs, unhandled_fault_var_fs
- dw str_gs, unhandled_fault_var_gs
- dw str_ss, unhandled_fault_var_ss
- dw 0
-
-; ============= bios_puts (print $-terminated string at DS:SI)
-bios_puts: cli
- cld
- push ax
- push bx
-.putsloop: lodsb
- cmp al,'$'
- jz .putsend
- mov ah,0x0E
- xor bx,bx
- int 10h
- jmp .putsloop
-.putsend: pop bx
- pop ax
- ret
-
-; ============= dos_puts (print $-terminated string at DS:DX)
-dos_puts: mov ah,09h
- int 21h
- ret
-
-; ============= read one digit from DS:SI return in AX (16-bit code)
-ax_strtol_16_single:mov al,[si]
- cmp al,'0'
- jb .no
- cmp al,'9'
- ja .no
- sub al,'0'
- xor ah,ah
- inc si
- clc
- ret
-.no: stc
- ret
-
-; ============= read from DS:SI and convert numerical string to integer value return in AX (16-bit code)
-ax_strtol_16: xor cx,cx
-.loop: push cx
- call ax_strtol_16_single
- pop cx
- jc .done
- mov bx,cx
- add bx,bx
- shl cx,3 ; BX = CX * 2, CX *= 8
- add cx,bx ; CX = (CX * 8) + (CX * 2) = CX * 10
- add cx,ax ; CX += new digit
- jmp .loop
-.done: mov ax,cx
- ret
-
-; ============= take AX and write to buffer (DS:SI) as hexadecimal string (16-bit code)
-al_to_hex_16_dos:mov byte [di+2],'$'
- jmp al_to_hex_16
-al_to_hex_16_nul:mov byte [di+2],0
-al_to_hex_16: push di
- push bx
- push ax
- xor bh,bh
- mov ah,al
- and al,0xF
- mov bl,al
- mov al,[bx+str_hex] ; AL' = str_hex[al]
- shr ah,4
- mov bl,ah
- mov ah,[bx+str_hex] ; AH' = str_hex[ah]
- mov [di+0],ah
- mov [di+1],al
- pop ax
- pop bx
- pop di
- ret
-
-; ============= take AX and write to buffer (DS:SI) as hexadecimal string (16-bit code)
-ax_to_hex_16_dos:mov byte [di+4],'$'
- jmp ax_to_hex_16
-ax_to_hex_16_nul:mov byte [di+4],0
-ax_to_hex_16: push di
- push ax
- mov al,ah
- call al_to_hex_16
- pop ax
- add di,2
- call al_to_hex_16
- pop di
- ret
-
-; ============= take EAX and write to buffer (DS:DI) as hexadecimal string (16-bit code)
-eax_to_hex_16_dos:mov byte [di+8],'$'
- jmp eax_to_hex_16
-eax_to_hex_16_nul:mov byte [di+8],0
-eax_to_hex_16: push di
- push eax
- shr eax,16
- call ax_to_hex_16
- pop eax
- add di,4
- call ax_to_hex_16
- pop di
- ret
-
-; ============= /U Unloading the resident copy of this program
-unload_this_program:
- smsw ax
- test al,1
- jnz .v86_active
- mov dx,str_not_loaded
- jmp _exit_with_msg
-.v86_active:
- xor ax,ax
- mov es,ax
- mov bx,[es:(RM_INT_API*4)]
- or cx,[es:(RM_INT_API*4)+2]
- cmp cx,0 ; if pointer is 0000:0000
- jz .v86_not_me
- mov eax,0xAABBAA55
- int RM_INT_API
- cmp eax,0xBBAABB33
- jnz .v86_not_me
-.v86_is_me: mov ax,cs
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov dx,str_removing_self
- call dos_puts
-; instruct it to remove itself
- mov eax,0xAABBAABB
- int RM_INT_API
-; exit, having done our job
- mov dx,str_crlf
- call dos_puts
- mov dx,str_unloaded
- jmp _exit_with_msg
-.v86_not_me: mov dx,str_v86_but_not_me
- jmp _exit_with_msg
-
-; ============= DATA: THESE EXIST IN THE .COM BINARY IMAGE
- section .data align=2
-himem_sys_buffer_size:dd (256*1024) ; DWORD [amount of extended memory to allocate]
-str_require_386:db '386 or higher required$'
-str_removing_self:db 'Removing from memory',13,10,'$'
-str_v86_detected:db 'Virtual 8086 mode already active$'
-str_v86_but_not_me:db 'Virtual 8086 active, and its not me$'
-str_not_loaded: db 'Not resident in memory$'
-str_cannot_free_self:db 'Cannot free self from memory$'
-str_need_himem_sys:db 'HIMEM.SYS not installed$'
-str_himem_a20_error:db 'HIMEM.SYS failed to enable A20$'
-str_himem_alloc_err:db 'Unable to alloc extended memory$'
-str_himem_lock_err:db 'Unable to lock extended memory$'
-str_buffer_too_small:db 'Buffer too small$'
-str_buffer_too_large:db 'Buffer too large$'
-str_unloaded: db 'Unloaded',13,10,'$'
-str_buffer_at: db 'Buffer at: $'
-str_crlf: db 13,10,'$'
-str_hex: db '0123456789ABCDEF'
-str_help: db 'V86KERN [options]',13,10
- db 'Demonstration Virtual 8086 kernel/monitor',13,10
- db 13,10
- db 'Options start with - or /',13,10
- db ' /? Show this help',13,10
- db ' /B=... Set buffer size (in KB)',13,10
- db ' /U Unload the kernel',13,10
- db ' /I Run with IOPL=3 (trap CLI/STI/etc)',13,10
- db '$'
-str_unknown_switch:db 'Unknown switch $'
-str_needs_equals:db 'Switch missing =...$'
-str_eax: db 'EAX$'
-str_ebx: db 'EBX$'
-str_ecx: db 'ECX$'
-str_edx: db 'EDX$'
-str_esi: db 'ESI$'
-str_edi: db 'EDI$'
-str_ebp: db 'EBP$'
-str_esp: db 'ESP$'
-str_eip: db 'EIP$'
-str_errcode: db 'ERR$'
-str_eflags: db 'FLG$'
-str_cr0: db 'CR0$'
-str_cr3: db 'CR3$'
-str_cr4: db 'CR4$'
-str_cs: db 'CS$'
-str_ds: db 'DS$'
-str_es: db 'ES$'
-str_fs: db 'FS$'
-str_gs: db 'GS$'
-str_ss: db 'SS$'
-str_mode_prot: db 'Protected mode$'
-str_mode_v86: db 'Virtual 8086 mode$'
-str_vm86_hello: db 'This text was printed by the Virtual 8086 mode component of this program',13,10,'$'
-str_fault_0x00: db 'Divide by Zero$'
-str_fault_0x01: db 'Debug$'
-str_fault_0x02: db 'NMI$'
-str_fault_0x03: db 'Breakpoint$'
-str_fault_0x04: db 'Overflow$'
-str_fault_0x05: db 'Boundary Check$'
-str_fault_0x06: db 'Invalid Opcode$'
-str_fault_0x07: db 'Coprocessor N/A$'
-str_fault_0x08: db 'Double Fault$'
-str_fault_0x09: db 'Coprocessor Segment Overrun$'
-str_fault_0x0A: db 'Invalid TSS$'
-str_fault_0x0B: db 'Segment Not Present$'
-str_fault_0x0C: db 'Stack Fault$'
-str_fault_0x0D: db 'General Protection Fault$'
-str_fault_0x0E: db 'Page Fault$'
-str_fault_0x0F: db 'Exception F$'
-str_fault_0x10: db 'FPU Error$'
-str_fault_0x11: db 'Alignment Check$'
-str_fault_0x12: db 'Machine Check$'
-str_fault_0x13: db 'SIMD/SSE Exception$'
-str_fault_unknown:db 'Unknown exception$'
-str_v86_unknown:db 'Unknown instruction in v86 mode$'
-str_v86_hlt_cli:db 'v86 halt with interrupts disabled$'
-str_v86_secret: db 'Inappropriate use of v86 secret handshake$'
-str_exit_to_dos:db 'Shutdown successful, exiting to DOS$'
-str_irq_deferred:db 'Deferred IRQ$'
-str_irq_1: db 'IRQ #1$'
-
-; ============= VARIABLES: THESE DO NOT EXIST IN THE .COM FILE THEY EXIST IN MEMORY FOLLOWING THE BINARY IMAGE
- section .bss align=2
-; ---------------------- STACK
-stack_base: resb 4096 ; char[4096+4]
-stack_init: resd 1 ; DWORD
-stack_top:
-scratch_str: resb 64 ; char[64]
-; ---------------------- STACK
-stack_base_vm86:resb 4096 ; char[4096+4]
-stack_init_vm86:resd 2 ; DWORD
-stack_top_vm86:
-; ---------------------- HIMEM.SYS state
-himem_sys_entry:resd 1 ; FAR POINTER
-himem_sys_buffer_phys:resd 1 ; DWORD [physical memory address]
-himem_sys_buffer_handle:resw 1 ; WORD [HIMEM.SYS handle]
-; ---------------------- my real mode segment
-my_realmode_seg:resw 1 ; WORD
-my_phys_base: resd 1 ; DWORD
-tss_phys_base: resd 1 ; DWORD base logical address of TSS
-tss_vm86_phys_base:resd 1 ; DWORD base logical address of TSS
-buffer_alloc: resd 1 ; DWORD
-kern32_stack_base:resd 1 ; DWORD
-kern32_stack_top:resd 1 ; DWORD
-v86_raw_opcode: resd 1 ; DWORD
- resd 1 ; *PADDING*
-; ---------------------- GDTR/IDTR
-gdtr_pmode: resq 1 ; LIMIT. BASE
-gdtr_real: resq 1 ; LIMIT, BASE
-idtr_pmode: resq 1 ; LIMIT, BASE
-idtr_real: resq 1 ; LIMIT, BASE
-; ---------------------- GLOBAL DESCRIPTOR TABLE
- align 8
-gdt: resq (MAX_SEL/8) ; 16 GDT entries
-; ---------------------- INTERRUPT DESCRIPTOR TABLE
- align 8
-idt: resq 256 ; all 256
-; ---------------------- STATE
-irq_pending: resw 1
-v86_if: resb 1
-user_req_unload:resb 1
-user_req_iopl: resb 1
-i_am_tsr: resb 1
-unload_int_ret: resd 1
-unload_int_stk: resd 1
-; ---------------------- WHEN DISPLAYING THE UNHANDLED FAULT DIALOG
-unhandled_fault_var_errcode:resd 1
-unhandled_fault_var_eax:resd 1
-unhandled_fault_var_ebx:resd 1
-unhandled_fault_var_ecx:resd 1
-unhandled_fault_var_edx:resd 1
-unhandled_fault_var_esi:resd 1
-unhandled_fault_var_edi:resd 1
-unhandled_fault_var_ebp:resd 1
-unhandled_fault_var_esp:resd 1
-unhandled_fault_var_eip:resd 1
-unhandled_fault_var_eflags:resd 1
-unhandled_fault_var_cr0:resd 1
-unhandled_fault_var_cr3:resd 1
-unhandled_fault_var_cr4:resd 1
-unhandled_fault_var_cs:resw 1
-unhandled_fault_var_ds:resw 1
-unhandled_fault_var_es:resw 1
-unhandled_fault_var_fs:resw 1
-unhandled_fault_var_gs:resw 1
-unhandled_fault_var_ss:resw 1
-; ---------------------------------------------------------------------
-; END POINTER
-; ---------------------------------------------------------------------
-padding: resq 2 ; SAFETY PADDING
-the_end:
+++ /dev/null
-; v86kern2.asm
-;
-; Test program: Proof-of-concept minimalist virtual 8086 "monitor"
-; (C) 2010-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-;
-;
-; MODE: 16-bit real mode MS-DOS .COM executable
-; Assumes DS == ES == SS
-
-; NOTES:
-; - This works... for the most part.
-; - Somehow this works even with DOSBox's funky ROM-based interrupt emulation
-; - The emulation provided is sufficient for real-mode exceptions including INT 3h debug and
-; INT 1h trace. It also handles the correct exception to permit DOS programs to use the
-; FPU if present.
-; - This program also demonstrates a minimal I/O port trapping implementation. In this example,
-; port 0x64 (keyboard controller command port) and port 0x92 (PS/2 & AT Port A) are intercepted
-; to ensure that whatever the program does, the A20 gate is always enabled. This resolves the
-; random crashes observed in Windows 95 DOS mode where HIMEM.SYS and the DOS kernel were
-; apparently playing around with the A20 line.
-;
-; FIXME:
-; - Privileged instructions like mov cr0,<reg> trigger an exception and this program makes no
-; attempt to emulate those instructions.
-;
-; - Whatever the BIOS does in response to CTRL+ALT+DEL it doesn't work well when we are active.
-;
-; - Incomplete VCPI implementation and EMM emulation with no pages to alloc
-;
-; - Paging is not enabled
-;
-; OTHER NOTES:
-; - This code makes no attempt to emulate the LDT manipulation that most BIOS implementations
-; apparently like to do when handling INT 15H extended memory copy. Programs that use extended
-; memory via HIMEM.SYS or via INT 15H will crash. [FIXED: VM86 monitor intercepts INT 15H
-; calls. If the function call is for extended memory copy, the VM86 monitor will carry out
-; the copy itself and return].
-
-; Standard selectors in protected mode
-NULL_SEL equ (0 << 3)
-CODE16_SEL equ (1 << 3)
-DATA16_SEL equ (2 << 3)
-CODE32_SEL equ (3 << 3)
-DATA32_SEL equ (4 << 3)
-FLAT16_SEL equ (5 << 3)
-FLAT32_SEL equ (6 << 3)
-LDT_SEL equ (7 << 3)
-TSS_SEL equ (8 << 3)
-TSS_VM86_SEL equ (9 << 3)
-MAX_SEL equ (10 << 3)
-
-; We reprogram the PIC to direct IRQ 0-15 to this base interrupt
-RM_INT_API equ 0xEF
-IRQ_BASE_INT equ 0xF0
-
-; Extensible virtual 8086 mode kernel for DOS
-; (C) 2011 Jonathan Campbell
-
- bits 16
- section .code
- [map v86kern2.map]
- org 0x100
-
-; ============= ENTRY POINT
- mov ax,cs
- mov word [my_realmode_seg],ax
- mov bp,stack_base
- mov sp,stack_init ; SP is normally at 0xFFF0 so move it back down
- mov word [himem_sys_buffer_handle],0
- mov word [himem_sys_buffer_phys+2],0
- mov word [himem_sys_buffer_phys],0
- mov word [himem_sys_entry+2],0
- mov word [himem_sys_entry],0
- mov byte [user_req_unload],0
- mov byte [user_req_iopl],3
- mov byte [irq_pending],0
- mov byte [i_am_tsr],0
- mov byte [v86_if],0
- jmp _entry
-
-; ============= CPU DETECT
-cpu_is_386: pushf
- pop ax
- and ax,0x0FFF
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- cmp ax,0xF000
- jz cpu_is_386_not
-; 286 test: EFLAGS will always have bits 12-15 clear
- or ax,0xF000
- push ax
- popf
- pushf
- pop ax
- and ax,0xF000
- jz cpu_is_386_not
-; it's a 386
- xor ax,ax ; ZF=1
- ret
-cpu_is_386_not: mov ax,1
- or ax,ax ; ZF=0
- ret
-
-; ============= EXIT WITH MESSAGE ($-terminated string at DS:DX)
-_exit_with_msg: mov ah,9
- int 21h ; fall through to _exit
-; ============= EXIT
-_exit: mov ax,cs
- mov ds,ax
- cmp word [himem_sys_buffer_handle],0 ; if there is a handle to free, then do it
- jz .no_handle
- mov ah,0Dh ; HIMEM.SYS function 0Dh unlock memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
- mov ah,0Ah ; HIMEM.SYS function 0Ah free memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
-.no_handle: mov ax,4C00h
- int 21h
-
-; ============= PROGRAM STARTS HERE
-_entry: call parse_argv
- jz .argv_ok
- mov dx,str_help
- call _exit_with_msg
-.argv_ok: call cpu_is_386 ; CHECK: 386 or higher
- jz .is386
- mov dx,str_require_386
- jmp _exit_with_msg
-.is386: cmp byte [user_req_unload],0; CHECK: Did user request that we unload?
- jz .not_unload
- jmp unload_this_program
-.not_unload: smsw ax ; CHECK: Virtual 8086 mode not already enabled
- test al,1
- jz .not_v86
- mov dx,str_v86_detected
- jmp _exit_with_msg
-.not_v86: cmp dword [himem_sys_buffer_size],64*1024 ; CHECK: buffer size is 64KB or larger
- jge .buffer_size_large_enough
- mov dx,str_buffer_too_small
- jmp _exit_with_msg
-.buffer_size_large_enough:
- cmp dword [himem_sys_buffer_size],16*1024*1024
- jle .buffer_size_small_enough
- mov dx,str_buffer_too_large
- jmp _exit_with_msg
-.buffer_size_small_enough:
- mov ax,4300h ; CHECK: HIMEM.SYS is present
- int 2Fh
- cmp al,80h
- jz .yes_himem_sys
- jmp .skip_himem
-.yes_himem_sys: mov ax,4310h ; Get HIMEM.SYS entry point (cannot fail)
- int 2Fh
- mov word [himem_sys_entry],bx
- mov word [himem_sys_entry+2],es
- mov ah,5h ; HIMEM.SYS Local Enable A20
- call far word [himem_sys_entry]
- cmp ax,1
- jz .yes_himem_a20
- mov dx,str_himem_a20_error
- jmp _exit_with_msg
-.yes_himem_a20: mov ah,09h ; HIMEM.SYS allocate block
- cli ; <- in case BIOS interrupts do not save upper 16 bits
- mov edx,[himem_sys_buffer_size]
- add edx,1023
- shr edx,10 ; EDX = (X BYTES+1023)/1024 KB
- call far word [himem_sys_entry]
- cmp ax,1
- jz .yes_himem_buf
- mov dx,str_himem_alloc_err
- jmp _exit_with_msg
-.yes_himem_buf: mov word [himem_sys_buffer_handle],dx ; store memory handle
- mov ah,0Ch ; HIMEM.SYS lock memory block
- call far word [himem_sys_entry] ; NOTE: DX = memory handle (still)
- cmp ax,1
- jz .yes_himem_lock
- mov dx,str_himem_lock_err
- jmp _exit_with_msg
-.yes_himem_lock:mov word [himem_sys_buffer_phys],bx ; store DX:BX physical memory address
- mov word [himem_sys_buffer_phys+2],dx
-.skip_himem:
-
-; tss physical addrs
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,tss_main
- mov [tss_phys_base],eax ; = 104 bytes
-
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,tss_vm86
- mov [tss_vm86_phys_base],eax ; = 8192+104 bytes
-
-; PRINT "BUFFER AT: " + *((DWORD*)himem_sys_buffer_phys) + "\n"
- mov dx,str_buffer_at
- call dos_puts
- cli
- mov eax,[himem_sys_buffer_phys]
- mov di,scratch_str
- call eax_to_hex_16_dos
- mov dx,di
- call dos_puts
-
- cli
- mov eax,[himem_sys_buffer_phys]
- add eax,[himem_sys_buffer_size]
- dec eax
- mov byte [scratch_str],'-'
- mov di,scratch_str+1
- call eax_to_hex_16_dos
- mov dx,scratch_str
- call dos_puts
-
- mov dx,str_crlf
- call dos_puts
-
- xor eax,eax
- mov ax,cs
- mov es,ax
- shl eax,4
- mov dword [my_phys_base],eax
-
-; we use the extended memory buffer for VCPI emulation (page allocation)
- mov eax,dword [himem_sys_buffer_phys]
- mov dword [vcpi_alloc_bitmap_phys],eax
- mov dword [vcpi_alloc_bitmap_size],eax
- mov dword [vcpi_alloc_pages_phys],eax
-
- cmp eax,0
- jz .nothing
-
- add eax,4096 ; assume bitmap size of 4K, enough for 4MB of pages
- mov dword [vcpi_alloc_pages_phys],eax
-
- mov ebx,dword [himem_sys_buffer_size]
- add ebx,0xFFF
- shr ebx,12+3 ; EBX = size of bitmap (up to 4K)
- mov dword [vcpi_alloc_bitmap_size],ebx
-.nothing:
-
-; clear the IDT and GDT
- cld
- xor ax,ax
-
- mov cx,MAX_SEL / 2
- mov di,gdt
- rep stosw
-
-; prepare the IDTR and GDTR.
-; real mode versions: limit=0xFFFF base=0
- xor eax,eax
- dec ax ; AX = 0xFFFF
- mov word [idtr_real],ax
- mov word [gdtr_real],ax
- inc ax
- mov dword [idtr_real+2],eax
- mov dword [gdtr_real+2],eax
-; protected mode GDTR limit=MAX_SEL-1 base=(code segment)+var
- mov word [gdtr_pmode],MAX_SEL - 1
- mov word [idtr_pmode],(256 << 3) - 1
- mov eax,[my_phys_base]
- add eax,gdt
- mov dword [gdtr_pmode+2],eax
- mov eax,[my_phys_base]
- add eax,idt
- mov dword [idtr_pmode+2],eax
-
-; build the GDT
- cld
- lea di,[gdt+CODE16_SEL]
-; Code selector (CODE_16SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0x0F
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA16_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x0F
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Code selector (CODE_32SEL)
- dec ax ; 0x0000 - 1 = 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x9A
- stosw ; BASE[23:16] access byte=executable readable
- mov al,0xCF
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (DATA32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; Data selector (FLAT16_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- xor ax,ax
- stosw ; BASE[15:0]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0x8F
- xor ah,ah
- stosw
-; Data selector (FLAT32_SEL)
- xor ax,ax
- dec ax ; 0xFFFF
- stosw ; LIMIT
- xor ax,ax
- stosw ; BASE[15:0]
- mov ah,0x92
- stosw ; BASE[23:16] access byte=data writeable
- mov al,0xCF
- xor ah,ah
- stosw
-; LDT selector (LDT_SEL)
- mov ax,7 ; I have no use for the LDT
- stosw ; LIMIT
- mov ax,[my_phys_base]
- stosw ; BASE[15:0]
- mov al,[my_phys_base+2]
- mov ah,0x82
- stosw ; BASE[23:16] access byte=data writeable LDT type 2
- mov al,0x0F
- mov ah,[my_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; TSS selector (TSS_SEL)
- mov ax,104-1
- stosw ; LIMIT
- mov ax,[tss_phys_base]
- stosw ; BASE[15:0]
- mov al,[tss_phys_base+2]
- mov ah,0x89
- stosw ; BASE[23:16] access byte=data writeable non-busy TSS type 9
- mov al,0x0F
- mov ah,[tss_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-; TSS selector (TSS_VM86_SEL)
- mov ax,104+8192-1
- stosw ; LIMIT
- mov ax,[tss_vm86_phys_base]
- stosw ; BASE[15:0]
- mov al,[tss_vm86_phys_base+2]
- mov ah,0x89
- stosw ; BASE[23:16] access byte=data writeable non-busy TSS type 9
- mov al,0x0F
- mov ah,[tss_vm86_phys_base+3] ; LIMIT[19:16] flags=0 BASE[31:24]
- stosw
-
-; prepare the CPU registers
- lidt [idtr_pmode]
- lgdt [gdtr_pmode]
-
-; enter protected mode
- mov eax,0x00000011
- or eax,[cr0_more]
- mov cr0,eax
- jmp CODE16_SEL:pmode16_entry
-pmode16_entry: mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,stack_init
-
-; load task register
- mov ax,TSS_SEL
- ltr ax
-
-; load LDT
- mov ax,LDT_SEL
- lldt ax
-
-; now enter 32-bit protected mode
- jmp CODE32_SEL:pmode32_entry
- bits 32
-pmode32_entry: mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov ax,FLAT32_SEL
- mov fs,ax
- mov gs,ax
- mov esp,stack_init
-; at this point: we are in 32-bit protected mode!
-
-; ============= setup the TSS representing our task (for when we return)
- cld
- mov edi,[tss_phys_base]
- sub edi,[my_phys_base]
-
- xor eax,eax ; TSS+0x00 = no backlink
- stosd
- mov eax,stack_init ; TSS+0x04 = ESP for CPL0
- stosd
- mov eax,DATA32_SEL ; TSS+0x08 = SS for CPL0
- stosd
- mov eax,stack_init ; TSS+0x0C = ESP for CPL1
- stosd
- mov eax,DATA32_SEL ; TSS+0x10 = SS for CPL1
- stosd
- mov eax,stack_init ; TSS+0x14 = ESP for CPL2
- stosd
- mov eax,DATA32_SEL ; TSS+0x18 = SS for CPL2
- stosd
- xor eax,eax ; TSS+0x1C = CR3
- stosd
- mov eax,0 ; TSS+0x20 = EIP [FIXME]
- stosd
- mov eax,0x00000002 ; TSS+0x24 = EFLAGS VM=0
- stosd
- xor eax,eax ; TSS+0x28 = EAX
- stosd
- xor eax,eax ; TSS+0x2C = ECX
- stosd
- xor eax,eax ; TSS+0x30 = EDX
- stosd
- xor eax,eax ; TSS+0x34 = EBX
- stosd
- mov eax,stack_init ; TSS+0x38 = ESP
- stosd
- xor eax,eax ; TSS+0x3C = EBP
- stosd
- xor eax,eax ; TSS+0x40 = ESI
- stosd
- xor eax,eax ; TSS+0x44 = EDI
- stosd
- mov ax,DATA32_SEL ; TSS+0x48 = ES
- stosd
- mov ax,CODE32_SEL ; TSS+0x4C = CS
- stosd
- mov ax,DATA32_SEL ; TSS+0x50 = SS
- stosd
- mov ax,DATA32_SEL ; TSS+0x54 = DS
- stosd
- mov ax,DATA32_SEL ; TSS+0x58 = FS
- stosd
- mov ax,DATA32_SEL ; TSS+0x5C = GS
- stosd
- xor eax,eax ; TSS+0x60 = LDTR
- stosd
- mov eax,(104 << 16) ; TSS+0x64 = I/O map base
- stosd
-
-; ============= setup the TSS representing the virtual 8086 mode task
- cld
- mov edi,[tss_vm86_phys_base]
- sub edi,[my_phys_base]
-
- xor eax,eax ; TSS+0x00 = no backlink
- stosd
- mov eax,stack_init ; TSS+0x04 = ESP for CPL0
- stosd
- mov eax,DATA32_SEL ; TSS+0x08 = SS for CPL0
- stosd
- mov eax,stack_init ; TSS+0x0C = ESP for CPL1
- stosd
- mov eax,DATA32_SEL ; TSS+0x10 = SS for CPL1
- stosd
- mov eax,stack_init ; TSS+0x14 = ESP for CPL2
- stosd
- mov eax,DATA32_SEL ; TSS+0x18 = SS for CPL2
- stosd
- xor eax,eax ; TSS+0x1C = CR3
- stosd
- mov eax,vm86_entry ; TSS+0x20 = EIP
- stosd
- mov eax,0x00020202 ; TSS+0x24 = EFLAGS VM=1 IOPL=N IF=1
- movzx ebx,byte [user_req_iopl]
- and bl,3
- shl ebx,12
- or eax,ebx ; EFLAGS |= user_req_iopl << 12
- stosd
- xor eax,eax ; TSS+0x28 = EAX
- stosd
- xor eax,eax ; TSS+0x2C = ECX
- stosd
- xor eax,eax ; TSS+0x30 = EDX
- stosd
- xor eax,eax ; TSS+0x34 = EBX
- stosd
- mov eax,stack_init_vm86 ; TSS+0x38 = ESP
- stosd
- xor eax,eax ; TSS+0x3C = EBP
- stosd
- xor eax,eax ; TSS+0x40 = ESI
- stosd
- xor eax,eax ; TSS+0x44 = EDI
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x48 = ES
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x4C = CS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x50 = SS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x54 = DS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x58 = FS
- stosd
- mov ax,[my_realmode_seg] ; TSS+0x5C = GS
- stosd
- xor eax,eax ; TSS+0x60 = LDTR
- stosd
- mov eax,(104 << 16) ; TSS+0x64 = I/O map base (0x68 == 104)
- stosd
- xor eax,eax
- mov ecx,8192 >> 2 ; TSS+0x68 = I/O permission map (pre-set to all open)
- rep stosd
-
-; actually, we want it to trap some ports off the bat
- mov edi,[tss_vm86_phys_base]
- sub edi,[my_phys_base]
- add edi,0x68 ; TSS+0x68 = I/O permission map
- or byte [edi+(0x64/8)],1 << (0x64 & 7) ; trap port 0x64
- or byte [edi+(0x92/8)],1 << (0x92 & 7) ; trap port 0x92
-
-; zero VCPI page map
- mov eax,dword [vcpi_alloc_bitmap_phys]
- cmp eax,0
- jz .nothing
- push es
- mov ax,FLAT32_SEL
- mov es,ax
- xor eax,eax
- cld
- mov edi,dword [vcpi_alloc_bitmap_phys]
- mov ecx,dword [vcpi_alloc_bitmap_size]
- shr ecx,2
- rep stosd
- pop es
-.nothing:
-
-; set up the IDT
- cld
-
- mov edi,idt
- mov esi,interrupt_procs
-
-; the first 32 interrupts (0x00-0x1F) are marked CPL=0. This causes
-; real-mode software interrupts in that range to instead cause a GPF
-; which we can then safely reflect back to real mode. If all were
-; marked CPL=3 then a real-mode software interrupt would trigger an
-; actual INT in the IDT and it would be extremely difficult for
-; fault handlers to differentiate between actual faults vs. software
-; interrupts.
- mov ecx,0x14
-.idtdef0: lodsw
- stosw ; base[15:0]
- mov ax,CODE32_SEL
- stosw
- mov ax,0x8E00 ; DPL=0 (so that software interrupts 0x00-0x1F can be handled by our GPF)
- stosw
- xor ax,ax
- stosw
- loop .idtdef0
-
- mov ecx,0x100 - 0x14
-.idtdef3: lodsw
- stosw ; base[15:0]
- mov ax,CODE32_SEL
- stosw
- mov ax,0xEE00 ; DPL=3
- stosw
- xor ax,ax
- stosw
- loop .idtdef3
-
-; next we need to reprogram the PIC so that IRQ 0-7 do not conflict with the CPU exceptions.
- mov al,0x10 ; ICW1 A0=0
- out 20h,al
- mov al,IRQ_BASE_INT ; ICW2 A0=1
- out 21h,al
- mov al,0x04 ; ICW3 A0=1 slave on IRQ 2
- out 21h,al
-
- mov al,0x10 ; ICW1 A0=0
- out 0xA0,al
- mov al,IRQ_BASE_INT+8 ; ICW2 A0=1
- out 0xA1,al
- mov al,0x02 ; ICW3 A0=1
- out 0xA1,al
-
-; jump into virtual 8086 mode
- jmp TSS_VM86_SEL:0
-
-; interrupt jump table. emits a 4-byte instruction (no error code)
-; interrupt_entry_4 <vector>
-%macro interrupt_entry_4 1
-; non-error code version. We push a dummy error code along with the intnum.
-interrupt_%1: push byte 0
- push %1
- jmp interrupt_routine
-%endmacro
-
-; interrupt jump table. emits a 4-byte instruction (no error code), meant for IRQs
-; interrupt_entry_4 <vector>
-%macro interrupt_entry_4irq 1
-; non-error code version. We push a dummy error code along with the intnum.
-interrupt_%1: push byte 0
- push %1
- jmp interrupt_routine_irq
-%endmacro
-
-; interrupt jump table. emits a 4-byte instruction (no error code), meant for IRQs
-; interrupt_entry_4 <vector>
-%macro interrupt_entry_4_tf 1
-; non-error code version. We push a dummy error code along with the intnum.
-interrupt_%1: push byte 0
- push %1
- jmp interrupt_routine_tf
-%endmacro
-
-; error code version. The CPU pushes an error code on the stack. We just push the intnum and move on,
-%macro interrupt_entry_4_ec 1
-interrupt_%1: push %1
- jmp interrupt_routine
-%endmacro
-
-; specialized for GPF fault. no time to jump to generic interrupt handlers.
-%macro interrupt_entry_4gpf 1
-interrupt_%1: push %1
- jmp interrupt_routine_gpf
-%endmacro
-
-; specialized for EMM/VCPI entry. no time to jump to generic interrupt handlers.
-%macro interrupt_entry_4emm 1
-interrupt_%1: push byte 0
- push %1
- jmp interrupt_routine_emm
-%endmacro
-
- interrupt_entry_4 0x00
- interrupt_entry_4_tf 0x01
- interrupt_entry_4 0x02
- interrupt_entry_4 0x03
- interrupt_entry_4 0x04
- interrupt_entry_4 0x05
- interrupt_entry_4 0x06
- interrupt_entry_4 0x07
- interrupt_entry_4_ec 0x08
- interrupt_entry_4 0x09
- interrupt_entry_4_ec 0x0A
- interrupt_entry_4_ec 0x0B
- interrupt_entry_4_ec 0x0C
- interrupt_entry_4gpf 0x0D
- interrupt_entry_4 0x0E
- interrupt_entry_4 0x0F
- interrupt_entry_4 0x10
- interrupt_entry_4 0x11
- interrupt_entry_4 0x12
- interrupt_entry_4 0x13
- interrupt_entry_4 0x14 ; <== FIRST INTERRUPT NOT TO TRAP VIA GPF
- interrupt_entry_4 0x15
- interrupt_entry_4 0x16
- interrupt_entry_4 0x17
- interrupt_entry_4 0x18
- interrupt_entry_4 0x19
- interrupt_entry_4 0x1A
- interrupt_entry_4 0x1B
- interrupt_entry_4 0x1C
- interrupt_entry_4 0x1D
- interrupt_entry_4 0x1E
- interrupt_entry_4 0x1F
- interrupt_entry_4 0x20
- interrupt_entry_4 0x21
- interrupt_entry_4 0x22
- interrupt_entry_4 0x23
- interrupt_entry_4 0x24
- interrupt_entry_4 0x25
- interrupt_entry_4 0x26
- interrupt_entry_4 0x27
- interrupt_entry_4 0x28
- interrupt_entry_4 0x29
- interrupt_entry_4 0x2A
- interrupt_entry_4 0x2B
- interrupt_entry_4 0x2C
- interrupt_entry_4 0x2D
- interrupt_entry_4 0x2E
- interrupt_entry_4 0x2F
- interrupt_entry_4 0x30
- interrupt_entry_4 0x31
- interrupt_entry_4 0x32
- interrupt_entry_4 0x33
- interrupt_entry_4 0x34
- interrupt_entry_4 0x35
- interrupt_entry_4 0x36
- interrupt_entry_4 0x37
- interrupt_entry_4 0x38
- interrupt_entry_4 0x39
- interrupt_entry_4 0x3A
- interrupt_entry_4 0x3B
- interrupt_entry_4 0x3C
- interrupt_entry_4 0x3D
- interrupt_entry_4 0x3E
- interrupt_entry_4 0x3F
- interrupt_entry_4 0x40
- interrupt_entry_4 0x41
- interrupt_entry_4 0x42
- interrupt_entry_4 0x43
- interrupt_entry_4 0x44
- interrupt_entry_4 0x45
- interrupt_entry_4 0x46
- interrupt_entry_4 0x47
- interrupt_entry_4 0x48
- interrupt_entry_4 0x49
- interrupt_entry_4 0x4A
- interrupt_entry_4 0x4B
- interrupt_entry_4 0x4C
- interrupt_entry_4 0x4D
- interrupt_entry_4 0x4E
- interrupt_entry_4 0x4F
- interrupt_entry_4 0x50
- interrupt_entry_4 0x51
- interrupt_entry_4 0x52
- interrupt_entry_4 0x53
- interrupt_entry_4 0x54
- interrupt_entry_4 0x55
- interrupt_entry_4 0x56
- interrupt_entry_4 0x57
- interrupt_entry_4 0x58
- interrupt_entry_4 0x59
- interrupt_entry_4 0x5A
- interrupt_entry_4 0x5B
- interrupt_entry_4 0x5C
- interrupt_entry_4 0x5D
- interrupt_entry_4 0x5E
- interrupt_entry_4 0x5F
- interrupt_entry_4 0x60
- interrupt_entry_4 0x61
- interrupt_entry_4 0x62
- interrupt_entry_4 0x63
- interrupt_entry_4 0x64
- interrupt_entry_4 0x65
- interrupt_entry_4 0x66
- interrupt_entry_4emm 0x67
- interrupt_entry_4 0x68
- interrupt_entry_4 0x69
- interrupt_entry_4 0x6A
- interrupt_entry_4 0x6B
- interrupt_entry_4 0x6C
- interrupt_entry_4 0x6D
- interrupt_entry_4 0x6E
- interrupt_entry_4 0x6F
- interrupt_entry_4 0x70
- interrupt_entry_4 0x71
- interrupt_entry_4 0x72
- interrupt_entry_4 0x73
- interrupt_entry_4 0x74
- interrupt_entry_4 0x75
- interrupt_entry_4 0x76
- interrupt_entry_4 0x77
- interrupt_entry_4 0x78
- interrupt_entry_4 0x79
- interrupt_entry_4 0x7A
- interrupt_entry_4 0x7B
- interrupt_entry_4 0x7C
- interrupt_entry_4 0x7D
- interrupt_entry_4 0x7E
- interrupt_entry_4 0x7F
- interrupt_entry_4 0x80
- interrupt_entry_4 0x81
- interrupt_entry_4 0x82
- interrupt_entry_4 0x83
- interrupt_entry_4 0x84
- interrupt_entry_4 0x85
- interrupt_entry_4 0x86
- interrupt_entry_4 0x87
- interrupt_entry_4 0x88
- interrupt_entry_4 0x89
- interrupt_entry_4 0x8A
- interrupt_entry_4 0x8B
- interrupt_entry_4 0x8C
- interrupt_entry_4 0x8D
- interrupt_entry_4 0x8E
- interrupt_entry_4 0x8F
- interrupt_entry_4 0x90
- interrupt_entry_4 0x91
- interrupt_entry_4 0x92
- interrupt_entry_4 0x93
- interrupt_entry_4 0x94
- interrupt_entry_4 0x95
- interrupt_entry_4 0x96
- interrupt_entry_4 0x97
- interrupt_entry_4 0x98
- interrupt_entry_4 0x99
- interrupt_entry_4 0x9A
- interrupt_entry_4 0x9B
- interrupt_entry_4 0x9C
- interrupt_entry_4 0x9D
- interrupt_entry_4 0x9E
- interrupt_entry_4 0x9F
- interrupt_entry_4 0xA0
- interrupt_entry_4 0xA1
- interrupt_entry_4 0xA2
- interrupt_entry_4 0xA3
- interrupt_entry_4 0xA4
- interrupt_entry_4 0xA5
- interrupt_entry_4 0xA6
- interrupt_entry_4 0xA7
- interrupt_entry_4 0xA8
- interrupt_entry_4 0xA9
- interrupt_entry_4 0xAA
- interrupt_entry_4 0xAB
- interrupt_entry_4 0xAC
- interrupt_entry_4 0xAD
- interrupt_entry_4 0xAE
- interrupt_entry_4 0xAF
- interrupt_entry_4 0xB0
- interrupt_entry_4 0xB1
- interrupt_entry_4 0xB2
- interrupt_entry_4 0xB3
- interrupt_entry_4 0xB4
- interrupt_entry_4 0xB5
- interrupt_entry_4 0xB6
- interrupt_entry_4 0xB7
- interrupt_entry_4 0xB8
- interrupt_entry_4 0xB9
- interrupt_entry_4 0xBA
- interrupt_entry_4 0xBB
- interrupt_entry_4 0xBC
- interrupt_entry_4 0xBD
- interrupt_entry_4 0xBE
- interrupt_entry_4 0xBF
- interrupt_entry_4 0xC0
- interrupt_entry_4 0xC1
- interrupt_entry_4 0xC2
- interrupt_entry_4 0xC3
- interrupt_entry_4 0xC4
- interrupt_entry_4 0xC5
- interrupt_entry_4 0xC6
- interrupt_entry_4 0xC7
- interrupt_entry_4 0xC8
- interrupt_entry_4 0xC9
- interrupt_entry_4 0xCA
- interrupt_entry_4 0xCB
- interrupt_entry_4 0xCC
- interrupt_entry_4 0xCD
- interrupt_entry_4 0xCE
- interrupt_entry_4 0xCF
- interrupt_entry_4 0xD0
- interrupt_entry_4 0xD1
- interrupt_entry_4 0xD2
- interrupt_entry_4 0xD3
- interrupt_entry_4 0xD4
- interrupt_entry_4 0xD5
- interrupt_entry_4 0xD6
- interrupt_entry_4 0xD7
- interrupt_entry_4 0xD8
- interrupt_entry_4 0xD9
- interrupt_entry_4 0xDA
- interrupt_entry_4 0xDB
- interrupt_entry_4 0xDC
- interrupt_entry_4 0xDD
- interrupt_entry_4 0xDE
- interrupt_entry_4 0xDF
- interrupt_entry_4 0xE0
- interrupt_entry_4 0xE1
- interrupt_entry_4 0xE2
- interrupt_entry_4 0xE3
- interrupt_entry_4 0xE4
- interrupt_entry_4 0xE5
- interrupt_entry_4 0xE6
- interrupt_entry_4 0xE7
- interrupt_entry_4 0xE8
- interrupt_entry_4 0xE9
- interrupt_entry_4 0xEA
- interrupt_entry_4 0xEB
- interrupt_entry_4 0xEC
- interrupt_entry_4 0xED
- interrupt_entry_4 0xEE
- interrupt_entry_4 0xEF
- interrupt_entry_4irq 0xF0
- interrupt_entry_4irq 0xF1
- interrupt_entry_4irq 0xF2
- interrupt_entry_4irq 0xF3
- interrupt_entry_4irq 0xF4
- interrupt_entry_4irq 0xF5
- interrupt_entry_4irq 0xF6
- interrupt_entry_4irq 0xF7
- interrupt_entry_4irq 0xF8
- interrupt_entry_4irq 0xF9
- interrupt_entry_4irq 0xFA
- interrupt_entry_4irq 0xFB
- interrupt_entry_4irq 0xFC
- interrupt_entry_4irq 0xFD
- interrupt_entry_4irq 0xFE
- interrupt_entry_4irq 0xFF
-
-interrupt_procs:dw interrupt_0x00
- dw interrupt_0x01
- dw interrupt_0x02
- dw interrupt_0x03
- dw interrupt_0x04
- dw interrupt_0x05
- dw interrupt_0x06
- dw interrupt_0x07
- dw interrupt_0x08
- dw interrupt_0x09
- dw interrupt_0x0A
- dw interrupt_0x0B
- dw interrupt_0x0C
- dw interrupt_0x0D
- dw interrupt_0x0E
- dw interrupt_0x0F
- dw interrupt_0x10
- dw interrupt_0x11
- dw interrupt_0x12
- dw interrupt_0x13
- dw interrupt_0x14
- dw interrupt_0x15
- dw interrupt_0x16
- dw interrupt_0x17
- dw interrupt_0x18
- dw interrupt_0x19
- dw interrupt_0x1A
- dw interrupt_0x1B
- dw interrupt_0x1C
- dw interrupt_0x1D
- dw interrupt_0x1E
- dw interrupt_0x1F
-
- dw interrupt_0x20
- dw interrupt_0x21
- dw interrupt_0x22
- dw interrupt_0x23
- dw interrupt_0x24
- dw interrupt_0x25
- dw interrupt_0x26
- dw interrupt_0x27
- dw interrupt_0x28
- dw interrupt_0x29
- dw interrupt_0x2A
- dw interrupt_0x2B
- dw interrupt_0x2C
- dw interrupt_0x2D
- dw interrupt_0x2E
- dw interrupt_0x2F
- dw interrupt_0x30
- dw interrupt_0x31
- dw interrupt_0x32
- dw interrupt_0x33
- dw interrupt_0x34
- dw interrupt_0x35
- dw interrupt_0x36
- dw interrupt_0x37
- dw interrupt_0x38
- dw interrupt_0x39
- dw interrupt_0x3A
- dw interrupt_0x3B
- dw interrupt_0x3C
- dw interrupt_0x3D
- dw interrupt_0x3E
- dw interrupt_0x3F
-
- dw interrupt_0x40
- dw interrupt_0x41
- dw interrupt_0x42
- dw interrupt_0x43
- dw interrupt_0x44
- dw interrupt_0x45
- dw interrupt_0x46
- dw interrupt_0x47
- dw interrupt_0x48
- dw interrupt_0x49
- dw interrupt_0x4A
- dw interrupt_0x4B
- dw interrupt_0x4C
- dw interrupt_0x4D
- dw interrupt_0x4E
- dw interrupt_0x4F
- dw interrupt_0x50
- dw interrupt_0x51
- dw interrupt_0x52
- dw interrupt_0x53
- dw interrupt_0x54
- dw interrupt_0x55
- dw interrupt_0x56
- dw interrupt_0x57
- dw interrupt_0x58
- dw interrupt_0x59
- dw interrupt_0x5A
- dw interrupt_0x5B
- dw interrupt_0x5C
- dw interrupt_0x5D
- dw interrupt_0x5E
- dw interrupt_0x5F
-
- dw interrupt_0x60
- dw interrupt_0x61
- dw interrupt_0x62
- dw interrupt_0x63
- dw interrupt_0x64
- dw interrupt_0x65
- dw interrupt_0x66
- dw interrupt_0x67
- dw interrupt_0x68
- dw interrupt_0x69
- dw interrupt_0x6A
- dw interrupt_0x6B
- dw interrupt_0x6C
- dw interrupt_0x6D
- dw interrupt_0x6E
- dw interrupt_0x6F
- dw interrupt_0x70
- dw interrupt_0x71
- dw interrupt_0x72
- dw interrupt_0x73
- dw interrupt_0x74
- dw interrupt_0x75
- dw interrupt_0x76
- dw interrupt_0x77
- dw interrupt_0x78
- dw interrupt_0x79
- dw interrupt_0x7A
- dw interrupt_0x7B
- dw interrupt_0x7C
- dw interrupt_0x7D
- dw interrupt_0x7E
- dw interrupt_0x7F
-
- dw interrupt_0x80
- dw interrupt_0x81
- dw interrupt_0x82
- dw interrupt_0x83
- dw interrupt_0x84
- dw interrupt_0x85
- dw interrupt_0x86
- dw interrupt_0x87
- dw interrupt_0x88
- dw interrupt_0x89
- dw interrupt_0x8A
- dw interrupt_0x8B
- dw interrupt_0x8C
- dw interrupt_0x8D
- dw interrupt_0x8E
- dw interrupt_0x8F
- dw interrupt_0x90
- dw interrupt_0x91
- dw interrupt_0x92
- dw interrupt_0x93
- dw interrupt_0x94
- dw interrupt_0x95
- dw interrupt_0x96
- dw interrupt_0x97
- dw interrupt_0x98
- dw interrupt_0x99
- dw interrupt_0x9A
- dw interrupt_0x9B
- dw interrupt_0x9C
- dw interrupt_0x9D
- dw interrupt_0x9E
- dw interrupt_0x9F
-
- dw interrupt_0xA0
- dw interrupt_0xA1
- dw interrupt_0xA2
- dw interrupt_0xA3
- dw interrupt_0xA4
- dw interrupt_0xA5
- dw interrupt_0xA6
- dw interrupt_0xA7
- dw interrupt_0xA8
- dw interrupt_0xA9
- dw interrupt_0xAA
- dw interrupt_0xAB
- dw interrupt_0xAC
- dw interrupt_0xAD
- dw interrupt_0xAE
- dw interrupt_0xAF
- dw interrupt_0xB0
- dw interrupt_0xB1
- dw interrupt_0xB2
- dw interrupt_0xB3
- dw interrupt_0xB4
- dw interrupt_0xB5
- dw interrupt_0xB6
- dw interrupt_0xB7
- dw interrupt_0xB8
- dw interrupt_0xB9
- dw interrupt_0xBA
- dw interrupt_0xBB
- dw interrupt_0xBC
- dw interrupt_0xBD
- dw interrupt_0xBE
- dw interrupt_0xBF
-
- dw interrupt_0xC0
- dw interrupt_0xC1
- dw interrupt_0xC2
- dw interrupt_0xC3
- dw interrupt_0xC4
- dw interrupt_0xC5
- dw interrupt_0xC6
- dw interrupt_0xC7
- dw interrupt_0xC8
- dw interrupt_0xC9
- dw interrupt_0xCA
- dw interrupt_0xCB
- dw interrupt_0xCC
- dw interrupt_0xCD
- dw interrupt_0xCE
- dw interrupt_0xCF
- dw interrupt_0xD0
- dw interrupt_0xD1
- dw interrupt_0xD2
- dw interrupt_0xD3
- dw interrupt_0xD4
- dw interrupt_0xD5
- dw interrupt_0xD6
- dw interrupt_0xD7
- dw interrupt_0xD8
- dw interrupt_0xD9
- dw interrupt_0xDA
- dw interrupt_0xDB
- dw interrupt_0xDC
- dw interrupt_0xDD
- dw interrupt_0xDE
- dw interrupt_0xDF
-
- dw interrupt_0xE0
- dw interrupt_0xE1
- dw interrupt_0xE2
- dw interrupt_0xE3
- dw interrupt_0xE4
- dw interrupt_0xE5
- dw interrupt_0xE6
- dw interrupt_0xE7
- dw interrupt_0xE8
- dw interrupt_0xE9
- dw interrupt_0xEA
- dw interrupt_0xEB
- dw interrupt_0xEC
- dw interrupt_0xED
- dw interrupt_0xEE
- dw interrupt_0xEF
- dw interrupt_0xF0
- dw interrupt_0xF1
- dw interrupt_0xF2
- dw interrupt_0xF3
- dw interrupt_0xF4
- dw interrupt_0xF5
- dw interrupt_0xF6
- dw interrupt_0xF7
- dw interrupt_0xF8
- dw interrupt_0xF9
- dw interrupt_0xFA
- dw interrupt_0xFB
- dw interrupt_0xFC
- dw interrupt_0xFD
- dw interrupt_0xFE
- dw interrupt_0xFF
-
-interrupt_0x00_strs:
- dw str_fault_0x00
- dw str_fault_0x01
- dw str_fault_0x02
- dw str_fault_0x03
- dw str_fault_0x04
- dw str_fault_0x05
- dw str_fault_0x06
- dw str_fault_0x07
- dw str_fault_0x08
- dw str_fault_0x09
- dw str_fault_0x0A
- dw str_fault_0x0B
- dw str_fault_0x0C
- dw str_fault_0x0D
- dw str_fault_0x0E
- dw str_fault_0x0F
- dw str_fault_0x10
- dw str_fault_0x11
- dw str_fault_0x12
- dw str_fault_0x13
-
-; VCPI PM entry
-%macro pm_int_entry 0
- pusha
- push ds
- push es
- mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- lea eax,[esp+4+4+32+4+4+12] ; ESP + DS + ES + PUSHA + INTNUM + ERRCODE + IRET
- ; TODO: MOVE EAX over ESP image on stack
- lea ebp,[esp]
-%endmacro
-%macro pm_int_exit 0
- pop es
- pop ds
- popa
- retf
-%endmacro
-
-; this must reside here. Any further down the jmps in the table will be out of range.
-; Check:
-; (EFLAGS & VM) = Happend in v86 mode?
-%macro int_entry 0
- pusha
- push ds
- push es
- mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- lea eax,[esp+4+4+32+4+4+12] ; ESP + DS + ES + PUSHA + INTNUM + ERRCODE + IRET
- ; TODO: MOVE EAX over ESP image on stack
- lea ebp,[esp]
-%endmacro
-%macro int_exit 0
- pop es
- pop ds
- popa
- add esp,8 ; drop error code + interrupt num
- iret
-%endmacro
-%define int_ES word [ebp+0]
-%define int_DS word [ebp+4]
-%define int_EDI dword [ebp+8]
-%define int_ESI dword [ebp+12]
-%define int_EBP dword [ebp+16]
-%define int_ESP dword [ebp+20]
-%define int_EBX dword [ebp+24]
-%define int_EDX dword [ebp+28]
-%define int_ECX dword [ebp+32]
-%define int_EAX dword [ebp+36]
-%define int_AX word [ebp+36]
-%define int_AL byte [ebp+36]
-%define int_INTNUM dword [ebp+40]
-%define int_INTNUM_b byte [ebp+40]
-%define int_ERRCODE dword [ebp+44]
-%define int_EIP dword [ebp+48]
-%define int_EIP_w word [ebp+48]
-%define int_CS word [ebp+52]
-%define int_EFLAGS dword [ebp+56]
-%define int_FLAGS word [ebp+56]
-; the following also exist if coming out of v86 mode
-%define int_v86_ESP dword [ebp+60]
-%define int_v86_SS word [ebp+64]
-%define int_v86_ES word [ebp+68]
-%define int_v86_DS word [ebp+72]
-%define int_v86_FS word [ebp+76]
-%define int_v86_GS word [ebp+80]
-
-irq_rm_map: db 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F
- db 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
-
-; return: EAX = physical memory address of vm86 SS:SP pointer
-vm86_ss_esp_to_phys:
- xor eax,eax
- mov ax,int_v86_SS
- shl eax,4
- mov ebx,int_v86_ESP
- and ebx,0xFFFF
- add eax,ebx
- ret
-
-; return: EAX = physical memory address of vm86 CS:IP pointer
-vm86_cs_eip_to_phys:
- xor eax,eax
- mov ax,int_CS
- shl eax,4
- mov ebx,int_EIP
- and ebx,0xFFFF
- add eax,ebx
- ret
-
-; EAX = interrupt to direct v86 mode to.
-; the caller must be on a stack frame formed from v86 mode to protected mode transition, or this won't work
-vm86_push_interrupt:
- push es
- mov bx,FLAT32_SEL
- mov es,bx
- mov ecx,[es:eax*4]
- sub int_v86_ESP,6 ; IRET stack frame
- jc .stack_overflow
- call vm86_ss_esp_to_phys
- mov ebx,int_EIP ; save IP,CS,FLAGS to stack
- mov word [es:eax+0],bx
- mov bx,int_CS
- mov word [es:eax+2],bx
- mov ebx,int_EFLAGS
- mov word [es:eax+4],bx
-
- mov int_EIP_w,cx ; load new CS:IP from interrupt vector
- shr ecx,16
- mov int_CS,cx
-
- pop es
- ret
-.stack_overflow:
- call interrupt_routine_halt_prepare
- mov edx,int_INTNUM
- mov esi,str_stack_overflow
- jmp fault_jmp_unhandled
-
-interrupt_routine_tf: ; INT 0x01 Trap Interrupt
- int_entry
- test int_EFLAGS,0x20000 ; did this happen from v86 mode?
- jz .not_vm86
- mov eax,1 ; reflect INT 0x01 to vm86
- call vm86_push_interrupt
- and int_EFLAGS,~0x100 ; clear the trap flag
- int_exit
-.not_vm86: call interrupt_routine_halt_prepare
- mov edx,int_INTNUM
- mov esi,str_unexpected_int_not_v86
- jmp fault_jmp_unhandled
-
-interrupt_routine_irq:
- int_entry
- test int_EFLAGS,0x20000 ; did this happen from v86 mode?
- jz .not_vm86
- mov eax,int_INTNUM
- sub eax,IRQ_BASE_INT
- movzx eax,byte [eax+irq_rm_map]
- call vm86_push_interrupt
- int_exit
-.not_vm86: call interrupt_routine_halt_prepare
- mov edx,int_INTNUM
- mov esi,str_unexpected_int_not_v86
- jmp fault_jmp_unhandled
-
-vm86_stack_overflow:
- call interrupt_routine_halt_prepare
- mov edx,int_INTNUM
- mov esi,str_stack_overflow
- jmp fault_jmp_unhandled
-
-; General Protection Fault
-interrupt_routine_gpf:
- int_entry
- mov ax,FLAT32_SEL
- mov es,ax
- test int_EFLAGS,0x20000 ; did this happen from v86 mode?
- jz .not_vm86
-
- call vm86_cs_eip_to_phys ; else, read the opcode at CS:IP to tell between exceptions and explicit INT xxh instructions
- mov eax,[es:eax] ; EAX = first 4 bytes of the opcode
-
-; INT 3?
- cmp al,0xCC
- jz .vm86_int3
-; INT N?
- cmp al,0xCD
- jz .vm86_int_n
-; IN AL,<imm>
- cmp al,0xE4
- jz .vm86_in_al_imm
-; IN AX,<imm>
- cmp al,0xE5
- jz .vm86_in_ax_imm
-; OUT <imm>,AL
- cmp al,0xE6
- jz .vm86_out_imm_al
-; OUT <imm>,AX
- cmp al,0xE7
- jz .vm86_out_imm_ax
-; IN AL,DX
- cmp al,0xEC
- jz .vm86_in_al_dx
-; IN AX,DX
- cmp al,0xED
- jz .vm86_in_ax_dx
-; OUT DX,AL
- cmp al,0xEE
- jz .vm86_out_dx_al
-; OUT DX,AX
- cmp al,0xEF
- jz .vm86_out_dx_ax
-; CLI?
- cmp al,0xFA
- jz .vm86_cli
-; STI?
- cmp al,0xFB
- jz .vm86_sti
-; PUSHF?
- cmp al,0x9C
- jz .vm86_pushf
-; POPF?
- cmp al,0x9D
- jz .vm86_popf
-; PUSHFD?
- cmp ax,0x9C66
- jz .vm86_pushfd
-; POPFD?
- cmp ax,0x9D66
- jz .vm86_popfd
-; IRET?
- cmp al,0xCF
- jz .vm86_iret
-; well then I don't know
- call interrupt_routine_halt_prepare
- mov edx,0xD
- mov esi,str_v86_unknown
- jmp fault_jmp_unhandled
-
-.vm86_in_al_imm:add int_EIP,2 ; EIP += 2
- movzx edx,ah ; I/O port number in second byte
- mov ecx,1 ; ecx = size of I/O
- call on_vm86_io_read
- mov int_AL,al ; eax = byte value
- int_exit
-
-.vm86_in_ax_imm:add int_EIP,2 ; EIP += 2
- movzx edx,ah ; I/O port number in second byte
- mov ecx,2 ; ecx = size of I/O
- call on_vm86_io_read
- mov int_AX,ax ; eax = byte value
- int_exit
-
-.vm86_in_al_dx: inc int_EIP ; EIP += 1
- mov edx,int_EDX ; edx = port number
- and edx,0xFFFF
- mov ecx,1 ; ecx = size of I/O
- call on_vm86_io_read
- mov int_AL,al ; eax = byte value
- int_exit
-
-.vm86_in_ax_dx: inc int_EIP ; EIP += 1
- mov edx,int_EDX ; edx = port number
- and edx,0xFFFF
- mov ecx,2 ; ecx = size of I/O
- call on_vm86_io_read
- mov int_AX,ax ; eax = byte value
- int_exit
-
-.vm86_out_imm_al:add int_EIP,2 ; EIP += 2
- movzx edx,ah ; I/O port number in second byte
- movzx eax,int_AL ; eax = byte value
- mov ecx,1 ; ecx = size of I/O
- call on_vm86_io_write
- int_exit
-
-.vm86_out_imm_ax:add int_EIP,2 ; EIP += 2
- movzx edx,ah ; I/O port number in second byte
- mov eax,int_EAX
- and eax,0xFFFF
- mov ecx,2 ; ecx = size of I/O
- call on_vm86_io_write
- int_exit
-
-.vm86_out_dx_al:inc int_EIP ; EIP += 1
- mov edx,int_EDX ; edx = port number
- and edx,0xFFFF
- movzx eax,int_AL ; eax = byte value
- mov ecx,1 ; ecx = size of I/O
- call on_vm86_io_write
- int_exit
-
-.vm86_out_dx_ax:inc int_EIP ; EIP += 1
- mov edx,int_EDX ; edx = port number
- and edx,0xFFFF
- mov eax,int_EAX
- and eax,0xFFFF
- mov ecx,2 ; ecx = size of I/O
- call on_vm86_io_write
- int_exit
-
-.vm86_pushfd: push es
- mov bx,FLAT32_SEL
- mov es,bx
- sub int_v86_ESP,4 ; push DWORD
- jc vm86_stack_overflow
- call vm86_ss_esp_to_phys ; EAX = SS:SP physical mem location
- mov ebx,int_EFLAGS ; retrieve FLAGS
- mov [es:eax],ebx ; store on stack
- pop es
- add int_EIP,2
- int_exit
-
-.vm86_popfd: push es
- mov bx,FLAT32_SEL
- mov es,bx
- call vm86_ss_esp_to_phys ; EAX = SS:SP physical mem location
- add int_v86_ESP,4 ; pop DWORD
- jc vm86_stack_overflow
- mov ebx,[es:eax] ; retrieve from stack
- or ebx,0x20000 ; don't let the guest disable virtual 8086 mode
- mov int_EFLAGS,ebx ; place in FLAGS
- pop es
- add int_EIP,2
- int_exit
-
-.vm86_pushf: push es
- mov bx,FLAT32_SEL
- mov es,bx
- sub int_v86_ESP,2 ; push WORD
- jc vm86_stack_overflow
- call vm86_ss_esp_to_phys ; EAX = SS:SP physical mem location
- mov bx,int_FLAGS ; retrieve FLAGS
- mov [es:eax],bx ; store on stack
- pop es
- add int_EIP,1
- int_exit
-
-.vm86_popf: push es
- mov bx,FLAT32_SEL
- mov es,bx
- call vm86_ss_esp_to_phys ; EAX = SS:SP physical mem location
- add int_v86_ESP,2 ; pop WORD
- jc vm86_stack_overflow
- mov bx,[es:eax] ; retrieve from stack
- mov int_FLAGS,bx ; place in FLAGS
- pop es
- add int_EIP,1
- int_exit
-
-.vm86_iret: push es
- mov bx,FLAT32_SEL
- mov es,bx
- call vm86_ss_esp_to_phys ; EAX = SS:SP physical mem location
- add int_v86_ESP,6 ; pop interrupt stack frame
- jc vm86_stack_overflow
- xor ebx,ebx
- mov bx,[es:eax+0] ; EBX = IP
- mov int_EIP,ebx
- mov bx,[es:eax+2] ; EBX = CS
- mov int_CS,bx
- mov bx,[es:eax+4] ; EBX = FLAGS
- mov int_FLAGS,bx
- pop es
- int_exit
-
-.vm86_cli: and int_EFLAGS,~0x200 ; IF=0
- inc int_EIP
- int_exit
-
-.vm86_sti: or int_EFLAGS,0x200 ; IF=1
- inc int_EIP
- int_exit
-
-.vm86_int3: inc int_EIP ; EIP++
- mov eax,3
- call vm86_push_interrupt
- int_exit
-
-.vm86_int_n: movzx eax,ah ; AL=CD AH=intnum
- add int_EIP,2 ; EIP += 2
- call vm86_push_interrupt
- int_exit
-
-.not_vm86: call interrupt_routine_halt_prepare
- call edx_esi_default_int_str
- jmp fault_jmp_unhandled
-
-interrupt_routine:
- int_entry
- mov ax,FLAT32_SEL
- mov es,ax
- cmp int_INTNUM,RM_INT_API ; interrupts sent to our RM_INT_API are handled directly
- jz .rm_int_api
- test int_EFLAGS,0x20000 ; did this happen from v86 mode?
- jz .not_vm86
-
-; okay then, there are several reasons such interrupts fire.
- mov al,int_INTNUM_b
-; INT 15H interception
- cmp al,0x15
- jz .vm86_int15
-; Anything int >= 0x14 on
- cmp al,0x14
- jae .vm86_intN
-; INT 0x03 debug interrupt FIXME is this needed?
- cmp al,0x03
- jz .vm86_int3
-; INT 0x01 debug trap FIXME is this needed?
- cmp al,0x01
- jz .vm86_int1
-; INT 0x07 COPROCESSOR NOT PRESENT (vm86 task used a floating point instruction)
- cmp al,0x07
- jz .fpu_7
-
- call interrupt_routine_halt_prepare
- call edx_esi_default_int_str
- jmp fault_jmp_unhandled
-
-; COPROCESSOR NOT PRESENT. USUALLY SIGNALLED AFTER TASK SWITCH ON FIRST FPU INSTRUCTION.
-.fpu_7: clts
- int_exit
-
-.vm86_int1: mov eax,1
- call vm86_push_interrupt
- and int_EFLAGS,~0x100 ; clear trap flag
- int_exit
-
-.vm86_int3: mov eax,3
- call vm86_push_interrupt
- int_exit
-
-.vm86_intN: mov eax,int_INTNUM
- call vm86_push_interrupt
- int_exit
-
-; INT 15h; we must intercept AH=87h for extended memory programs to work properly within our VM86 environment
-.vm86_int15: mov ebx,int_EAX
- cmp bh,0x87
- jz .vm86_int15_87
-; carry it forward to the BIOS
- mov eax,int_INTNUM
- call vm86_push_interrupt
- int_exit
-
-; INT 15H AH=87h
-.vm86_int15_87: xor eax,eax
- mov ax,int_v86_ES
- shl eax,4
- and int_ESI,0xFFFF
- add eax,int_ESI
- mov ecx,int_ECX
- and ecx,0xFFFF
-; ECX = count of WORDs, EAX = physical memory addr of GDT
- mov esi,[es:eax+0x10+2]
- and esi,0xFFFFFF
- mov edi,[es:eax+0x18+2]
- and edi,0xFFFFFF
-; ESI = physical memory addr (src), EDI = physical memory addr (dst)
- movzx ebx,byte [es:eax+0x10+7]
- shl ebx,24
- or esi,ebx
- movzx ebx,byte [es:eax+0x18+7]
- shl ebx,24
- or edi,ebx
-; carry out the actual copy
- push ds
- mov ax,es
- mov ds,ax
- cld
- rep movsw
- pop ds
-; signal success
- mov int_EAX,0
- int_exit
-
-.not_vm86: call interrupt_routine_halt_prepare
- call edx_esi_default_int_str
- jmp fault_jmp_unhandled
-.rm_int_api: mov eax,int_EAX
- cmp eax,0xAABBAABB ; command to unload
- jz .rm_int_api_unload
- cmp eax,0xAABBAA55 ; detection
- jz .rm_int_api_detect
-; unknown command
- mov int_EAX,eax
- call interrupt_routine_halt_prepare
- call edx_esi_default_int_str
- jmp fault_jmp_unhandled
-.rm_int_api_unload:
- mov eax,int_v86_ESP
- mov [unload_int_stk+0],ax
- mov ax,int_v86_SS
- mov [unload_int_stk+2],ax
-
- mov eax,int_EIP
- mov [unload_int_ret+0],ax
- mov ax,int_CS
- mov [unload_int_ret+2],ax
-
- mov ax,DATA32_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov esp,stack_init
- jmp CODE32_SEL:_exit_from_prot32
-.rm_int_api_detect:
- mov int_EAX,0xBBAABB33
- int_exit
-edx_esi_default_int_str:
- mov edx,int_INTNUM
- cmp edx,0x13
- jle .l1
- mov edx,0x13
-.l1: xor esi,esi
- mov si,word [(edx*2)+interrupt_0x00_strs]
- mov edx,int_INTNUM
- ret
-interrupt_routine_halt_prepare: ; <====== SET ESI = address of string to print. Trashes EAX.
- xor eax,eax
- mov dword [unhandled_fault_var_opcode],eax
- mov eax,int_EAX
- mov dword [unhandled_fault_var_eax],eax
- mov eax,int_EBX
- mov dword [unhandled_fault_var_ebx],eax
- mov eax,int_ECX
- mov dword [unhandled_fault_var_ecx],eax
- mov eax,int_EDX
- mov dword [unhandled_fault_var_edx],eax
- mov eax,int_ESI
- mov dword [unhandled_fault_var_esi],eax
- mov eax,int_EDI
- mov dword [unhandled_fault_var_edi],eax
- mov eax,int_EBP
- mov dword [unhandled_fault_var_ebp],eax
- mov eax,int_ESP
- mov dword [unhandled_fault_var_esp],eax
- mov eax,int_EIP
- mov dword [unhandled_fault_var_eip],eax
- mov eax,int_ERRCODE
- mov dword [unhandled_fault_var_errcode],eax
- xor eax,eax
- mov ax,int_ES
- mov word [unhandled_fault_var_es],ax
- mov ax,int_DS
- mov word [unhandled_fault_var_ds],ax
- mov ax,int_CS
- mov word [unhandled_fault_var_cs],ax
- mov ax,fs
- mov word [unhandled_fault_var_fs],ax
- mov ax,gs
- mov word [unhandled_fault_var_gs],ax
- mov ax,ss
- mov word [unhandled_fault_var_ss],ax
- mov eax,cr0
- mov dword [unhandled_fault_var_cr0],eax
- mov eax,cr3
- mov dword [unhandled_fault_var_cr3],eax
- mov eax,cr4
- mov dword [unhandled_fault_var_cr4],eax
- mov eax,int_EFLAGS
- mov dword [unhandled_fault_var_eflags],eax
- test eax,0x20000 ; was the VM flag set in EFLAGS when it happened?
- jnz .v86_mode
- test int_CS,3 ; did we come from ring 1/2/3?
- jz .no_escalation
-; ESP needs to reflect it's contents prior to jumping to ring 0
- mov eax,int_v86_ESP
- mov dword [unhandled_fault_var_esp],eax
-.no_escalation: ret
-; the segment registers need to reflect what they were in vm86 mode
-.v86_mode: xor eax,eax
- mov ax,int_v86_ES
- mov word [unhandled_fault_var_es],ax
- mov ax,int_v86_DS
- mov word [unhandled_fault_var_ds],ax
- mov ax,int_v86_FS
- mov word [unhandled_fault_var_fs],ax
- mov ax,int_v86_GS
- mov word [unhandled_fault_var_gs],ax
- mov ax,int_v86_SS
- mov word [unhandled_fault_var_ss],ax
- mov eax,int_v86_ESP
- mov dword [unhandled_fault_var_esp],eax
-; we also might want to know what opcodes were involved
- push es
- mov ax,FLAT32_SEL
- call vm86_cs_eip_to_phys
- mov ebx,[es:eax]
- mov dword [unhandled_fault_var_opcode],ebx
- pop es
- ret
-
-; ================ INT 67h EMM/VCPI entry point
-; TODO: At some point this code needs to be written to a) reflect the INT 67H call back to v86 mode if it's not EMM/VCPI functions
-; and b) chain to v86 mode if the return address CS:IP is not the real-mode INT 67H handler we installed (so that other
-; programs can hook the interrupt on top of us)
-interrupt_routine_emm:
- int_entry
- mov eax,int_EAX
- cmp ah,0DEh
- jz .vcpi
- cmp ah,040h
- jl .pass
- cmp ah,05Eh
- jae .pass
- jmp .emm
- int_exit
-.pass: jmp emm_unhandled
-; VCPI processing (AH=0xDE)
-.vcpi: cmp al,0x0C
- ja emm_unhandled
- movzx eax,al
- jmp word [vcpi_functions+(eax*2)]
-; EMM processing (AH=0x40...0x5D)
-.emm: sub ah,0x40
- movzx eax,ah
- jmp word [emm_functions+(eax*2)]
-
-emm_unhandled:
-vcpi_unhandled:
- call interrupt_routine_halt_prepare
- mov edx,67h
- mov esi,str_unknown_emm_vcpi_call
- jmp fault_jmp_unhandled
-
-; VCPI call table
-vcpi_functions: dw vcpi00_detect ; 0x00
- dw vcpi01_get_pm_if ; 0x01
- dw vcpi_unhandled ; 0x02
- dw vcpi03_free_pages ; 0x03
- dw vcpi04_alloc_page ; 0x04
- dw vcpi05_free_page ; 0x05
- dw vcpi06_get_phys_addr ; 0x06
- dw vcpi_unhandled ; 0x07
- dw vcpi_unhandled ; 0x08
- dw vcpi_unhandled ; 0x09
- dw vcpi0A_8259A_mapping ; 0x0A
- dw vcpi_unhandled ; 0x0B
- dw vcpi0C_enter_pm ; 0x0C
-
-; emm call table
-emm_functions: dw emm40_get_status ; 0x40
- dw emm41_get_pfa ; 0x41
- dw emm42_get_unalloc_page_count ; 0x42
- dw emm43_alloc_pages ; 0x43
- dw emm44_map_handle_page ; 0x44
- dw emm45_dealloc_pages ; 0x45
- dw emm46_get_version ; 0x46
- dw emm47_save_page_map ; 0x47
- dw emm48_restore_page_map ; 0x48
- dw emm_unhandled ; 0x49
- dw emm_unhandled ; 0x4A
- dw emm4B_get_handle_count ; 0x4B
- dw emm4C_get_handle_pages ; 0x4C
- dw emm4D_get_all_handle_pages ; 0x4D
- dw emm4E_combo ; 0x4E
- dw emm4F_combo ; 0x4F
- dw emm50_combo ; 0x50
- dw emm51_realloc_pages ; 0x51
- dw emm52_combo ; 0x52
- dw emm53_combo ; 0x53
- dw emm54_combo ; 0x54
- dw emm55_combo ; 0x55
- dw emm56_combo ; 0x56
- dw emm57_combo ; 0x57
- dw emm58_combo ; 0x58
- dw emm59_combo ; 0x59
- dw emm5A_combo ; 0x5A
- dw emm5B_combo ; 0x5B
- dw emm5C_prepare_warmboot ; 0x5C
- dw emm5D_combo ; 0x5D
-
-; 8042 trapping state
-trap_8042_mode db 0x00
-; port 92 trapping
-fake_port_92 db 0x02 ; the reason we save this is some programs insist on
- ; reading back to check. if we forced bits the program
- ; will get stuck in a loop.
-
-; VCPI I/O write
-; in: EDX=port number EAX/AX/AL=byte value to write ECX=I/O size
-; out: EAX/AX/AL=byte value to return
-on_vm86_io_write: cmp edx,0x64
- jz .write_8042_controller
- cmp edx,0x92
- jz .write_port_A_92h
-.unknown_port: ret ; IGNORE
-.write_8042_controller: cmp byte [trap_8042_mode],0xD1 ; trap Write Output Port bitfield
- jz .write_8042_controller_out
-; now match the command directly
- cmp al,0xF0 ; trap attempts to pulse output bits
- jae .write_8042_controller_outpulse
- cmp al,0xD1 ; trap Write Output Port
- jz .write_8042_controller_out_and_latch
-; command is OK, pass it through
- out 0x64,al
- ret
-; the previous byte was the Write Output command, so the next byte is the actual bits to write. We must ensure A20 is on.
-.write_8042_controller_out: or al,0x02 ; ensure bit 1 (A20 gate) is always on
- out 0x64,al
- mov byte [trap_8042_mode],0x00
- ret
-; the program attempted to pulse output bits. silently ignore.
-.write_8042_controller_outpulse:ret
-; the program sent us a command that we pass through, but we must modify the data byte as it passes
-.write_8042_controller_out_and_latch:
- mov byte [trap_8042_mode],al
- out 0x64,al ; then pass the command through
- ret
-; the program is writing port 0x92 to try and fiddle with A20
-.write_port_A_92h: mov byte [fake_port_92],al ; store what the program wrote
- or al,2 ; make sure A20 gate is on
- and al,0xFE ; don't let them reset CPU
- out 0x92,al ; then let it through
- ret
-
-; VCPI I/O read
-; in: EDX=port number ECX=I/O size
-; out: EAX/AX/AL=byte value to return
-on_vm86_io_read: cmp edx,0x64
- jz .read_8042_controller
- cmp edx,0x92
- jz .read_port_A_92h
-.unknown_port: xor eax,eax ; return 0xFF
- dec eax
- ret
-.read_8042_controller: in al,0x64 ; let it through
- movzx eax,al
- ret
-.read_port_A_92h: movzx eax,byte [fake_port_92] ; return last written value
- ret
-
-; VCPI protected mode entry (32-bit)
-vcpi_pm_entry: pm_int_entry
- call interrupt_routine_halt_prepare
- mov edx,67h
- mov esi,str_unknown_emm_vcpi_pm_call
- jmp fault_jmp_unhandled
- pm_int_exit
-
-; AX=0xDE00 VCPI detect
-vcpi00_detect: mov int_EAX,0 ; present
- mov int_EBX,0x0100 ; version v1.0
- int_exit
-
-; AX=0xDE01 VCPI get protected mode interface
-vcpi01_get_pm_if: mov ax,FLAT32_SEL
- mov es,ax
-; fill page table ES:DI and advance DI += 4096 on return to client
- xor edi,edi
- mov di,int_v86_ES
- shl edi,4
- add edi,int_EDI ; EDI = (ES<<4)+DI
- add int_EDI,4096 ; client (E)DI += 4
-; make fake page table for first 4MB that is 1:1 identity mapping
- mov ecx,4096>>2
- xor ebx,ebx
- cld
-.pmfill: lea eax,[ebx+0x007] ; EAX = PTE: base address + present + read/write, user
- add ebx,0x1000
- stosd
- loop .pmfill
-
-; then fill in the GDT table given by the client
- cld
- xor edi,edi
- mov di,int_v86_DS
- shl edi,4
- add edi,int_ESI ; EDI = (DS<<4)+SI
- ; CODE
- lea esi,[gdt+(CODE32_SEL&0xFFF8)] ; ESI = our code32 GDT
- lodsd ; ****COPY****
- stosd
- lodsd
- stosd
- ; DATA (not that it matters)
- lea esi,[gdt+(DATA32_SEL&0xFFF8)] ; ESI = our data32 GDT
- lodsd ; ****COPY****
- stosd
- lodsd
- stosd
- ; DATA (not that it matters)
- lea esi,[gdt+(FLAT32_SEL&0xFFF8)] ; ESI = our data32 GDT
- lodsd ; ****COPY****
- stosd
- lodsd
- stosd
-
- mov int_EAX,0 ; OK, no error
- mov int_EBX,vcpi_pm_entry ; our VCPI entry point
- int_exit
-
-; AX=0xDE03 VCPI get free pages:
-vcpi03_free_pages: mov int_EAX,0 ; OK
- mov int_EDX,(4*1024*1024)/4096 ; just report 4MB and be done with it
- int_exit
-
-; AX=0xDE04 VCPI alloc page:
-vcpi04_alloc_page: mov ax,FLAT32_SEL
- mov es,ax
- mov esi,[vcpi_alloc_bitmap_phys]
- mov ecx,[vcpi_alloc_bitmap_size]
- cld
-.scan: mov al,byte [es:esi]
- cmp al,0xFF
- jnz .found
- inc esi
- dec ecx
- jnz .scan
-.not_found: mov int_EAX,0x8800 ; not found
- mov int_EDX,0
- int_exit
-.found: not al
- xor ah,ah
- xor ebx,ebx
- bsf bx,ax ; BX=# of bit that is zero
- jz .bmp_error ; ZF=0 or else
- mov cl,bl
- mov al,1
- shl al,cl
- or byte [es:esi],al
- sub esi,[vcpi_alloc_bitmap_phys]
- lea eax,[esi*8+ebx] ; EAX = page number
- shl eax,12 ; EAX = page address
- add eax,[vcpi_alloc_pages_phys]
- mov int_EDX,eax ; EDX = physical page #
- mov int_EAX,0
- int_exit
-.bmp_error: call interrupt_routine_halt_prepare
- mov edx,67h
- mov esi,str_vcpi_alloc_page_bug
- jmp fault_jmp_unhandled
-
-; AX=0xDE05 VCPI alloc page:
-vcpi05_free_page: mov ax,FLAT32_SEL
- mov es,ax
-
- mov edx,int_EDX
- sub edx,[vcpi_alloc_pages_phys]
- jc .not_found
- shr edx,12
- mov esi,edx
- shr esi,3
- cmp esi,[vcpi_alloc_bitmap_size]
- jae .not_found
- mov ecx,edx
- and ecx,7
- mov al,1
- shl al,cl
- not al
- add esi,[vcpi_alloc_bitmap_phys]
- int 3 ; <- FIXME: Remove debug b.p. when you verify this works
- and [es:esi],al
- int_exit
-.not_found: mov int_EAX,0x8A00
- mov eax,0xABCD1234 ; <- DEBUG: remove when you verify this works
- int 3
- int_exit
-
-; AX=0xDE06 VCPI get physical address of 4K page
-vcpi06_get_phys_addr: mov eax,int_ECX
- and eax,0xFFFF
- shl eax,12
- mov int_EDX,eax
- mov int_EAX,0
- int_exit
-
-; AX=0xDE0A VCPI get Interrupt Vector Mappings
-vcpi0A_8259A_mapping: mov int_EAX,0
- mov int_EBX,IRQ_BASE_INT ; 1st vector for master PIC
- mov int_ECX,IRQ_BASE_INT+8 ; 1st vector for slave PIC
- int_exit
-
-; AX=0xDE0C VCPI enter protected mode
-vcpi0C_enter_pm: call interrupt_routine_halt_prepare
- mov edx,67h
- mov esi,str_vcpi_pm_not_supported
- jmp fault_jmp_unhandled
-
-; AH=0x40 Get Status
-emm40_get_status: mov int_EAX,0 ; we're OK
- int_exit
-
-emm41_get_pfa: mov int_EAX,0 ; OK
- mov int_EBX,0xC000 ; FIXME: We don't provide ANY pages, just make the VGA BISO the "page frame"
- int_exit
-
-emm42_get_unalloc_page_count: mov int_EAX,0 ; OK
- mov int_EBX,0 ; no pages free
- mov int_EDX,0 ; no pages at all
- int_exit
-
-emm43_alloc_pages: mov int_EAX,0x8700 ; not enough memory
- mov int_EDX,0 ; handle=0
- int_exit
-
-emm44_map_handle_page: mov int_EAX,0x8A00 ; out of range
- int_exit
-
-emm45_dealloc_pages: mov int_EAX,0 ; uhhhh... OK
- int_exit
-
-emm46_get_version: mov int_EAX,0x40 ; version 4.0
- int_exit
-
-emm47_save_page_map: jmp emm_unhandled
-emm48_restore_page_map: jmp emm_unhandled
-emm4B_get_handle_count: jmp emm_unhandled
-emm4C_get_handle_pages: jmp emm_unhandled
-emm4D_get_all_handle_pages: jmp emm_unhandled
-emm4E_combo: jmp emm_unhandled
-emm4F_combo: jmp emm_unhandled
-emm50_combo: jmp emm_unhandled
-emm51_realloc_pages: jmp emm_unhandled
-emm52_combo: jmp emm_unhandled
-emm53_combo: jmp emm_unhandled
-emm54_combo: jmp emm_unhandled
-emm55_combo: jmp emm_unhandled
-emm56_combo: jmp emm_unhandled
-emm57_combo: jmp emm_unhandled
-
-emm58_combo: mov eax,int_EAX
- cmp al,0
- jz .func_5800
- jmp emm_unhandled
-.func_5800: ; ========================== INT 67h AX=5800h
- mov int_EAX,0 ; OK
- mov int_ECX,0 ; the returned array is zero entries in length
- int_exit
-
-emm59_combo: jmp emm_unhandled
-emm5A_combo: jmp emm_unhandled
-emm5B_combo: jmp emm_unhandled
-emm5C_prepare_warmboot: jmp emm_unhandled
-emm5D_combo: jmp emm_unhandled
-
-
-%unmacro int_entry 0
-%unmacro int_exit 0
-%undef int_ES
-%undef int_DS
-%undef int_EDI
-%undef int_ESI
-%undef int_EBP
-%undef int_ESP
-%undef int_EBX
-%undef int_EDX
-%undef int_ECX
-%undef int_EAX
-%undef int_INTNUM
-%undef int_INTNUM_b
-%undef int_ERRCODE
-%undef int_EIP_w
-%undef int_EIP
-%undef int_CS
-%undef int_EFLAGS
-%undef int_v86_SS
-%undef int_v86_ES
-%undef int_v86_DS
-%undef int_v86_FS
-%undef int_v86_GS
-
-; ========== FAULT COLLECTION ROUTINE. SS:ESP should point to fault. If the exception does not push an error code,
-; then the caller must push a dummy error code
-; if privilege escalation was involved (stack switching) then retrieve SS:ESP at fault from the stack frame.
-; else retrieve from actual SS:ESP registers
-fault_jmp_unhandled:
- jmp CODE16_SEL:.thunk16
- bits 16
-.thunk16: mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
- mov sp,stack_init
- jmp unhandled_fault_errcode
- bits 32
-
-; ============= cleanup, exit to DOS (from 32-bit protected mode)
-_exit_from_prot32:
- jmp CODE16_SEL:.entry16
- bits 16
-.entry16: mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov esp,stack_init
-
-; ============= cleanup, exit to DOS (from 16-bit protected mode)
-_exit_from_prot16:
- mov ax,DATA16_SEL
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
-
- ; overwrite the far jmp's segment value
- mov ax,[my_realmode_seg]
- mov word [.real_hackme+3],ax
- mov esp,stack_init
-
- mov eax,0x00000010
- mov cr0,eax
-
- lidt [idtr_real]
- lgdt [gdtr_real]
-
-.real_hackme: jmp 0:.real_entry
-.real_entry: mov ax,[cs:my_realmode_seg]
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ss,ax
- mov sp,stack_init
-
-; reprogram the PIC back to what normal DOS expects: IRQ 0-7 => INT 8-15
- mov al,0x10 ; ICW1 A0=0
- out 20h,al
- mov al,0x08 ; ICW2 A0=1
- out 21h,al
- mov al,0x04 ; ICW3 A0=1 slave on IRQ 2
- out 21h,al
-
- mov al,0x10 ; ICW1 A0=0
- out 0xA0,al
- mov al,0x70 ; ICW2 A0=1
- out 0xA1,al
- mov al,0x02 ; ICW3 A0=1
- out 0xA1,al
-
-; remove our INT 66h API
- xor ax,ax
- mov es,ax
- mov word [es:(RM_INT_API*4)],ax
- mov word [es:(RM_INT_API*4)+2],ax
-
-; free HIMEM.SYS blocks
- test word [himem_sys_buffer_handle],0
- jz .no_himem_sys
- mov ah,0Dh ; HIMEM.SYS function 0Dh unlock memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
- mov ah,0Ah ; HIMEM.SYS function 0Ah free memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
-.no_himem_sys:
-
-; if we already exited as a TSR...
- test byte [i_am_tsr],1
- jnz .tsr_exit
-
-; time to exit to DOS
- mov dx,str_exit_to_dos
- jmp _exit_with_msg
-
-; ============= ALTERNATE EXIT IF WE ALREADY EXITED AS TSR
-.tsr_exit:
- mov ax,cs
- mov es,ax ; ES = our code segment which is also our PSP segment
- mov ah,0x49 ; function 49h free memory block
- clc
- int 21h
- jnc .tsr_exit_free_ok
- mov dx,str_cannot_free_self
- call dos_puts
-.tsr_exit_free_ok:
- cli
- mov ax,[cs:unload_int_stk+0] ; offset
- add ax,6 ; discard prior frame
- mov sp,ax
- mov ax,[cs:unload_int_stk+2] ; segment
- mov ss,ax
-
- mov dx,str_exit_to_dos
- call dos_puts
-
- cmp word [himem_sys_buffer_handle],0 ; if there is a handle to free, then do it
- jz .no_handle
- mov ah,0Dh ; HIMEM.SYS function 0Dh unlock memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
- mov ah,0Ah ; HIMEM.SYS function 0Ah free memory block
- mov dx,word [himem_sys_buffer_handle]
- call far word [himem_sys_entry]
-.no_handle:
-
- cli
-
- mov al,020h
-
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
-
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
-
- in al,61h
- in al,61h
- in al,61h
- in al,61h
-
- sti
-
- jmp far word [cs:unload_int_ret]
-
-; ============= UNHANDLED FAULT HANDLER (16-bit code)
-; input: EDX = Number of interrupt
-; SI = Textual string of fault
-;
-unhandled_fault_errcode:
- cli
- mov ax,DATA16_SEL
- mov ds,ax
-
- mov ax,[cs:my_realmode_seg]
- mov word [.real16jmp+3],ax
-
- mov ax,FLAT16_SEL
- mov ds,ax
- mov es,ax
- mov ss,ax
-
- lgdt [cs:gdtr_real]
- lidt [cs:idtr_real]
-
- ; crash-thunk to real mode
- mov eax,0x00000010
- mov cr0,eax
-.real16jmp: jmp 0:.real16
-.real16: mov ax,[cs:my_realmode_seg]
- mov ds,ax
- mov ss,ax
- xor ax,ax
- mov es,ax
-
- mov ax,3
- int 10h
-
- cld
- mov ax,0x4E20
- mov ecx,80*25
- mov edi,0xB8000
- a32 rep stosw
-
- ; print exception name on screen
- mov edi,0xB8000
- call .unhandled_print
- mov al,' ' ; +space plus AH still contains upper byte from .unhandled_print
- a32 stosw
-
- ; then the number (in EDX) write to DS:DI
- mov eax,edx
- push edi
- mov edi,scratch_str
- call eax_to_hex_16_dos
- lea si,[di+6] ; only the last two hex digits
- pop edi
- call .unhandled_print
-
- ; print the registers.
- ; during this loop: SI = print list EDI = location on screen to draw [ESP] = location on screen of row start
- mov edi,0xB8000+(160*2) ; two lines down
- push edi
- mov si,printlist_32
-.regprint32: lodsw
- or ax,ax
- jz .regprint32e ; AX=0 STOP
- dec ax
- jz .regprint32nl ; AX=1 GO TO NEW LINE
- push si
- mov si,ax ; SI=AX=address of variable name
- inc si
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (':')
- a32 stosw
- lodsw ; SI=address of variable
- push si
- mov si,ax
- mov eax,[si]
- push edi
- mov edi,scratch_str
- call eax_to_hex_16_dos
- mov esi,edi
- pop edi
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (' ')
- a32 stosw
- jmp .regprint32
-.regprint32nl: pop edi
- add edi,160 ; move to next line, save back to [ESP]
- push edi
- jmp .regprint32
-.regprint32e: pop edi
-
- add edi,160 ; next line...
-
- mov si,printlist_16
-.regprint16: lodsw
- or ax,ax
- jz .regprint16e ; AX=0 STOP
- dec ax
- jz .regprint16nl ; AX=1 GO TO NEW LINE
- push si
- mov si,ax ; SI=AX=address of variable name
- inc si
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (':')
- a32 stosw
- lodsw ; SI=address of variable
- push si
- mov si,ax
- xor eax,eax
- mov ax,[si]
- push edi
- mov edi,scratch_str
- call eax_to_hex_16_dos
- lea esi,[edi+4]
- pop edi
- call .unhandled_print
- pop si
- mov ax,0x4E00 | (' ')
- a32 stosw
- jmp .regprint16
-.regprint16nl: pop edi
- add edi,160 ; move to next line, save back to [ESP]
- push edi
- jmp .regprint16
-.regprint16e: mov si,str_mode_prot ; CPU mode
- test dword [unhandled_fault_var_eflags],0x20000
- jz .regprint_cpu_mode_not_v86
- mov si,str_mode_v86
-.regprint_cpu_mode_not_v86:
- call .unhandled_print
- pop edi
-
- mov al,020h
-
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
- out 0A0h,al
-
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
- out 20h,al
-
- sti
- jmp short $
-; ===== print on screen from DS:SI to ES:EDI
-.unhandled_print:
- lodsb
- cmp al,'$'
- jz .unhandled_printe
- mov ah,0x4E
- a32 stosw
- jmp .unhandled_print
-.unhandled_printe:
- ret
-
-; ============= Entry point (virtual 8086 mode)
-vm86_entry: mov ax,ds ; *DEBUG*
- mov ss,ax
-
- cli ; make sure the v86 monitor handles CLI
- sti ; ...and STI
- pushf ; ...and PUSHF
- popf ; ...and POPF
- pushfd ; ...32-bit PUSHF
- popfd ; ...32-bit POPF
- in al,21h ; ...IN?
- out 21h,al ; ...OUT?
-
- ; can I clear vm86 mode by clearing the VM bit?
- pushfd
- pop eax
- and eax,~0x20000
- push eax
- popfd
-
- ; NOW MAKE SURE PUSHF/POPF STORE THE VALUE ON-STACK LIKE THEY'RE SUPPOSED TO
- mov bx,sp
- mov word [ss:bx-2],0x5A5A
- pushf
- mov bx,sp
- cmp word [ss:bx],0x5A5A
- jnz .pushf_ok ; if the value DIDN'T CHANGE then the monitor failed to write FLAGS to stack
- mov ax,0
- jmp vm86_errcode
-.pushf_ok:
-
- ; DOES POPF WORK?
- mov ax,0x492
- push ax
- popf
- pushf
- pop ax
- and ax,0xFD6
- cmp ax,0x492
- jz .popf_ok
- mov ax,1
- jmp vm86_errcode
-.popf_ok:
-
- ; TEST 32-bit PUSHF
- mov bx,sp
- mov dword [ss:bx-4],0x5A5A5A5A
- pushfd
- mov bx,sp
- cmp dword [ss:bx],0x5A5A5A5A
- jnz .pushfd_ok ; if the value DIDN'T CHANGE then the monitor failed to write FLAGS to stack
- mov ax,2
- jmp vm86_errcode
-.pushfd_ok:
-
- ; DOES POPFD WORK?
- mov eax,0x492
- push eax
- popfd
- pushfd
- pop eax
- and eax,0xFD6
- cmp eax,0x492
- jz .popfd_ok
- mov ax,3
- jmp vm86_errcode
-.popfd_ok:
-
- ; IF I CLEAR INTERRUPT (CLI) AND THEN EXECUTE AN INTERRUPT, DOES IT COME BACK ENABLED?
- cli
- mov ah,0x0F ; INT 10 AH=0x0F which has no visisible effect
- int 10h
- pushf
- pop ax
- test ax,0x200
- jz .int_doesnt_enable
- mov ax,4
- jmp vm86_errcode
-.int_doesnt_enable:
-
- ; HELLO WORLD!
- mov si,str_vm86_hello
- call bios_puts
-
- ; TEST DEFERRED IRQ MECHANISM BY DELIBERATLEY HALTING FOR AWHILE
- cli
- mov ecx,0x1000000 ; delibrate slow countdown loop
-.l1: dec ecx
- jnz .l1
- sti
-
- ; for my next trick, I will exit to DOS as a TSR
- ; and allow the user to run the whole DOS kernel this way :)
- mov es,[cs:0x2C] ; locate our environment block and free it
- mov ah,0x49 ; function 49h free memory block
- int 21h
- jnc .env_free_ok
- mov ax,4
- jmp vm86_errcode
-.env_free_ok: mov word [cs:0x2C],0 ; rub out the ENV block
-
- ; setup our INT 66h API
- xor ax,ax
- mov es,ax
- mov word [es:(RM_INT_API*4)],realmode_api_entry
- mov ax,cs
- mov word [es:(RM_INT_API*4)+2],ax
-
- ; setup our INT 67h vector
- ; REMINDER: On exit you need to restore this vector
- mov ax,cs
- mov bx,rm_int_67_entry
- shr bx,4
- add ax,bx
- mov word [es:(0x67*4)+2],ax
- xor ax,ax
- mov word [es:(0x67*4)+0],ax
-
- ; finally, terminate and stay resident
- mov byte [i_am_tsr],1
- mov edx,the_end ; DX = memory in paragraphs to save
- add edx,15
- shr edx,4
- add edx,0x11 ; <-- FIXME: IS THIS NECESSARY?
- mov ah,0x31 ; function 31h terminate and stay resident
- int 21h
-
-; ============= "Secret Handshake" to exit back into the v86 monitor and shutdown the program (virtual 8086 mode)
-; TODO: Remove this, call into RM_INT_API instead
-vm86_exit: mov eax,0xAABBAABB
- int RM_INT_API
- hlt
-
-; ============= If any of our self-test fails, we draw DIRECTLY ON VGA RAM and hike back into the vm86 monitor ASAP.
-; if self-tests fail chances are calling the BIOS/DOS will cause major problems. AX=CODE
-vm86_errcode: mov bx,0xB800
- mov es,bx
- and ax,0xF
- or ax,0x4E30 ; AX = VGA alphanumeric code for that number
- mov [es:160],ax
- jmp vm86_exit
-
-; ============= Real-mode API entry (reflect to v86 monitor by executing an INT)
-; this would allow the trick to work even for programs that direct-call instead
-realmode_api_entry:
- int RM_INT_API
- iret
-
-; ============= Parse command line (from PSP segment)
-parse_argv: cld
- mov si,81h
-.scan: lodsb
- or al,al
- jz .done
- cmp al,0Dh
- jz .done
- cmp al,20h
- jz .scan
- cmp al,'-'
- jz .switch
- cmp al,'/'
- jz .switch
- ; FALL THROUGH WITH ZF=0 to return
-.done: ret
- ; AT THIS POINT: SI = just after the / or - in the switch
-.switch: lodsb
- cmp al,'?'
- jz .help
- cmp al,'A'
- jb .unknown_switch
- cmp al,'Z'
- ja .unknown_switch
- ; the A-Z switches are allowed to have "=NNNN" after them where N is some integer in hex or decimal
- sub al,'A'
- mov bl,al
- xor bh,bh ; BX = index into lookup table
- add bx,bx
- jmp word [bx+.switch_az]
-.fail: mov al,1
-.help: or al,al ; AL != 0 => ZF=0
- ret
-.unknown_switch:mov dx,str_unknown_switch
- call dos_puts
- lea dx,[si-2] ; step back two chars
- mov byte [si],'$'
- call dos_puts
- mov dx,str_crlf
- call dos_puts
- jmp .fail
-; ========== Switches CALL here if they need a numeric value to follow.
-; returns to caller if so, parsing as 16-bit integer returned in EAX. Else,
-; it discards the return address and jumps to the 'needs param' error message.
-.switch_needs_equ_check:
- cmp byte [si],'='
- jnz .switch_needs_equ_check_fail
- inc si
- cli
- xor eax,eax
- call ax_strtol_16
- ret
-.switch_needs_equ_check_fail:
- add sp,2 ; fall through
-.switch_needs_equ:
- mov dx,str_needs_equals
- call dos_puts
- jmp .fail
-; ========== /B=<number>
-.switch_buffer_size:
- call .switch_needs_equ_check
- shl eax,10
- mov [himem_sys_buffer_size],eax
- jmp .scan
-; ========== /U
-.switch_unload: mov byte [user_req_unload],1
- jmp .scan
-; ========== /I
-.switch_iopl: mov byte [user_req_iopl],0
- jmp .scan
-; ========== /C
-.switch_cache_disable:
- or dword [cr0_more],0x40000000
- jmp .scan
-; ========== /W
-.switch_writeback_disable:
- or dword [cr0_more],0x20000000
- jmp .scan
-; switch A-Z jump table
-.switch_az: dw .unknown_switch ; /A
- dw .switch_buffer_size ; /B=<number>
- dw .switch_cache_disable ; /C
- dw .unknown_switch ; /D
- dw .unknown_switch ; /E
- dw .unknown_switch ; /F
- dw .unknown_switch ; /G
- dw .unknown_switch ; /H
- dw .switch_iopl ; /I
- dw .unknown_switch ; /J
- dw .unknown_switch ; /K
- dw .unknown_switch ; /L
- dw .unknown_switch ; /M
- dw .unknown_switch ; /N
- dw .unknown_switch ; /O
- dw .unknown_switch ; /P
- dw .unknown_switch ; /Q
- dw .unknown_switch ; /R
- dw .unknown_switch ; /S
- dw .unknown_switch ; /T
- dw .switch_unload ; /U
- dw .unknown_switch ; /V
- dw .switch_writeback_disable ; /W
- dw .unknown_switch ; /X
- dw .unknown_switch ; /Y
- dw .unknown_switch ; /Z
-
-; register print list
-printlist_32: dw str_eax, unhandled_fault_var_eax
- dw str_ebx, unhandled_fault_var_ebx
- dw str_ecx, unhandled_fault_var_ecx
- dw str_edx, unhandled_fault_var_edx
- dw str_esi, unhandled_fault_var_esi
- dw str_edi, unhandled_fault_var_edi
- dw 1
- dw str_ebp, unhandled_fault_var_ebp
- dw str_esp, unhandled_fault_var_esp
- dw str_eip, unhandled_fault_var_eip
- dw str_eflags, unhandled_fault_var_eflags
- dw str_errcode, unhandled_fault_var_errcode
- dw str_cr0, unhandled_fault_var_cr0
- dw 1
- dw str_cr3, unhandled_fault_var_cr3
- dw str_cr4, unhandled_fault_var_cr4
- dw str_opcode, unhandled_fault_var_opcode
- dw 0
-printlist_16: dw str_cs, unhandled_fault_var_cs
- dw str_ds, unhandled_fault_var_ds
- dw str_es, unhandled_fault_var_es
- dw str_fs, unhandled_fault_var_fs
- dw str_gs, unhandled_fault_var_gs
- dw str_ss, unhandled_fault_var_ss
- dw 0
-
-; ============= bios_puts (print $-terminated string at DS:SI)
-bios_puts: cli
- cld
- push ax
- push bx
-.putsloop: lodsb
- cmp al,'$'
- jz .putsend
- mov ah,0x0E
- xor bx,bx
- int 10h
- jmp .putsloop
-.putsend: pop bx
- pop ax
- ret
-
-; ============= dos_puts (print $-terminated string at DS:DX)
-dos_puts: mov ah,09h
- int 21h
- ret
-
-; ============= read one digit from DS:SI return in AX (16-bit code)
-ax_strtol_16_single:mov al,[si]
- cmp al,'0'
- jb .no
- cmp al,'9'
- ja .no
- sub al,'0'
- xor ah,ah
- inc si
- clc
- ret
-.no: stc
- ret
-
-; ============= read from DS:SI and convert numerical string to integer value return in AX (16-bit code)
-ax_strtol_16: xor cx,cx
-.loop: push cx
- call ax_strtol_16_single
- pop cx
- jc .done
- mov bx,cx
- add bx,bx
- shl cx,3 ; BX = CX * 2, CX *= 8
- add cx,bx ; CX = (CX * 8) + (CX * 2) = CX * 10
- add cx,ax ; CX += new digit
- jmp .loop
-.done: mov ax,cx
- ret
-
-; ============= take AX and write to buffer (DS:SI) as hexadecimal string (16-bit code)
-al_to_hex_16_dos:mov byte [di+2],'$'
- jmp al_to_hex_16
-al_to_hex_16_nul:mov byte [di+2],0
-al_to_hex_16: push di
- push bx
- push ax
- xor bh,bh
- mov ah,al
- and al,0xF
- mov bl,al
- mov al,[bx+str_hex] ; AL' = str_hex[al]
- shr ah,4
- mov bl,ah
- mov ah,[bx+str_hex] ; AH' = str_hex[ah]
- mov [di+0],ah
- mov [di+1],al
- pop ax
- pop bx
- pop di
- ret
-
-; ============= take AX and write to buffer (DS:SI) as hexadecimal string (16-bit code)
-ax_to_hex_16_dos:mov byte [di+4],'$'
- jmp ax_to_hex_16
-ax_to_hex_16_nul:mov byte [di+4],0
-ax_to_hex_16: push di
- push ax
- mov al,ah
- call al_to_hex_16
- pop ax
- add di,2
- call al_to_hex_16
- pop di
- ret
-
-; ============= take EAX and write to buffer (DS:DI) as hexadecimal string (16-bit code)
-eax_to_hex_16_dos:mov byte [di+8],'$'
- jmp eax_to_hex_16
-eax_to_hex_16_nul:mov byte [di+8],0
-eax_to_hex_16: push di
- push eax
- shr eax,16
- call ax_to_hex_16
- pop eax
- add di,4
- call ax_to_hex_16
- pop di
- ret
-
-; ============= /U Unloading the resident copy of this program
-unload_this_program:
- smsw ax
- test al,1
- jnz .v86_active
- mov dx,str_not_loaded
- jmp _exit_with_msg
-.v86_active:
- xor ax,ax
- mov es,ax
- mov bx,[es:(RM_INT_API*4)]
- or cx,[es:(RM_INT_API*4)+2]
- cmp cx,0 ; if pointer is 0000:0000
- jz .v86_not_me
- mov eax,0xAABBAA55
- int RM_INT_API
- cmp eax,0xBBAABB33
- jnz .v86_not_me
-.v86_is_me: mov ax,cs
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov dx,str_removing_self
- call dos_puts
-; instruct it to remove itself
- mov eax,0xAABBAABB
- int RM_INT_API
-; exit, having done our job
- mov dx,str_crlf
- call dos_puts
- mov dx,str_unloaded
- jmp _exit_with_msg
-.v86_not_me: mov dx,str_v86_but_not_me
- jmp _exit_with_msg
-
-; ============= DATA: THESE EXIST IN THE .COM BINARY IMAGE
- section .data align=2
-himem_sys_buffer_size:dd (256*1024) ; DWORD [amount of extended memory to allocate]
-cr0_more: dd 0x00000000 ; cache disable, not write through
-str_require_386:db '386 or higher required$'
-str_removing_self:db 'Removing from memory',13,10,'$'
-str_v86_detected:db 'Virtual 8086 mode already active$'
-str_v86_but_not_me:db 'Virtual 8086 active, and its not me$'
-str_not_loaded: db 'Not resident in memory$'
-str_cannot_free_self:db 'Cannot free self from memory$'
-str_need_himem_sys:db 'HIMEM.SYS not installed$'
-str_himem_a20_error:db 'HIMEM.SYS failed to enable A20$'
-str_himem_alloc_err:db 'Unable to alloc extended memory$'
-str_himem_lock_err:db 'Unable to lock extended memory$'
-str_buffer_too_small:db 'Buffer too small$'
-str_buffer_too_large:db 'Buffer too large$'
-str_unloaded: db 'Unloaded',13,10,'$'
-str_buffer_at: db 'Buffer at: $'
-str_crlf: db 13,10,'$'
-str_hex: db '0123456789ABCDEF'
-str_help: db 'V86KERN [options]',13,10
- db 'Demonstration Virtual 8086 kernel/monitor',13,10
- db 13,10
- db 'Options start with - or /',13,10
- db ' /? Show this help',13,10
- db ' /B=... Set buffer size (in KB)',13,10
- db ' /U Unload the kernel',13,10
- db ' /I Run with IOPL=3 (trap CLI/STI/etc)',13,10
- db ' /C Disable memory cache',13,10
- db ' /W Disable write-back cache',13,10
- db '$'
-str_unknown_switch:db 'Unknown switch $'
-str_needs_equals:db 'Switch missing =...$'
-str_eax: db 'EAX$'
-str_ebx: db 'EBX$'
-str_ecx: db 'ECX$'
-str_edx: db 'EDX$'
-str_esi: db 'ESI$'
-str_edi: db 'EDI$'
-str_ebp: db 'EBP$'
-str_esp: db 'ESP$'
-str_eip: db 'EIP$'
-str_errcode: db 'ERR$'
-str_eflags: db 'FLG$'
-str_cr0: db 'CR0$'
-str_cr3: db 'CR3$'
-str_cr4: db 'CR4$'
-str_opcode: db 'OPC$'
-str_cs: db 'CS$'
-str_ds: db 'DS$'
-str_es: db 'ES$'
-str_fs: db 'FS$'
-str_gs: db 'GS$'
-str_ss: db 'SS$'
-str_mode_prot: db 'Protected mode$'
-str_mode_v86: db 'Virtual 8086 mode$'
-str_vm86_hello: db 'This text was printed by the Virtual 8086 mode component of this program',13,10,'$'
-str_fault_0x00: db 'Divide by Zero$'
-str_fault_0x01: db 'Debug$'
-str_fault_0x02: db 'NMI$'
-str_fault_0x03: db 'Breakpoint$'
-str_fault_0x04: db 'Overflow$'
-str_fault_0x05: db 'Boundary Check$'
-str_fault_0x06: db 'Invalid Opcode$'
-str_fault_0x07: db 'Coprocessor N/A$'
-str_fault_0x08: db 'Double Fault$'
-str_fault_0x09: db 'Coprocessor Segment Overrun$'
-str_fault_0x0A: db 'Invalid TSS$'
-str_fault_0x0B: db 'Segment Not Present$'
-str_fault_0x0C: db 'Stack Fault$'
-str_fault_0x0D: db 'General Protection Fault$'
-str_fault_0x0E: db 'Page Fault$'
-str_fault_0x0F: db 'Exception F$'
-str_fault_0x10: db 'FPU Error$'
-str_fault_0x11: db 'Alignment Check$'
-str_fault_0x12: db 'Machine Check$'
-str_fault_0x13: db 'SIMD/SSE Exception$'
-str_fault_unknown:db 'Unknown exception$'
-str_v86_unknown:db 'Unknown instruction in v86 mode$'
-str_v86_hlt_cli:db 'v86 halt with interrupts disabled$'
-str_v86_secret: db 'Inappropriate use of v86 secret handshake$'
-str_exit_to_dos:db 'Shutdown successful, exiting to DOS$'
-str_unknown_irq:db 'Unknown IRQ$'
-str_irq_deferred:db 'Deferred IRQ$'
-str_irq_1: db 'IRQ #1$'
-str_stack_overflow:db 'Stack overflow$'
-str_himem_corruption:db 'Extended memory corruption$'
-str_unexpected_int_not_v86:db 'Unexpected: IRQ not from within v86$'
-str_unknown_emm_vcpi_call:db 'Unknown EMM/VCPI call$'
-str_unknown_emm_vcpi_pm_call:db 'Unknown VCPI entry point call$'
-str_vcpi_alloc_page_bug:db 'VCPI page allocation bug check$'
-str_vcpi_pm_not_supported:db 'VCPI protected mode not implemented$'
-
-; ============= EMM/VCPI entry point redirection and "signature"
- align 16
-rm_int_67_entry:mov ah,0x84 ; AH=0x84 means "not defined"
- iret
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-rm_int_67_sig: db 'EMMXXXX0',0 ; DOS programs look for this signature relative to INT 67h segment
-
-; ============= VARIABLES: THESE DO NOT EXIST IN THE .COM FILE THEY EXIST IN MEMORY FOLLOWING THE BINARY IMAGE
- section .bss align=2
- align 8
-; ---------------------- STACK
-stack_base: resb 4096 ; char[4096+4]
-stack_init: resd 1 ; DWORD
-stack_top:
-scratch_str: resb 64 ; char[64]
-; ---------------------- STACK
-stack_base_vm86:resb 4096 ; char[4096+4]
-stack_init_vm86:resd 2 ; DWORD
-stack_top_vm86:
-; ---------------------- HIMEM.SYS state
-himem_sys_entry:resd 1 ; FAR POINTER
-himem_sys_buffer_phys:resd 1 ; DWORD [physical memory address]
-himem_sys_buffer_handle:resw 1 ; WORD [HIMEM.SYS handle]
-; ---------------------- my real mode segment
-my_realmode_seg:resw 1 ; WORD
-my_phys_base: resd 1 ; DWORD
-tss_phys_base: resd 1 ; DWORD base logical address of TSS
-tss_vm86_phys_base:resd 1 ; DWORD base logical address of TSS
-v86_raw_opcode: resd 1 ; DWORD
-; ---------------------- GDTR/IDTR
-gdtr_pmode: resq 1 ; LIMIT. BASE
-gdtr_real: resq 1 ; LIMIT, BASE
-idtr_pmode: resq 1 ; LIMIT, BASE
-idtr_real: resq 1 ; LIMIT, BASE
-; ---------------------- STATE
-irq_pending: resw 1
-user_req_unload:resb 1
-v86_if: resb 1
-; ---------------------- GLOBAL DESCRIPTOR TABLE
- resd 1
- align 8
-gdt: resq (MAX_SEL/8) ; 16 GDT entries
-; ---------------------- INTERRUPT DESCRIPTOR TABLE
- align 8
-idt: resq 256 ; all 256
-; ---------------------- STATE
-user_req_iopl: resb 1
-i_am_tsr: resb 1
-unload_int_ret: resd 1
-unload_int_stk: resd 1
-; ---------------------- VCPI allocation map and pages
-vcpi_alloc_bitmap_phys:resd 1
-vcpi_alloc_bitmap_size:resd 1
-vcpi_alloc_pages_phys:resd 1
-; ---------------------- WHEN DISPLAYING THE UNHANDLED FAULT DIALOG
-unhandled_fault_var_errcode:resd 1
-unhandled_fault_var_eax:resd 1
-unhandled_fault_var_ebx:resd 1
-unhandled_fault_var_ecx:resd 1
-unhandled_fault_var_edx:resd 1
-unhandled_fault_var_esi:resd 1
-unhandled_fault_var_edi:resd 1
-unhandled_fault_var_ebp:resd 1
-unhandled_fault_var_esp:resd 1
-unhandled_fault_var_eip:resd 1
-unhandled_fault_var_eflags:resd 1
-unhandled_fault_var_cr0:resd 1
-unhandled_fault_var_cr3:resd 1
-unhandled_fault_var_cr4:resd 1
-unhandled_fault_var_cs:resw 1
-unhandled_fault_var_ds:resw 1
-unhandled_fault_var_es:resw 1
-unhandled_fault_var_fs:resw 1
-unhandled_fault_var_gs:resw 1
-unhandled_fault_var_ss:resw 1
-unhandled_fault_var_opcode:resd 1
-; ---------------------- TSS
-tss_main: resb 128
-; ---------------------- VM86 TSS
-tss_vm86: resb 8192+128
-; ---------------------------------------------------------------------
-; END POINTER
-; ---------------------------------------------------------------------
-padding: resq 2 ; SAFETY PADDING
-the_end:
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ lib REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-/* biosext.c
- *
- * DOS library for carrying out extended memory copy using BIOS INT 15h
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/biosext.h>
-
-#if TARGET_MSDOS == 16
-int bios_extcopy_sub(uint32_t dst,uint32_t src,unsigned long copy/* WARNING: must be multiple of 2, and <= 64KB */) {
- /* WARNING: There are better ways to access extended memory.
- * But we have this function for those cases where the better ways are
- * unavailable. Such as:
- *
- * a) we're running on a 286, where 32-bit 386 instructions
- * are unavailable to carry out flat real mode tricks
- *
- * b) we're running under Windows, whos DOS VM subsystem
- * is intolerant of flat real mode and generally demands that
- * we switch into DPMI protected mode to even access it
- *
- * c) we're running under some other virtual 8086 mode system
- * that forbids flat realmode like hacks (such as EMM386.EXE)
- *
- * There is also another possible danger: Some BIOS implementations emulate 286 behavior (even on
- * 386, 486, Pentium, and beyond) by masking off or ignoring the upper 8 bits of the base (24-31).
- * On these systems, accessing memory at or above the 16MB mark with the BIOS is impossible. But on
- * these same systems, you have 32-bit protected mode and the option to use flat real mode anyway,
- * so it doesn't really matter. On a 286 class system where you must use this function, the CPU is
- * physically incapable of signalling more than 16MB (24 bit addressing) so again, that doesn't
- * matter.
- *
- * TODO: I need to test this theory: If a BIOS ignores address bits 24-31, but we're running under
- * Windows (and therefore the Windows kernel's emulation of the BIOS call), does the address
- * masking limitation still apply? */
- /* The following comment is a list of all system & BIOS combinations this code has been tested under.
- *
- * BIOS/System/Environment Works? At or above 16MB boundary?
- * ---------------------------------------------------------------------
- * DOSBox 0.74 YES w/ BUGS YES
- * Microsoft Virtual PC 2007 YES YES
- * Oracle VirtualBox 4.0.4 YES YES
- * QEMU YES YES
- * DOSBox 0.74 +
- * Microsoft Windows 3.0
- * Real mode YES YES
- * Standard mode YES YES
- * 386 Enhanced mode YES NO
- * Microsoft Windows 3.1
- * Standard mode YES YES
- * 386 Enhanced mode YES YES
- * Microsoft Windows 3.11
- * Standard mode YES YES
- * 386 Enhanced mode YES YES
- * QEMU +
- * Microsoft Windows 95 (4.00.950)
- * Normal YES YES
- * Safe mode YES YES
- * Microsoft Windows 98 (4.10.1998)
- * Normal YES YES
- * Safe mode YES YES
- * Microsoft Windows ME (4.90.3000)
- * Normal YES YES
- * Safe mode YES YES
- * Microsoft Windows 2000 Professional (5.00.2195)
- * Normal YES NO
- * Microsoft Windows XP Professional (5.1.2600)
- * Normal YES NO
- * Microsoft Windows XP Professional SP2 (5.1.2600)
- * Normal YES NO
- * Microsoft Windows Vista Ultimate
- * Normal YES NO
- *
- * Bugs:
- * * DOSBox 0.74: DOSBox directly emulates the INT BIOS function. Unfortunately it does it wrong,
- * apparently getting bytes 7 and 8 of the descriptor backwards. If this code always
- * fills in the flags and limit(16:19) bits, then it causes DOSBox to access addresses
- * in the 0x8F000000....0x8FFFFFFF range (because the flags+limit byte is usually 0x8F
- * on 386 systems and DOSBox is mistreating it as bits 24-31 of the address).
- *
- * Unfortunately this bug means that any program relying on this function exclusively
- * will be unable to properly target memory above 16MB when running under DOSBox. However,
- * DOSBox also fails to enforce segment limits in real mode (emulating a CPU that is
- * perpetually in "flat real mode") which means that you are free to abuse 386+ style
- * 32-bit addressing, therefore, you should be using flat real mode instead of this function.
- *
- * It's possible the DOSBox developers missed the bug because they only tested it against
- * ancient DOS games written in the 286 era that habitually left bytes 7-8 zero anyway.
- * Who knows?
- */
- union REGS regs;
- struct SREGS sregs;
- uint8_t tmp[0x40]; /* the global descriptor table */
-
- memset(tmp,0,sizeof(tmp));
-
- *((uint16_t*)(tmp+0x10)) = 0xFFFF; /* limit (source) */
- *((uint32_t*)(tmp+0x12)) = 0x93000000UL + (src & 0xFFFFFFUL); /* base and access byte (source) */
- if (src >= 0x1000000UL/*>= 16MB*/) /* see DOSBox bug report listed above to understand why I am filling in bytes 7-8 this way */
- *((uint16_t*)(tmp+0x16)) = ((src >> 16) & 0xFF00UL) + 0x8FUL; /* (386) base bits 24-31, flags, limit bits 16-19 */
-
- *((uint16_t*)(tmp+0x18)) = 0xFFFF; /* limit (dest) */
- *((uint32_t*)(tmp+0x1A)) = 0x93000000UL + (dst & 0xFFFFFFUL); /* base and access byte (dest) */
- if (dst >= 0x1000000UL/*>= 16MB*/) /* see DOSBox bug report listed above to understand why I am filling in bytes 7-8 this way */
- *((uint16_t*)(tmp+0x1E)) = ((dst >> 16) & 0xFF00UL) + 0x8FUL; /* (386) base bits 24-31, flags, limit bits 16-19 */
-
- regs.h.ah = 0x87;
- regs.w.cx = (unsigned int)(copy >> 1UL); /* number of WORDS, not BYTES */
- regs.w.si = FP_OFF((unsigned char*)tmp);
- sregs.es = FP_SEG((unsigned char*)tmp);
- int86x(0x15,®s,®s,&sregs); /* now call the BIOS */
- return (regs.h.ah == 0) ? 0 : -1;
-}
-
-int bios_extcopy(uint32_t dst,uint32_t src,unsigned long copy) {
- if (copy == 0UL) return 0;
- /* if we're on anything less than a 286, then this function is meaningless--there is no extended memory */
- if (cpu_basic_level == (signed char)0xFF) cpu_probe();
- if (cpu_basic_level < 2) return -1;
- /* carry out the copy operation */
- while (copy >= 0x10000UL) {
- if (bios_extcopy_sub(dst,src,0x10000UL))
- return -1;
-
- copy -= 0x10000UL;
- dst += 0x10000UL;
- src += 0x10000UL;
- }
- if (copy >= 2UL) {
- if (bios_extcopy_sub(dst,src,copy & 0xFFFFFFFEUL))
- return -1;
-
- dst += copy & 0xFFFFFFFEUL;
- src += copy & 0xFFFFFFFEUL;
- copy &= 1UL;
- }
- if (copy != 0UL) {
- unsigned char tmp[2];
- if (bios_extcopy_sub(ptr2phys(tmp),src,2)) return -1;
- *((unsigned char far*)MK_FP(dst>>4,dst&0xF)) = tmp[0];
- }
-
- return 0;
-}
-#endif
-
+++ /dev/null
-/* biosext.h
- *
- * DOS library for carrying out extended memory copy using BIOS INT 15h
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdint.h>
-
-#if TARGET_MSDOS == 16
-int bios_extcopy(uint32_t dst,uint32_t src,unsigned long copy);
-#endif
-
+++ /dev/null
-/* biosmem.c
- *
- * Various BIOS INT 15h extended memory query functions.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/biosmem.h>
-
-#if TARGET_MSDOS == 16
-int biosmem_size_E820(unsigned long *index,struct bios_E820 *nfo) {
- if (cpu_basic_level < 3) /* requires a 386 or higher. If the programmer didn't call CPU detection that's OK he gets the crash he deserves */
- return 0;
-
- return _biosmem_size_E820_3(index,nfo);
-}
-
-int biosmem_size_88(unsigned int *sz) {
- union REGS regs={0};
-
- regs.x.ax = 0x8800;
- int86(0x15,®s,®s);
- if (regs.x.cflag & 1) /* CF=1 */
- return 0;
- if (regs.x.ax == 0)
- return 0;
- if (regs.h.ah == 0x86 || regs.h.ah == 0x80)
- return 0;
-
- *sz = regs.x.ax;
- return 1;
-}
-
-int biosmem_size_E801(unsigned int *low,unsigned int *high) {
- union REGS regs={0};
-
- regs.x.ax = 0xE801;
- int86(0x15,®s,®s);
- if (regs.x.cflag & 1) { /* CF=1 */
- return 0;
- }
-
- if (regs.x.ax == 0)
- regs.x.ax = regs.x.cx;
- else if (regs.x.cx == 0)
- regs.x.cx = regs.x.ax;
-
- if (regs.x.bx == 0)
- regs.x.bx = regs.x.dx;
- else if (regs.x.dx == 0)
- regs.x.dx = regs.x.bx;
-
- if (regs.x.ax != regs.x.cx || regs.x.bx != regs.x.dx)
- return 0;
-
- *low = regs.x.ax;
- *high = regs.x.bx;
- return 1;
-}
-#endif
-
+++ /dev/null
-/* biosmem.h
- *
- * Various BIOS INT 15h extended memory query functions.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#pragma pack(push,1)
-struct bios_E820 {
- uint64_t base,length;
- uint32_t type;
- uint32_t ext_attributes;
-};
-#pragma pack(pop)
-
-/* INT 15H AX=E820 types */
-enum {
- BIOS_E820_NONE=0,
- BIOS_E820_RAM,
- BIOS_E820_RESERVED,
- BIOS_E820_ACPI_RECLAIMABLE,
- BIOS_E820_ACPI_NVS,
- BIOS_E820_FAULTY
-};
-
-int _biosmem_size_E820_3(unsigned long *index,struct bios_E820 *nfo);
-int biosmem_size_E820(unsigned long *index,struct bios_E820 *nfo);
-int biosmem_size_E801(unsigned int *low,unsigned int *high);
-int biosmem_size_88(unsigned int *sz);
-
+++ /dev/null
-/* biosmem3.c
- *
- * Support functions for calling BIOS INT 15h E820 to query extended memory layout
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/biosmem.h>
-
-#if TARGET_MSDOS == 16
-int _biosmem_size_E820_3(unsigned long *index,struct bios_E820 *nfo) {
- unsigned long idx = *index;
- unsigned long retv = 0;
- unsigned int len = 0;
-
- memset(nfo,0,sizeof(*nfo));
-
- __asm {
- push es
- mov eax,0xE820
- mov ebx,idx
- mov ecx,24
- mov edx,0x534D4150
-#if defined(__LARGE__) || defined(__COMPACT__)
- mov di,word ptr [nfo+2] ; segment portion of far pointer
- mov es,di
-#endif
- mov di,word ptr [nfo] ; offset of pointer
- int 15h
- pop es
- jc noway
- mov retv,eax
- mov idx,ebx
- mov len,cx ; Watcom doesn't know what "CL" is? It's only the lower 8 bits of CX/ECX Duhhhh...
-noway:
- }
-
- if (retv == 0x534D4150UL) {
- *index = idx;
- return len & 0xFF;
- }
-
- return 0;
-}
-#endif
-
+++ /dev/null
-
-# TODO: OS/2 target: What can we #define to tell the header files which OS/2
-# environment we're doing? (Command prompt app. vs Presentation Manager app vs.
-# "fullscreen" app.)
-
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NOW_BUILDING = HW_DOS_LIB
-
-OBJS = $(SUBDIR)$(HPS)dos.obj $(SUBDIR)$(HPS)dosxio.obj $(SUBDIR)$(HPS)biosext.obj $(SUBDIR)$(HPS)himemsys.obj $(SUBDIR)$(HPS)emm.obj $(SUBDIR)$(HPS)dosbox.obj $(SUBDIR)$(HPS)biosmem.obj $(SUBDIR)$(HPS)biosmem3.obj $(SUBDIR)$(HPS)dosasm.obj $(SUBDIR)$(HPS)tgusmega.obj $(SUBDIR)$(HPS)tgussbos.obj $(SUBDIR)$(HPS)tgusumid.obj $(SUBDIR)$(HPS)dosntvdm.obj $(SUBDIR)$(HPS)doswin.obj $(SUBDIR)$(HPS)dos_lol.obj $(SUBDIR)$(HPS)dossmdrv.obj $(SUBDIR)$(HPS)dosvbox.obj $(SUBDIR)$(HPS)dosmapal.obj $(SUBDIR)$(HPS)dosflavr.obj $(SUBDIR)$(HPS)dos9xvm.obj $(SUBDIR)$(HPS)dos_nmi.obj $(SUBDIR)$(HPS)win32lrd.obj $(SUBDIR)$(HPS)win3216t.obj $(SUBDIR)$(HPS)win16vec.obj $(SUBDIR)$(HPS)dpmiexcp.obj $(SUBDIR)$(HPS)dosvcpi.obj $(SUBDIR)$(HPS)ddpmilin.obj $(SUBDIR)$(HPS)ddpmiphy.obj $(SUBDIR)$(HPS)ddpmidos.obj $(SUBDIR)$(HPS)ddpmidsc.obj $(SUBDIR)$(HPS)dpmirmcl.obj $(SUBDIR)$(HPS)dos_mcb.obj $(SUBDIR)$(HPS)dospsp.obj $(SUBDIR)$(HPS)dosdev.obj $(SUBDIR)$(HPS)dos_ltp.obj $(SUBDIR)$(HPS)dosdpmi.obj
-!ifdef TARGET_WINDOWS
-OBJS += $(SUBDIR)$(HPS)winfcon.obj
-!endif
-
-#HW_DOS_LIB = $(SUBDIR)$(HPS)dos.lib
-
-!ifndef TARGET_OS2
-NTVDMLIB_LIB = ..$(HPS)..$(HPS)windows$(HPS)ntvdm$(HPS)$(SUBDIR)$(HPS)ntvdmlib.lib
-NTVDMLIB_LIB_WLINK_LIBRARIES = library $(NTVDMLIB_LIB)
-NTVDMVDD_LIB = ..$(HPS)..$(HPS)windows$(HPS)ntvdm$(HPS)$(SUBDIR)$(HPS)ntvdmvdd.lib
-NTVDMVDD_LIB_WLINK_LIBRARIES = library $(NTVDMVDD_LIB)
-!endif
-
-!ifndef TARGET_WINDOWS
-! ifndef TARGET_OS2
-LOL_EXE = $(SUBDIR)$(HPS)lol.exe
-TESTSMRT_EXE =$(SUBDIR)$(HPS)testsmrt.exe
-NTASTRM_EXE = $(SUBDIR)$(HPS)ntastrm.exe
-! ifeq TARGET_MSDOS 16
-TESTDPMI_EXE =$(SUBDIR)$(HPS)testdpmi.exe
-! endif
-TSTHIMEM_EXE =$(SUBDIR)$(HPS)tsthimem.exe
-TESTBEXT_EXE =$(SUBDIR)$(HPS)testbext.exe
-TESTEMM_EXE = $(SUBDIR)$(HPS)testemm.exe
-TSTBIOM_EXE = $(SUBDIR)$(HPS)tstbiom.exe
-TSTLP_EXE = $(SUBDIR)$(HPS)tstlp.exe
-! endif
-!endif
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-CR3_EXE = $(SUBDIR)$(HPS)cr3.exe
-
-!ifndef TARGET_OS2
-# if targeting Win32, then build the DOS NT assistant DLL that DOS versions
-# can use to better interact with Windows NT/2000/XP. Else, copy the winnt
-# DLL into the DOS build dir. The DLL is given the .VDD extension to clarify
-# that it is intented for use as a VDD for NTVDM.EXE (or as a Win32 extension
-# to the Win16 builds).
-DOSNTAST_VDD = $(SUBDIR)$(HPS)dosntast.vdd
-!endif
-
-!ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 32
-! ifeq TARGET_WINDOWS 40
-DOSNTAST_VDD_BUILD=1
-! endif
-! endif
-!endif
-
-$(HW_DOS_LIB): $(OBJS)
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos.obj -+$(SUBDIR)$(HPS)biosext.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)himemsys.obj -+$(SUBDIR)$(HPS)emm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dosbox.obj -+$(SUBDIR)$(HPS)biosmem.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)biosmem3.obj -+$(SUBDIR)$(HPS)dosasm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)tgusmega.obj -+$(SUBDIR)$(HPS)tgussbos.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)tgusumid.obj -+$(SUBDIR)$(HPS)dosntvdm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)doswin.obj -+$(SUBDIR)$(HPS)dosxio.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos_lol.obj -+$(SUBDIR)$(HPS)dossmdrv.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dosvbox.obj -+$(SUBDIR)$(HPS)dosmapal.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dosflavr.obj -+$(SUBDIR)$(HPS)dos9xvm.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos_nmi.obj -+$(SUBDIR)$(HPS)win32lrd.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)win3216t.obj -+$(SUBDIR)$(HPS)win16vec.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dpmiexcp.obj -+$(SUBDIR)$(HPS)dosvcpi.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)ddpmilin.obj -+$(SUBDIR)$(HPS)ddpmiphy.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)ddpmidos.obj -+$(SUBDIR)$(HPS)ddpmidsc.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dpmirmcl.obj -+$(SUBDIR)$(HPS)dos_mcb.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dospsp.obj -+$(SUBDIR)$(HPS)dosdev.obj
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)dos_ltp.obj -+$(SUBDIR)$(HPS)dosdpmi.obj
-!ifdef TARGET_WINDOWS
- wlib -q -b -c $(HW_DOS_LIB) -+$(SUBDIR)$(HPS)winfcon.obj
-!endif
-
-# some components need a 386 in real mode
-$(SUBDIR)$(HPS)biosmem3.obj: biosmem3.c
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS386) $[@
- @$(CC) @tmp.cmd
-
-$(SUBDIR)$(HPS)dosntast.obj: dosntast.c
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS_CON) $[@
- @$(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-exe: $(TESTSMRT_EXE) $(NTASTRM_EXE) $(TEST_EXE) $(CR3_EXE) $(TESTBEXT_EXE) $(TSTHIMEM_EXE) $(TESTEMM_EXE) $(TSTBIOM_EXE) $(LOL_EXE) $(TSTLP_EXE) $(TESTDPMI_EXE) .symbolic
-
-lib: $(DOSNTAST_VDD) $(HW_DOS_LIB) .symbolic
-
-!ifdef TESTSMRT_EXE
-$(TESTSMRT_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testsmrt.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)testsmrt.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTSMRT_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef NTASTRM_EXE
-$(NTASTRM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)ntastrm.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)ntastrm.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(NTASTRM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef DOSNTAST_VDD_BUILD
-$(DOSNTAST_VDD): $(HW_DOS_LIB) $(HW_CPU_LIB) $(NTVDMLIB_LIB) $(NTVDMVDD_LIB) $(SUBDIR)$(HPS)dosntast.obj
- %write tmp.cmd option quiet system $(WLINK_DLL_SYSTEM) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(NTVDMVDD_LIB_WLINK_LIBRARIES) $(NTVDMLIB_LIB_WLINK_LIBRARIES) library winmm.lib file $(SUBDIR)$(HPS)dosntast.obj
- %write tmp.cmd option modname='DOSNTAST'
-! ifeq TARGET_MSDOS 32
- %write tmp.cmd option nostdcall
-! endif
-# explanation: if we use the IMPLIB option, Watcom will go off and make an import library that
-# cases all references to refer to HELLDLD1.DLL within the NE image, which Windows does NOT like.
-# we need to ensure the DLL name is encoded by itself without a .DLL extension which is more
-# compatible with Windows and it's internal functions.
-#
-# Frankly I'm surprised that Watcom has this bug considering how long it's been around... Kind of disappointed really
-# %write tmp.cmd option impfile=$(SUBDIR)$(HPS)DOSNTAST.LCF
- %write tmp.cmd name $(DOSNTAST_VDD)
- @wlink @tmp.cmd
-!else
-# copy from Win32 dir. Build if necessary
-winnt$(HPS)dosntast.vdd: dosntast.c
- @$(MAKECMD) build lib winnt
-
-! ifdef DOSNTAST_VDD
-$(DOSNTAST_VDD): winnt$(HPS)dosntast.vdd
- @$(COPY) winnt$(HPS)dosntast.vdd $(DOSNTAST_VDD)
-! endif
-!endif
-
-!ifdef LOL_EXE
-$(LOL_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)lol.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)lol.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(LOL_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TESTDPMI_EXE
-$(TESTDPMI_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testdpmi.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)testdpmi.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTDPMI_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TEST_EXE
-$(TEST_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)test.obj $(HW_DOS_LIB_WLINK_LIBRARIES)
- %write tmp.cmd option map=$(SUBDIR)$(HPS)test.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(TEST_EXE)
- @wbind $(TEST_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(TEST_EXE)
-! endif
-!endif
-
-!ifdef CR3_EXE
-$(CR3_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)cr3.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)cr3.obj $(HW_DOS_LIB_WLINK_LIBRARIES)
- %write tmp.cmd option map=$(SUBDIR)$(HPS)cr3.map
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd segment TYPE CODE PRELOAD FIXED DISCARDABLE SHARED
- %write tmp.cmd segment TYPE DATA PRELOAD MOVEABLE
-! endif
-! endif
- %write tmp.cmd name $(CR3_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-! ifdef WIN386
- @$(WIN386_EXE_TO_REX_IF_REX) $(CR3_EXE)
- @wbind $(CR3_EXE) -q -n
-! endif
-! ifdef WIN_NE_SETVER_BUILD
- $(WIN_NE_SETVER_BUILD) $(CR3_EXE)
-! endif
-!endif
-
-!ifdef TSTLP_EXE
-$(TSTLP_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tstlp.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)tstlp.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TSTLP_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TESTBEXT_EXE
-$(TESTBEXT_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testbext.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)testbext.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTBEXT_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TSTHIMEM_EXE
-$(TSTHIMEM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tsthimem.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)tsthimem.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TSTHIMEM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TESTEMM_EXE
-$(TESTEMM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)testemm.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)testemm.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TESTEMM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef TSTBIOM_EXE
-$(TSTBIOM_EXE): $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tstbiom.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) $(WLINK_FLAGS) file $(SUBDIR)$(HPS)tstbiom.obj $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TSTBIOM_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_DOS_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* cr3.c
- *
- * Test program: Attempt to read the CR3 register, see what happens
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- uint32_t v_cr3=0;
-
- probe_dos();
-
- __asm {
- .386p
- int 3
- xor eax,eax
- mov eax,cr3
- mov v_cr3,eax
- }
-
- printf("CR3=0x%08lX\n",(unsigned long)v_cr3);
- return 0;
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32
-void *dpmi_alloc_dos(unsigned long len,uint16_t *selector) {
- unsigned short rm=0,pm=0,fail=0;
-
- /* convert len to paragraphs */
- len = (len + 15) >> 4UL;
- if (len >= 0xFF00UL) return NULL;
-
- __asm {
- mov bx,WORD PTR len
- mov ax,0x100
- int 0x31
-
- mov rm,ax
- mov pm,dx
- sbb ax,ax
- mov fail,ax
- }
-
- if (fail) return NULL;
-
- *selector = pm;
- return (void*)((unsigned long)rm << 4UL);
-}
-
-void dpmi_free_dos(uint16_t selector) {
- __asm {
- mov ax,0x101
- mov dx,selector
- int 0x31
- }
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* TODO: Windows 3.1/95/98/ME have a DPMI server underneath.
- * It would be neato at some point if these functions were
- * available for use from Windows 3.1 Win16/Win32, and
- * Windows 95/98/ME Win32 */
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void dpmi_free_descriptor(uint16_t d) {
- union REGS regs = {0};
- regs.w.ax = 0x0001; /* DPMI free descriptor */
- regs.w.bx = d;
- int386(0x31,®s,®s);
-}
-
-uint16_t dpmi_alloc_descriptors(uint16_t c) {
- union REGS regs = {0};
- regs.w.ax = 0x0000; /* allocate descriptor */
- regs.w.cx = 1; /* just one */
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return regs.w.ax;
-}
-
-unsigned int dpmi_set_segment_base(uint16_t sel,uint32_t base) {
- union REGS regs = {0};
- regs.w.ax = 0x0007; /* set segment base */
- regs.w.bx = sel;
- regs.w.cx = base >> 16UL;
- regs.w.dx = base;
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return 1;
-}
-
-unsigned int dpmi_set_segment_limit(uint16_t sel,uint32_t limit) {
- union REGS regs = {0};
- regs.w.ax = 0x0008; /* set segment limit */
- regs.w.bx = sel;
- regs.w.cx = limit >> 16UL;
- regs.w.dx = limit;
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return 1;
-}
-
-unsigned int dpmi_set_segment_access(uint16_t sel,uint16_t access) {
- union REGS regs = {0};
- unsigned char c=0;
-
- /* the DPL/CPL value we give to the DPMI function below must match our privilege level, so
- * get that value from our own selector */
- __asm {
- push eax
- movzx eax,sel
- and al,3
- mov c,al
- pop eax
- }
-
- regs.w.ax = 0x0009; /* set segment access rights */
- regs.w.bx = sel;
- regs.w.cx = (access & 0xFF9F) | (c << 5); /* readable, code, CPL=same, present=1, 16-bit byte granular */
- int386(0x31,®s,®s);
- if (regs.w.cflag & 1) return 0;
- return 1;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32
-int dpmi_linear_lock(uint32_t lin,uint32_t size) {
- int retv = 0;
-
- __asm {
- mov ax,0x0600
- mov cx,word ptr lin
- mov bx,word ptr lin+2
- mov di,word ptr size
- mov si,word ptr size+2
- int 0x31
- jc endf
- mov retv,1
-endf:
- }
-
- return retv;
-}
-
-int dpmi_linear_unlock(uint32_t lin,uint32_t size) {
- int retv = 0;
-
- __asm {
- mov ax,0x0601
- mov cx,word ptr lin
- mov bx,word ptr lin+2
- mov di,word ptr size
- mov si,word ptr size+2
- int 0x31
- jc endf
- mov retv,1
-endf:
- }
-
- return retv;
-}
-
-void *dpmi_linear_alloc(uint32_t try_lin,uint32_t size,uint32_t flags,uint32_t *handle) {
- void *retv = 0;
- uint32_t han = 0;
-
- __asm {
- mov ax,0x0504
- mov ebx,try_lin
- mov ecx,size
- mov edx,flags
- int 0x31
- jc endf
- mov retv,ebx
- mov han,esi
-endf:
- }
-
- if (retv != NULL && handle != NULL)
- *handle = han;
-
- return retv;
-}
-
-int dpmi_linear_free(uint32_t handle) {
- int retv = 0;
-
- __asm {
- mov ax,0x0502
- mov di,word ptr handle
- mov si,word ptr handle+2
- int 0x31
- jc endf
- mov retv,1
-endf:
- }
-
- return retv;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32
-void *dpmi_phys_addr_map(uint32_t phys,uint32_t size) {
- uint32_t retv = 0;
-
- __asm {
- mov ax,0x0800
- mov cx,word ptr phys
- mov bx,word ptr phys+2
- mov di,word ptr size
- mov si,word ptr size+2
- int 0x31
- jc endf
- mov word ptr retv,cx
- mov word ptr retv+2,bx
-endf:
- }
-
- return (void*)retv;
-}
-
-void dpmi_phys_addr_free(void *base) {
- __asm {
- mov ax,0x0801
- mov cx,word ptr base
- mov bx,word ptr base+2
- int 0x31
- }
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define int386 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-struct lib_dos_options lib_dos_option={0};
-
-/* DOS version info */
-uint8_t dos_flavor = 0;
-uint16_t dos_version = 0;
-uint32_t freedos_kernel_version = 0;
-const char *dos_version_method = NULL;
-
-#if TARGET_MSDOS == 32
-char *freedos_kernel_version_str = NULL;
-#else
-char far *freedos_kernel_version_str = NULL;
-#endif
-
-void probe_dos() {
-#if TARGET_MSDOS == 32 && 0
- assert(sizeof(struct dpmi_realmode_call) == 0x32);
- assert(offsetof(struct dpmi_realmode_call,ss) == 0x30);
- assert(offsetof(struct dpmi_realmode_call,cs) == 0x2C);
-#endif
-
- if (dos_version == 0) {
-#ifdef TARGET_WINDOWS
-# if TARGET_MSDOS == 32
-# ifdef WIN386
-/* =================== Windows 3.0/3.1 Win386 ================= */
- DWORD raw = GetVersion(); /* NTS: The Win16 version does not tell us if we're running under Windows NT */
-
- dos_version_method = "GetVersion";
- dos_version = (((raw >> 24UL) & 0xFFUL) << 8UL) | (((raw >> 16UL) & 0xFFUL) << 0UL);
-
- /* Windows NT/2000/XP NTVDM.EXE lies to us, reporting Windows 95 numbers and MS-DOS 5.0 */
- if (dos_version == 0x500) {
- uint16_t x = 0;
-
- /* Sorry Microsoft, but you make it hard for us to detect and we have to break your OS to find the info we need */
- __asm {
- mov ax,0x3306
- mov bx,0
- int 21h
- jc err1
- mov x,bx
-err1:
- }
-
- if (x != 0 && x != 0x005) { /* Once pushed to reveal the true DOS version, NTVDM.EXE responds with v5.50 */
- dos_version = (x >> 8) | (x << 8);
- dos_version_method = "INT 21h AX=3306h/NTVDM.EXE";
- }
- }
-# else
-/* =================== Windows 32-bit ================== */
- DWORD raw;
- /* GetVersion() 32-bit doesn't return the DOS version at all. The upper WORD has build number instead. */
- /* Instead, use GetVersionEx() to detect system. If system is Windows 3.1 or 9x/ME we might be able
- * to get away with abusing the DPMI server deep within Windows to get what we want. Else, if it's
- * Windows NT, we simply assume v5.50 */
-
- /* assume v5.0 */
- dos_version = 0x500;
- dos_version_method = "Guessing";
-
- /* use the Win32 version of GetVersion() to determine what OS we're under */
- raw = GetVersion();
- if (raw & 0x80000000UL) { /* Windows 9x/ME */
- /* Start by guessing the version number based on which version of Windows we're under */
- unsigned char major = raw & 0xFF,minor = (raw >> 8) & 0xFF,ok=0;
-
- dos_version_method = "Guessing by Windows version";
- if (major < 4) { /* Windows 3.1 Win32s */
- dos_version = 0x616; /* Assume MS-DOS 6.22, though it could be 6.20 or even 6.00 */
- }
- else if (major == 4) { /* Windows 95/98/ME */
- if (minor >= 90)
- dos_version = 0x800; /* Windows ME (8.00) */
- else if (minor >= 10)
- dos_version = 0x70A; /* Windows 98 (7.10) */
- else
- dos_version = 0x700; /* Windows 95 */
- }
-
- /* Try: Windows 9x/ME QT_Thunk hack to call down into the Win16 layer's version of GetVersion() */
- if (!ok && major == 4 && Win9xQT_ThunkInit()) {
- DWORD fptr,raw=0;
-
- fptr = GetProcAddress16(win9x_kernel_win16,"GETVERSION");
- if (fptr != 0) {
- dos_version_method = "Read from Win16 GetVersion() [32->16 QT_Thunk]";
-
- {
- __asm {
- mov edx,fptr
- mov eax,dword ptr [QT_Thunk]
-
- ; QT_Thunk needs 0x40 byte of data storage at [EBP]
- ; give it some, right here on the stack
- push ebp
- mov ebp,esp
- sub esp,0x40
-
- call eax ; <- QT_Thunk
-
- ; release stack storage
- mov esp,ebp
- pop ebp
-
- ; take Win16 response in DX:AX translate to EAX
- shl edx,16
- and eax,0xFFFF
- or eax,edx
- mov raw,eax
- }
- }
-
- if (raw != 0) {
- dos_version = (((raw >> 24UL) & 0xFFUL) << 8UL) | (((raw >> 16UL) & 0xFFUL) << 0UL);
- ok = 1;
- }
- }
- }
- /* Tried: Windows 3.1 with Win32s. Microsoft Win32 documentation gleefully calls Dos3Call "obsolete",
- * yet inspection of the Win32s DLLs shows that W32SKRNL.DLL has a _Dos3Call@0 symbol in it
- * that acts just like the Win16 version, calling down into DOS, and most of the Win32s DLLs
- * rely on it quite heavily to implement Win32 functions (the GetSystemTime function for example
- * using it to call INT 21h AH=2Ah).
- *
- * Some old MSDN documentation I have has a list of INT 21h calls and corresponding Win32
- * functions to use. Again of course, they skip right over "Get MS-DOS version", no help there.
- *
- * Anyway, calling this function with AX=0x3306 or AH=0x30 yields no results. Apparently, Microsoft
- * implemented passing through file I/O, date/time, and code page conversions, yet never considered
- * people might use it for something like... asking DOS it's version number. Attempting to make
- * these calls yields zero in AX and BX, or for AX=3306, a false return number that would imply
- * MS-DOS v1.0 (EAX=1). So, _Dos3Call@0 is not an option.
- *
- * But then that means we have absolutely no way to determine the DOS kernel version (short of
- * poking our nose into segments and memory locations we have no business being in!). We can't
- * use _Dos3Call@0, we can't use GetVersion() because the Win32 GetVersion() doesn't return
- * the DOS version, and we can't use Win95 style thunks because Win32s doesn't have a publicly
- * available and documented way to thunk down into Win16. We have absolutely jack shit to go by.
- *
- * Hey, Microsoft... When you released Win32s in 1993, did you ever stop to consider someone
- * might want to do something as simple as query the DOS version? Why couldn't you guys have
- * done something straightforward like a "GetDOSVersion()" API function that works under
- * Windows 9x/ME and returns an error under NT? I know it's silly of me to ask this in 2012
- * when Windows 8 is around the corner and Win32s are long dead, but often it seems like you
- * guys really don't stop to think about things like that and you make really stupid mistakes
- * with your APIs. */
- }
- else {
- dos_version = 0x532; /* Windows NT v5.50 */
- }
-# endif
-# elif TARGET_MSDOS == 16
-/* =================== Windows 16-bit ================== */
- DWORD raw = GetVersion(); /* NTS: The Win16 version does not tell us if we're running under Windows NT */
-
- dos_version_method = "GetVersion";
- dos_version = (((raw >> 24UL) & 0xFFUL) << 8UL) | (((raw >> 16UL) & 0xFFUL) << 0UL);
-
- /* Windows NT/2000/XP NTVDM.EXE lies to us, reporting Windows 95 numbers and MS-DOS 5.0 */
- if (dos_version == 0x500) {
- uint16_t x = 0;
-
- /* Sorry Microsoft, but you make it hard for us to detect and we have to break your OS to find the info we need */
- __asm {
- mov ax,0x3306
- mov bx,0
- int 21h
- jc err1
- mov x,bx
-err1:
- }
-
- if (x != 0 && x != 0x005) { /* Once pushed to reveal the true DOS version, NTVDM.EXE responds with v5.50 */
- dos_version = (x >> 8) | (x << 8);
- dos_version_method = "INT 21h AX=3306h/NTVDM.EXE";
- }
- }
-
- /* TODO: DOS "flavor" detection */
- /* TODO: If FreeDOS, get the kernel version and allocate a selector to point at FreeDOS's revision string */
-# else
-# error dunno
-# endif
-#elif defined(TARGET_OS2)
-/* =================== OS/2 ==================== */
- dos_version = (10 << 8) | 0;
- dos_version_method = "Blunt guess";
-
-# if TARGET_MSDOS == 32
- {
- ULONG major=0,minor=0,rev=0;
- DosQuerySysInfo(QSV_VERSION_MAJOR,QSV_VERSION_MAJOR,&major,sizeof(major));
- DosQuerySysInfo(QSV_VERSION_MINOR,QSV_VERSION_MINOR,&minor,sizeof(minor));
- DosQuerySysInfo(QSV_VERSION_REVISION,QSV_VERSION_REVISION,&rev,sizeof(rev));
- if (major != 0) {
- dos_version_method = "DosQuerySysInfo (OS/2)";
- dos_version = (major << 8) | minor;
- /* TODO: store the revision value too somewhere! */
- }
- }
-# elif TARGET_MSDOS == 16
- {
- USHORT x=0;
- DosGetVersion(&x);
- if (x != 0) {
- dos_version_method = "DosGetVersion (OS/2)";
- dos_version = x;
- }
- }
-# else
-# error dunno
-# endif
-#else
-/* =================== MS-DOS ================== */
- union REGS regs;
-
- regs.w.ax = 0x3000;
-# if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-# else
- int86(0x21,®s,®s);
-# endif
- dos_version = (regs.h.al << 8) | regs.h.ah;
- dos_version_method = "INT 21h AH=30h";
-
- if (dos_version >= 0x500 && regs.h.bh == 0xFD) {
- dos_flavor = DOS_FLAVOR_FREEDOS;
- freedos_kernel_version = (((uint32_t)regs.h.ch) << 16UL) |
- (((uint32_t)regs.h.cl) << 8UL) |
- ((uint32_t)regs.h.bl);
-
- /* now retrieve the FreeDOS kernel string */
- /* FIXME: Does this syscall have a way to return an error or indicate that it didn't return a string? */
- regs.w.ax = 0x33FF;
-# if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-# else
- int86(0x21,®s,®s);
-# endif
-
-# if TARGET_MSDOS == 32
- freedos_kernel_version_str = (unsigned char*)(((uint32_t)regs.w.dx << 4UL) + (uint32_t)regs.w.ax);
-# else
- freedos_kernel_version_str = MK_FP(regs.w.dx,regs.w.ax);
-# endif
- }
- else if (dos_version >= 0x200 && regs.h.bh == 0xFF)
- dos_flavor = DOS_FLAVOR_MSDOS;
-
- /* but, SETVER can arrange for DOS to lie to us. so get the real version via
- * undocumented subfunctions (DOS 5.0+ or later, apparently) */
- regs.w.ax = 0x3306; /* AH=0x33 AL=0x06 */
- regs.w.bx = 0; /* in case early DOS versions fail to set CF set BX to zero */
-# if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-# else
- int86(0x21,®s,®s);
-# endif
- if ((regs.w.cflag & 1) == 0 && regs.h.bl >= 5 && regs.h.bl <= 8) {
- dos_version = (regs.h.bl << 8) | regs.h.bh;
- dos_version_method = "INT 21h AX=3306h";
- }
-#endif
- }
-}
-
+++ /dev/null
-/* dos.h
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifndef __HW_DOS_DOS_H
-#define __HW_DOS_DOS_H
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NTVDM.EXE DOSNTAST.VDD call support */
-#include <windows/ntvdm/ntvdmlib.h>
-#endif
-
-#if defined(TARGET_OS2)
-# define INCL_DOSMISC
-# ifdef FAR /* <- conflict between OS/2 headers and cpu.h definition of "FAR" */
-# undef FAR
-# endif
-# include <os2.h>
-#endif
-
-extern unsigned char FAR *dos_LOL;
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-extern int8_t dpmi_no_0301h; /* -1 = not tested 0 = avail 1 = N/A */
-#else
-# define dpmi_no_0301h 0 /* FIXME: Is it possible for DOS extenders to run non-4GW non-LE executables? */
-#endif
-
-#define DPMI_ENTER_AUTO 0xFF
-
-/* DOS "Flavor" we are running under.
- * I originally didn't care too much until one day some really strange
- * fatal bugs popped up when running this code under FreeDOS 1.0, almost
- * as if the FreeDOS kernel does something to fuck with the DOS extender's
- * mind if our code attempts certain things like reading the ROM area... */
-enum {
- DOS_FLAVOR_NONE=0, /* generic DOS */
- DOS_FLAVOR_MSDOS, /* Microsoft MS-DOS */
- DOS_FLAVOR_FREEDOS, /* FreeDOS */
-};
-
-extern uint8_t dos_flavor;
-extern uint16_t dos_version;
-extern const char *dos_version_method;
-extern uint32_t freedos_kernel_version;
-#if TARGET_MSDOS == 32
-extern char *freedos_kernel_version_str;
-#else
-extern char far *freedos_kernel_version_str;
-#endif
-extern unsigned char vcpi_present;
-extern unsigned char vcpi_major_version,vcpi_minor_version;
-
-struct dos_mcb_enum {
- uint16_t segment;
- uint16_t counter;
- /* acquired data */
- unsigned char FAR *ptr; /* pointer to actual memory content */
- uint16_t size,psp,cur_segment;
- uint8_t type;
- char name[9];
-};
-
-#pragma pack(push,1)
-struct dpmi_realmode_call {
- uint32_t edi,esi,ebp,reserved;
- uint32_t ebx,edx,ecx,eax;
- uint16_t flags,es,ds,fs,gs,ip,cs,sp,ss;
-};
-#pragma pack(pop)
-
-#ifndef TARGET_OS2
-# if TARGET_MSDOS == 32
-/* WARNING: This is only 100% reliable if the memory in question is below the 1MB mark!
- * This may happen to work for pointers above the 1MB mark because DOS4GW and DOS32a tend to
- * allocate that way, but that 1:1 correspondence is not guaranteed */
-static inline uint32_t ptr2phys_low1mb(unsigned char *x) {
- return (uint32_t)x;
-}
-# else
-static inline uint32_t ptr2phys_low1mb(unsigned char far *x) {
- uint32_t r = (uint32_t)FP_SEG(x) << 4UL;
- return r + (uint32_t)FP_OFF(x);
-}
-# endif
-#endif
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
-static inline void far *normalize_realmode_far_ptr(void far *p) {
- return MK_FP(
- FP_SEG(p) + (FP_OFF(p) >> 4),
- FP_OFF(p) & 0xF);
-}
-#endif
-
-#ifndef TARGET_OS2
-# if TARGET_MSDOS == 32
-int _dos_xread(int fd,void *buffer,int bsz);
-# else
-int _dos_xread(int fd,void far *buffer,int bsz);
-# endif
-
-# if TARGET_MSDOS == 32
-int _dos_xwrite(int fd,void *buffer,int bsz);
-# else
-int _dos_xwrite(int fd,void far *buffer,int bsz);
-# endif
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-# define dpmi_alloc_descriptor() dpmi_alloc_descriptors(1)
-
-void *dpmi_alloc_dos(unsigned long len,uint16_t *selector);
-void dpmi_free_dos(uint16_t selector);
-
-void dpmi_free_descriptor(uint16_t d);
-uint16_t dpmi_alloc_descriptors(uint16_t c);
-unsigned int dpmi_set_segment_base(uint16_t sel,uint32_t base);
-unsigned int dpmi_set_segment_limit(uint16_t sel,uint32_t limit);
-unsigned int dpmi_set_segment_access(uint16_t sel,uint16_t access);
-void *dpmi_phys_addr_map(uint32_t phys,uint32_t size);
-void dpmi_phys_addr_free(void *base);
-#endif
-
-#if TARGET_MSDOS == 32
-unsigned char *dos_list_of_lists();
-#else
-unsigned char far *dos_list_of_lists();
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-int dpmi_alternate_rm_call(struct dpmi_realmode_call *rc);
-int dpmi_alternate_rm_call_stacko(struct dpmi_realmode_call *rc);
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-# if defined(TARGET_WINDOWS)
-/* as a 32-bit Windows program: even if DPMI is present, it's useless to us because we can't call into that part of Windows */
-# define dpmi_present 0
-# endif
-#endif
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
-/* as a 16-bit program (DOS or Windows), DPMI might be present. Note that DPMI can be present even under NTVDM.EXE under Windows NT,
- * because NTVDM.EXE will emulate some DPMI functions. */
-extern unsigned char dpmi_present;
-extern uint16_t dpmi_flags;
-extern unsigned char dpmi_init;
-extern uint32_t dpmi_entry_point; /* NTS: This is the real-mode address, even for 32-bit builds */
-extern unsigned char dpmi_processor_type;
-extern uint16_t dpmi_version;
-extern uint16_t dpmi_private_data_length_paragraphs;
-extern uint16_t dpmi_private_data_segment;
-extern unsigned char dpmi_entered; /* 0=not yet entered, 16=entered as 16bit, 32=entered as 32bit */
-extern uint64_t dpmi_rm_entry;
-extern uint32_t dpmi_pm_entry;
-extern uint16_t dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss;
-
-void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
-#endif
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-int dpmi_private_alloc();
-int dpmi_enter(unsigned char mode);
-#endif
-
-void probe_dos();
-void probe_dpmi();
-int probe_vcpi();
-
-uint16_t dos_mcb_first_segment();
-int mcb_name_is_junk(char *s/*8 char*/);
-int dos_mcb_next(struct dos_mcb_enum *e);
-int dos_mcb_first(struct dos_mcb_enum *e);
-void mcb_filter_name(struct dos_mcb_enum *e);
-unsigned char FAR *dos_mcb_get_psp(struct dos_mcb_enum *e);
-
-struct dos_psp_cooked {
- unsigned char FAR *raw;
- uint16_t memsize,callpsp,env;
- char cmd[130];
-};
-
-int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e);
-
-struct dos_device_enum {
- unsigned char FAR *raw,FAR *next;
- uint16_t ns,no,attr,entry,intent,count;
- char name[9];
-};
-
-int dos_device_first(struct dos_device_enum *e);
-int dos_device_next(struct dos_device_enum *e);
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_OS2)
-uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
-#endif
-
-#if TARGET_MSDOS == 32
-extern struct dos_linear_to_phys_info dos_ltp_info;
-extern unsigned char dos_ltp_info_init;
-
-int dos_ltp_probe();
-
-/* NTS: The return value is 64-bit so that in scenarios where we hack DPMI to support PSE and PAE modes,
- * the function will still return the physical address associated with the page even when it's above
- * the 4GB boundary. But as a 32-bit DOS program, the linear addresses will never exceed 32-bit. */
-uint64_t dos_linear_to_phys(uint32_t linear);
-
-int dpmi_linear_lock(uint32_t lin,uint32_t size);
-int dpmi_linear_unlock(uint32_t lin,uint32_t size);
-void *dpmi_linear_alloc(uint32_t try_lin,uint32_t size,uint32_t flags,uint32_t *handle);
-int dpmi_linear_free(uint32_t handle);
-
-#define DOS_LTP_FAILED 0xFFFFFFFFFFFFFFFFULL
-
-struct dos_linear_to_phys_info {
- unsigned char paging:1; /* paging is enabled, therefore mapping will occur. if not set, then linear == physical memory addresses */
- unsigned char dos_remap:1; /* if set, the lower 1MB region (DOS conventional memory) is remapped. if clear, we can assume 1:1 mapping below 1MB */
- unsigned char should_lock_pages:1; /* if set, the program should call DPMI functions to lock pages before attempting to get physical memory address */
- unsigned char cant_xlate:1; /* if set, resources to determine physical memory addresses are not available (such as: running in a Windows DOS Box). however dos_remap=0 means we can assume 1:1 mapping below 1MB */
- unsigned char using_pae:1; /* if set, the DOS extender or DPMI host has PAE/PSE extensions enabled. This changes how page tables are parsed, and can prevent us from mapping */
- unsigned char dma_dos_xlate:1; /* usually set if dos_remap=1 to say the DOS extender or environment translates DMA addresses (i.e. Windows DOS Box), but we can't actually know the physical memory address. We can do DMA from DOS memory */
- unsigned char vcpi_xlate:1; /* use VCPI to translate linear -> phys */
- unsigned char reserved:1;
- uint32_t cr0;
- uint32_t cr3; /* last known copy of the CR3 (page table base) register */
- uint32_t cr4; /* last known copy of the CR4 register */
-};
-#endif
-
-#define BIOS_KS_ALT 0x08
-#define BIOS_KT_CTRL 0x04
-
-static inline unsigned char read_bios_keystate() { /* from 0x40:0x17 */
-#if TARGET_MSDOS == 32
- return *((unsigned char*)(0x400 + 0x17));
-#else
- return *((unsigned char far*)MK_FP(0x40,0x17));
-#endif
-}
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-void far *win16_getexhandler(unsigned char n);
-int win16_setexhandler(unsigned char n,void far *x);
-void far *win16_getvect(unsigned char n);
-int win16_setvect(unsigned char n,void far *x);
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-typedef struct Win32OrdinalLookupInfo {
- DWORD entries,base,base_addr;
- DWORD* table;
-} Win32OrdinalLookupInfo;
-
-DWORD *Win32GetExportOrdinalTable(HMODULE mod,DWORD *entries,DWORD *base,DWORD *base_addr);
-void *Win32GetOrdinalAddress(Win32OrdinalLookupInfo *nfo,unsigned int ord);
-int Win32GetOrdinalLookupInfo(HMODULE mod,Win32OrdinalLookupInfo *info);
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-extern DWORD genthunk32w_ntdll;
-extern DWORD genthunk32w_kernel32;
-extern DWORD genthunk32w_kernel32_GetVersion;
-extern DWORD genthunk32w_kernel32_GetVersionEx;
-extern DWORD genthunk32w_kernel32_GetLastError;
-extern BOOL __GenThunksExist;
-extern BOOL __GenThunksChecked;
-extern DWORD (PASCAL FAR *__LoadLibraryEx32W)(LPCSTR lpName,DWORD a,DWORD b);
-extern BOOL (PASCAL FAR *__FreeLibrary32W)(DWORD hinst);
-extern DWORD (PASCAL FAR *__GetProcAddress32W)(DWORD hinst,LPCSTR name);
-extern DWORD (PASCAL FAR *__GetVDMPointer32W)(LPVOID ptr,UINT mask);
-extern DWORD (_cdecl _far *__CallProcEx32W)(DWORD params,DWORD convertMask,DWORD procaddr32,...);
-
-/* NOTE: You call it as if it were declared CallProc32W(..., DWORD hinst,DWORD convertMask,DWORD procaddr32); Ick */
-extern DWORD (PASCAL FAR *__CallProc32W)(DWORD hinst,DWORD convertMask,DWORD procaddr32,...);
-
-/* it would be nice if Open Watcom defined these constants for Win16 */
-#define CPEX_DEST_STDCALL 0x00000000UL
-#define CPEX_DEST_CDECL 0x80000000UL
-
-int genthunk32_init();
-void genthunk32_free();
-#endif
-
-#if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
-#pragma pack(push,4)
-/* OpenWatcom does not define the OSVERSIONINFO struct for Win16 */
-typedef struct OSVERSIONINFO {
- uint32_t dwOSVersionInfoSize;
- uint32_t dwMajorVersion;
- uint32_t dwMinorVersion;
- uint32_t dwBuildNumber;
- uint32_t dwPlatformId;
- char szCSDVersion[128];
-} OSVERSIONINFO;
-
-#define MAXPNAMELEN 32
-
-#define WAVECAPS_PITCH 0x0001
-#define WAVECAPS_PLAYBACKRATE 0x0002
-#define WAVECAPS_VOLUME 0x0004
-#define WAVECAPS_LRVOLUME 0x0008
-#define WAVECAPS_SYNC 0x0010
-#define WAVECAPS_SAMPLEACCURATE 0x0020
-
-typedef struct WAVEOUTCAPS {
- uint16_t wMid;
- uint16_t wPid;
- uint32_t vDriverVersion;
- char szPname[MAXPNAMELEN];
- uint32_t dwFormats;
- uint16_t wChannels;
- uint16_t wReserved1;
- uint32_t dwSupport;
-} WAVEOUTCAPS;
-#pragma pack(pop)
-#endif
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void far *dpmi_getexhandler(unsigned char n);
-int dpmi_setexhandler(unsigned char n,void far *x);
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* TODO: This should be moved into the hw/DOS library */
-extern unsigned char nmi_32_hooked;
-extern int nmi_32_refcount;
-extern void (interrupt *nmi_32_old_vec)();
-
-void do_nmi_32_unhook();
-void do_nmi_32_hook();
-#endif
-
-#if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-enum {
- DOS_CLOSE_AWARENESS_NOT_ACK=0,
- DOS_CLOSE_AWARENESS_ACKED=1
-};
-
-void dos_vm_yield();
-void dos_close_awareness_ack();
-int dos_close_awareness_query();
-void dos_close_awareness_cancel();
-int dos_close_awareness_available();
-int dos_close_awareness_enable(unsigned char en);
-#endif
-
-/* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
-extern char virtualbox_version_str[64];
-
-int detect_virtualbox_emu();
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-int __cdecl dpmi_lin2fmemcpy_32(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-int __cdecl dpmi_lin2fmemcpy_16(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-int dpmi_lin2fmemcpy(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-int dpmi_lin2fmemcpy_init();
-#endif
-
-struct lib_dos_options {
- uint8_t dont_load_dosntast:1; /* do not automatically load DOSNTAST, but use it if loaded. */
- /* if not loaded and the program wants it later on, it should
- * call ntvdm_dosntast_load_vdd(); */
- uint8_t dont_use_dosntast:1; /* do not use DOSNTAST, even if loaded */
- uint8_t __reserved__:6;
-};
-
-extern struct lib_dos_options lib_dos_option;
-
-# define DOSNTAST_HANDLE_UNASSIGNED 0xFFFFU
-
-# define DOSNTAST_INIT_REPORT_HANDLE 0xD0500000
-# define DOSNTAST_INIT_REPORT_HANDLE_C 0xD0500000ULL
-/* in: EBX = DOSNTAST_INIT_REPORT_HANDLE
- * ECX = NTVDM handle
- * out: EBX = 0x55AA55AA
- * ECX = flat memory address where signature is stored (must be in BIOS data area) */
-
-# define DOSNTAST_GETVERSIONEX 0xD0500001
-# define DOSNTAST_GETVERSIONEX_C 0xD0500001ULL
-/* in: EBX = <command>
- * ECX = protected mode call (1) or real-mode call (0)
- * DS:ESI = OSVERSIONINFO struct
- * out: EBX = result
- * DS:ESI = filled in with OS struct */
-
-# define DOSNTAST_GET_TICK_COUNT 0xD0500002
-# define DOSNTAST_GET_TICK_COUNT_C 0xD0500002ULL
-/* in: EBX = <command>
- * out: EBX = tick count */
-
-# define DOSNTAST_GET_IO_PORT 0xD0500003
-# define DOSNTAST_GET_IO_PORT_C 0xD0500003ULL
-/* in: EBX = <command>
- * out: EBX = 0x55AA55AA
- * EDX = I/O port base */
-
-# define DOSNTAST_NOTIFY_UNLOAD 0xD050FFFF
-# define DOSNTAST_NOTIFY_UNLOAD_C 0xD050FFFFULL
-/* in: EBX = <command>
- * out: EBX = none */
-
-# define DOSNTAST_FUNCTION_GENERAL 0x1000
-# define DOSNTAST_FUN_GEN_SUB_MESSAGEBOX 0x0000
-
-# define DOSNTAST_FUNCTION_WINMM 0x1001
-# define DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs 0x0000
-# define DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps 0x0001
-# define DOSNTAST_FUN_WINMM_SUB_waveOutOpen 0x0002
-
-const char *dos_flavor_str(uint8_t f);
-
-/* Windows NT-friendly version of Win386 MapAliasToFlat.
- * The library version is naive and assumes Windows 3.x/9x/ME behavior.
- * If you need to convert pointers NOT given by Win386's AllocAlias() functions
- * (such as 16:16 pointers given by Window messages) and need the code to gracefully
- * handle itself under Windows NT, use this function not MapAliasToFlat() */
-#if TARGET_MSDOS == 32 && defined(WIN386)
-void far *win386_alt_winnt_MapAliasToFlat(DWORD farptr);
-void far *win386_help_MapAliasToFlat(DWORD farptr);
-#endif
-
-#if (TARGET_MSDOS == 16 || TARGET_MSDOS == 32) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-extern unsigned short smartdrv_version;
-extern int smartdrv_fd;
-
-int smartdrv_close();
-int smartdrv_flush();
-int smartdrv_detect();
-#endif
-
-uint32_t dos_linear_to_phys_vcpi(uint32_t pn);
-
-#endif /* __HW_DOS_DOS_H */
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_MSDOS) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* Windows 9x/NT Close-awareness */
-void dos_close_awareness_cancel() {
- __asm {
- .386p
- mov ax,0x168F
- mov dx,0x0300
- int 0x2F
- }
-}
-
-void dos_close_awareness_ack() {
- __asm {
- .386p
- mov ax,0x168F
- mov dx,0x0200
- int 0x2F
- }
-}
-
-int dos_close_awareness_enable(unsigned char en) {
- uint16_t r=0;
-
- en = (en != 0) ? 1 : 0;
-
- __asm {
- .386p
- mov ax,0x168F
- xor dx,dx
- mov dl,en
- int 0x2F
- mov r,ax
- }
-
- return (int)r;
-}
-
-int dos_close_awareness_query() {
- uint16_t r=0;
-
- __asm {
- .386p
- mov ax,0x168F
- mov dx,0x0100
- int 0x2F
- mov r,ax
- }
-
- if (r == 0x168F)
- return -1;
-
- return (int)r;
-}
-
-int dos_close_awareness_available() {
- /* "close-awareness" is provided by Windows */
- return (windows_mode == WINDOWS_ENHANCED || windows_mode == WINDOWS_NT);
-}
-
-void dos_vm_yield() {
- __asm {
- mov ax,0x1680 /* RELEASE VM TIME SLICE */
- xor bx,bx /* THIS VM */
- int 0x2F
- }
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DOS "list of lists" pointer */
-unsigned char FAR *dos_LOL=NULL;
-
-/* MS-DOS "list of lists" secret call */
-#if TARGET_MSDOS == 32
-# ifdef WIN386
-unsigned char *dos_list_of_lists() {
- return NULL;/*not implemented*/
-}
-# else
-static void dos_realmode_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x0021
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-
-unsigned char *dos_list_of_lists() {
- struct dpmi_realmode_call rc={0};
-
- rc.eax = 0x5200;
- dos_realmode_call(&rc);
- if (rc.flags & 1) return NULL; /* CF */
- return (dos_LOL = ((unsigned char*)((rc.es << 4) + (rc.ebx & 0xFFFFUL))));
-}
-# endif
-#else
-unsigned char far *dos_list_of_lists() {
- unsigned int s=0,o=0;
-
- __asm {
- mov ah,0x52
- int 21h
- jc notwork
- mov s,es
- mov o,bx
-notwork:
- }
-
- return (dos_LOL = ((unsigned char far*)MK_FP(s,o)));
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* TODO: Since VCPI/EMM386.EXE can affect 16-bit real mode, why not enable this API for 16-bit real mode too? */
-/* TODO: Also why not enable this function for 16-bit protected mode under Windows 3.1? */
-#if TARGET_MSDOS == 32
-struct dos_linear_to_phys_info dos_ltp_info;
-unsigned char dos_ltp_info_init=0;
-
-/* WARNING: Caller must have called probe_dos() and detect_windows() */
-int dos_ltp_probe() {
- if (!dos_ltp_info_init) {
- memset(&dos_ltp_info,0,sizeof(dos_ltp_info));
-
- /* part of our hackery needs to know what CPU we're running under */
- if (cpu_basic_level < 0)
- cpu_probe();
-
- probe_dos();
-
-#if defined(TARGET_WINDOWS)
- /* TODO: Careful analsys of what version and mode Windows we're running under */
- /* start with the assumption that we don't know where we are and we can't translate to physical. */
- dos_ltp_info.vcpi_xlate = 0; /* TODO: It is said Windows 3.0 has VCPI at the core. Can we detect that? Use it? */
- dos_ltp_info.paging = (windows_mode <= WINDOWS_STANDARD ? 0 : 1); /* paging is not used in REAL or STANDARD modes */
- dos_ltp_info.dos_remap = dos_ltp_info.paging;
- dos_ltp_info.should_lock_pages = 1;
- dos_ltp_info.cant_xlate = 1;
- dos_ltp_info.using_pae = 0; /* TODO: Windows XP SP2 and later can and do use PAE. How to detect that? */
- dos_ltp_info.dma_dos_xlate = 0;
-
-# if TARGET_MSDOS == 32
-# else
- /* TODO: Use GetWinFlags() and version info */
-# endif
-#else
-/* ================ MS-DOS specific =============== */
- /* we need to know if VCPI is present */
- probe_vcpi();
-
- /* NTS: Microsoft Windows 3.0/3.1 Enhanced mode and Windows 95/98/ME all trap access to the control registers.
- * But then they emulate the instruction in such a way that we get weird nonsense values.
- *
- * Windows 95/98/ME: We get CR0 = 2. Why??
- * Windows 3.0/3.1: We get CR0 = 0.
- *
- * So basically what Windows is telling us... is that we're 32-bit protected mode code NOT running in
- * protected mode? What? */
- if (windows_mode == WINDOWS_ENHANCED) {
- /* it's pointless, the VM will trap and return nonsense for control register contents */
- dos_ltp_info.cr0 = 0x80000001UL;
- dos_ltp_info.cr3 = 0x00000000UL;
- dos_ltp_info.cr4 = 0x00000000UL;
- }
- else if (windows_mode == WINDOWS_NT) {
- /* Windows NTVDM will let us read CR0, but CR3 and CR4 come up blank. So what's the point then? */
- uint32_t r0=0;
-
- __asm {
- xor eax,eax
- dec eax
-
- mov eax,cr0
- mov r0,eax
- }
- dos_ltp_info.cr0 = r0 | 0x80000001UL; /* paging and protected mode are ALWAYS enabled, even if NTVDM should lie to us */
- dos_ltp_info.cr3 = 0x00000000UL;
- dos_ltp_info.cr4 = 0x00000000UL;
- }
- else {
- uint32_t r0=0,r3=0,r4=0;
- __asm {
- xor eax,eax
- dec eax
-
- mov eax,cr0
- mov r0,eax
-
- mov eax,cr3
- mov r3,eax
-
- mov eax,cr4
- mov r4,eax
- }
- dos_ltp_info.cr0 = r0;
- dos_ltp_info.cr3 = r3;
- dos_ltp_info.cr4 = r4;
- }
-
- dos_ltp_info.vcpi_xlate = vcpi_present?1:0; /* if no other methods available, try asking the VCPI server */
- dos_ltp_info.paging = (dos_ltp_info.cr0 >> 31)?1:0; /* if bit 31 of CR0 is set, the extender has paging enabled */
- dos_ltp_info.dos_remap = vcpi_present?1:0; /* most DOS extenders map 1:1 the lower 1MB, but VCPI can violate that */
- dos_ltp_info.should_lock_pages = dos_ltp_info.paging; /* it's a good assumption if paging is enabled the extender probably pages to disk and may move things around */
- dos_ltp_info.cant_xlate = dos_ltp_info.paging; /* assume we can't translate addresses yet if paging is enabled */
- dos_ltp_info.using_pae = (dos_ltp_info.cr4 & 0x20)?1:0; /* take note if PAE is enabled */
- dos_ltp_info.dma_dos_xlate = dos_ltp_info.paging; /* assume the extender translates DMA if paging is enabled */
-
- if (windows_mode == WINDOWS_ENHANCED || windows_mode == WINDOWS_NT) {
- dos_ltp_info.should_lock_pages = 1; /* Windows is known to page to disk (the swapfile) */
- dos_ltp_info.dma_dos_xlate = 1; /* Windows virtualizes the DMA controller */
- dos_ltp_info.cant_xlate = 1; /* Windows provides us no way to determine the physical memory address from linear */
- dos_ltp_info.dos_remap = 1; /* Windows remaps the DOS memory area. This is how it makes multiple DOS VMs possible */
- dos_ltp_info.vcpi_xlate = 0; /* Windows does not like VCPI */
- dos_ltp_info.paging = 1; /* Windows uses paging. Always */
- }
-
- /* this code is ill prepared for PAE modes for the time being, since PAE makes page table entries 64-bit
- * wide instead of 32-bit wide. Then again, 99% of DOS out there probably couldn't handle PAE well either. */
- if (dos_ltp_info.using_pae)
- dos_ltp_info.cant_xlate = 1;
-
- /* if NOT running under Windows, and the CR3 register shows something, then we can translate by directly peeking at the page tables */
- if (windows_mode == WINDOWS_NONE && dos_ltp_info.cr3 >= 0x1000)
- dos_ltp_info.cant_xlate = 0;
-#endif
-
- dos_ltp_info_init = 1;
- }
-
- return 1;
-}
-#endif
-
-#if TARGET_MSDOS == 32
-/* WARNINGS: Worst case scanario this function cannot translate anything at all.
- * It will return 0xFFFFFFFFUL if it cannot determine the address.
- * If paging is disabled, the linear address will be returned.
- * If the environment requires you to lock pages, then you must do so
- * before calling this function. Failure to do so will mean erratic
- * behavior when the page you were working on moves out from under you! */
-
-/* "There is no way in a DPMI environment to determine the physical address corresponding to a given linear address. This is part of the design of DPMI. You must design your application accordingly."
- *
- * Fuck you.
- * I need the damn physical address and you're not gonna stop me! */
-
-/* NOTES:
- *
- * QEMU + Windows 95 + EMM386.EXE:
- *
- * I don't know if the DOS extender is doing this, or EMM386.EXE is enforcing it, but
- * a dump of the first 4MB in the test program reveals our linear address space is
- * randomly constructed from 16KB pages taken from all over extended memory. Some of
- * them, the pages are arranged BACKWARDS. Yeah, backwards.
- *
- * Anyone behind DOS4/GW and DOS32a care to explain that weirdness?
- *
- * Also revealed, DOS4/GW follows the DPMI spec and refuses to map pages from conventional
- * memory. So if DOS memory is not mapped 1:1 and the page tables are held down there we
- * literally cannot read them! */
-/* NOTE: The return value is 64-bit so that in the future, if we ever run under DOS with PAE or
- * PSE-36 trickery, we can still report the correct address even if above 4GB. The parameter
- * supplied however remains 32-bit, because as a 32-bit DOS program there's no way any
- * linear address will ever exceed 4GB. */
-uint64_t dos_linear_to_phys(uint32_t linear) {
- uint32_t off,ent;
- uint64_t ret = DOS_LTP_FAILED;
- unsigned char lock1=0,lock2=0;
- uint32_t *l1=NULL,*l2=NULL;
-
- if (!dos_ltp_info.paging)
- return linear;
- if (linear < 0x100000UL && !dos_ltp_info.dos_remap) /* if below 1MB boundary and DOS is not remapped, then no translation */
- return linear;
-
- /* if VCPI translation is to be used, and lower DOS memory is remapped OR the page requested is >= 1MB (or in adapter ROM/RAM), then call the VCPI server and ask */
- if (dos_ltp_info.vcpi_xlate && (dos_ltp_info.dos_remap || linear >= 0xC0000UL)) {
- ent = dos_linear_to_phys_vcpi(linear>>12);
- if (ent != 0xFFFFFFFFUL) return ent;
- /* Most likely requests for memory >= 1MB will fail, because VCPI is only required to
- * provide the system call for lower 1MB DOS conventional memory */
- }
-
-/* if we can't use VCPI and cannot translate, then give up. */
-/* also, this code does not yet support PAE */
- if (dos_ltp_info.using_pae || dos_ltp_info.cant_xlate)
- return ret;
-
-/* re-read control reg because EMM386, etc. is free to change it at any time */
- {
- uint32_t r3=0,r4=0;
- __asm {
- xor eax,eax
- dec eax
-
- mov eax,cr3
- mov r3,eax
-
- mov eax,cr4
- mov r4,eax
- }
- dos_ltp_info.cr3 = r3;
- dos_ltp_info.cr4 = r4;
- }
-
- /* OK then, we have to translate */
- off = linear & 0xFFFUL;
- linear >>= 12UL;
- if (dos_ltp_info.cr3 < 0x1000) /* if the contents of CR3 are not available, then we cannot translate */
- return ret;
-
- /* VCPI possibility: the page table might reside below 1MB in DOS memory, and remain unmapped. */
- if (dos_ltp_info.dos_remap && dos_ltp_info.vcpi_xlate && dos_ltp_info.cr3 < 0x100000UL) {
- lock1 = 0;
- if (dos_linear_to_phys_vcpi(dos_ltp_info.cr3>>12) == (dos_ltp_info.cr3&0xFFFFF000UL)) /* if VCPI says it's a 1:1 mapping down there, then it's OK */
- l1 = (uint32_t*)(dos_ltp_info.cr3 & 0xFFFFF000UL);
- }
- /* DOS4/GW and DOS32A Goodie: the first level of the page table is in conventional memory... and the extender maps DOS 1:1 :) */
- else if (!dos_ltp_info.dos_remap && dos_ltp_info.cr3 < 0x100000UL) {
- lock1 = 0;
- l1 = (uint32_t*)(dos_ltp_info.cr3 & 0xFFFFF000UL);
- }
- else {
- /* well, then we gotta map it */
- l1 = (uint32_t*)dpmi_phys_addr_map(dos_ltp_info.cr3 & 0xFFFFF000UL,4096);
- if (l1 != NULL) lock1 = 1;
- }
-
- if (l1 != NULL) {
- /* level 1 lookup */
- ent = l1[linear >> 10UL];
- if (ent & 1) { /* if the page is actually present... */
- /* if the CPU supports PSE (Page Size Extensions) and has them enabled (via CR4) and the page is marked PS=1 */
- if ((cpu_cpuid_features.a.raw[2/*EDX*/] & (1 << 3)) && (dos_ltp_info.cr4 & 0x10) && (ent & 0x80)) {
- /* it's a 4MB page, and we stop searching the page hierarchy here */
- ret = ent & 0xFFC00000UL; /* bits 31-22 are the actual page address */
-
- /* but wait: if the CPU supports PSE-36, then we need to readback address bits 35...32,
- * or if an AMD64 processor, address bits 39...32 */
- /* FIXME: So, we can assume if the CPU supports 64-bit long mode, that we can use bits 39...32?
- * Perhaps this is a more in-depth check that we should be doing in the ltp_probe function? */
- if (cpu_cpuid_features.a.raw[2/*E2X*/] & (1 << 17)) { /* If PSE support exists */
- if (cpu_cpuid_features.a.raw[3/*ECX*/] & (1 << 29)) { /* If CPU supports 64-bit long mode */
- /* AMD64 compatible, up to 40 bits */
- ret |= ((uint64_t)((ent >> 13UL) & 0xFFUL)) << 32ULL;
- }
- else { /* else, assume Pentium III compatible, up to 36 bits */
- ret |= ((uint64_t)((ent >> 13UL) & 0xFUL)) << 32ULL;
- }
- }
- }
- else {
- /* VCPI possibility: the page table might reside below 1MB in DOS memory, and remain unmapped. */
- if (dos_ltp_info.dos_remap && dos_ltp_info.vcpi_xlate && ent < 0x100000UL) {
- lock2 = 0;
- if (dos_linear_to_phys_vcpi(ent>>12) == (ent&0xFFFFF000UL)) /* if VCPI says it's a 1:1 mapping down there, then it's OK */
- l2 = (uint32_t*)(ent & 0xFFFFF000UL);
- }
- /* again the second level is usually in DOS memory where we can assume 1:1 mapping */
- else if (!dos_ltp_info.dos_remap && !dos_ltp_info.dos_remap && ent < 0x100000UL) {
- lock2 = 0;
- l2 = (uint32_t*)(ent & 0xFFFFF000UL);
- }
- else {
- /* well, then we gotta map it */
- l2 = (uint32_t*)dpmi_phys_addr_map(ent & 0xFFFFF000UL,4096);
- if (l2 != NULL) lock2 = 1;
- }
- }
- }
- }
-
- if (l2 != NULL) {
- /* level 2 lookup */
- ent = l2[linear & 0x3FF];
- if (ent & 1) { /* if the page is actually present... */
- ret = ent & 0xFFFFF000UL;
- }
- }
-
- if (lock2) dpmi_phys_addr_free((void*)l2);
- if (lock1) dpmi_phys_addr_free((void*)l1);
- return ret;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-unsigned char FAR *dos_mcb_get_psp(struct dos_mcb_enum *e) {
- if (e->psp < 0x80 || e->psp == 0xFFFFU)
- return NULL;
-
-#if TARGET_MSDOS == 32
- return (unsigned char*)((uint32_t)e->psp << 4UL);
-#else
- return (unsigned char FAR*)MK_FP(e->psp,0);
-#endif
-}
-
-int mcb_name_is_junk(char *s/*8 char*/) {
- int junk=0,i;
- unsigned char c;
-
- for (i=0;i < 8;i++) {
- c = (unsigned char)s[i];
- if (c == 0)
- break;
- else if (c < 32 || c >= 127)
- junk = 1;
- }
-
- return junk;
-}
-
-uint16_t dos_mcb_first_segment() {
- if (dos_LOL == NULL)
- return 0;
-
- return *((uint16_t FAR*)(dos_LOL-2)); /* NTS: This is not a mistake. You take the pointer given by DOS and refer to the WORD starting 2 bytes PRIOR. I don't know why they did that... */
-}
-
-void mcb_filter_name(struct dos_mcb_enum *e) {
- if (e->psp > 0 && e->psp < 0x80) { /* likely special DOS segment */
- if (!memcmp(e->name,"SC",2) || !memcmp(e->name,"SD",2))
- memset(e->name+2,0,6);
- else
- memset(e->name,0,8);
- }
- else if (mcb_name_is_junk(e->name)) {
- memset(e->name,0,8);
- }
-}
-
-int dos_mcb_next(struct dos_mcb_enum *e) {
- unsigned char FAR *mcb;
- unsigned int i;
- uint16_t nxt;
-
- if (e->type == 0x5A || e->segment == 0x0000U || e->segment == 0xFFFFU)
- return 0;
- if (e->counter >= 16384)
- return 0;
-
-#if TARGET_MSDOS == 32
- mcb = (unsigned char*)((uint32_t)(e->segment) << 4UL);
- e->ptr = mcb + 16;
-#else
- mcb = (unsigned char far*)(MK_FP(e->segment,0));
- e->ptr = (unsigned char far*)(MK_FP(e->segment+1U,0));
-#endif
-
- e->cur_segment = e->segment;
- e->type = *((uint8_t FAR*)(mcb+0));
- e->psp = *((uint16_t FAR*)(mcb+1));
- e->size = *((uint16_t FAR*)(mcb+3));
- for (i=0;i < 8;i++) e->name[i] = mcb[i+8]; e->name[8] = 0;
- if (e->type != 0x5A && e->type != 0x4D) return 0;
- nxt = e->segment + e->size + 1;
- if (nxt <= e->segment) return 0;
- e->segment = nxt;
- return 1;
-}
-
-int dos_mcb_first(struct dos_mcb_enum *e) {
- if (dos_LOL == NULL)
- return 0;
-
- e->counter = 0;
- e->segment = dos_mcb_first_segment();
- if (e->segment == 0x0000U || e->segment == 0xFFFFU)
- return 0;
-
- return dos_mcb_next(e);
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* TODO: This should be moved into the hw/DOS library */
-unsigned char nmi_32_hooked = 0;
-int nmi_32_refcount = 0;
-void (interrupt *nmi_32_old_vec)() = NULL;
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NMI reflection (32-bit -> 16-bit)
- This code is VITAL if we want to work with SBOS and MEGA-EM
- from protected mode. */
-static struct dpmi_realmode_call nmi_32_nr={0};
-static void interrupt far nmi_32() {
- /* trigger a real-mode INT 02h */
- __asm {
- mov ax,0x0300
- mov bx,0x02
- xor cx,cx
- mov edi,offset nmi_32_nr ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-
-void do_nmi_32_unhook() {
- if (nmi_32_refcount > 0)
- nmi_32_refcount--;
-
- if (nmi_32_refcount == 0) {
- if (nmi_32_hooked) {
- nmi_32_hooked = 0;
- _dos_setvect(0x02,nmi_32_old_vec);
- nmi_32_old_vec = NULL;
- }
- }
-}
-
-void do_nmi_32_hook() {
- if (nmi_32_refcount == 0) {
- if (!nmi_32_hooked) {
- nmi_32_hooked = 1;
- nmi_32_old_vec = _dos_getvect(0x02);
- _dos_setvect(0x02,nmi_32);
- }
- }
- nmi_32_refcount++;
-}
-#endif
-
+++ /dev/null
-; dosasm.asm
-;
-; Assembly language support routines for dos.c
-; (C) 2011-2012 Jonathan Campbell.
-; Hackipedia DOS library.
-;
-; This code is licensed under the LGPL.
-; <insert LGPL legal text here>
-
-extern _dpmi_entered ; BYTE
-extern _dpmi_entry_point ; DWORD
-extern _dpmi_private_data_segment ; word
-extern _dpmi_rm_entry ; qword
-extern _dpmi_pm_entry ; dword
-extern _dpmi_pm_cs,_dpmi_pm_ds,_dpmi_pm_es,_dpmi_pm_ss
-
-section .text class=CODE
-
-; NTS: If we code 'push ax' and 'popf' for the 16-bit tests in 32-bit protected mode we will screw up the stack pointer and crash
-; so we avoid duplicate code by defining 'native' pushf/popf functions and 'result' to ax or eax depending on CPU mode
-%if TARGET_MSDOS == 32
- %define point_s esi
- %define result eax
- %define pushfn pushfd
- %define popfn popfd
-use32
-%else
- %define point_s si
- %define result ax
- %define pushfn pushf
- %define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-%ifndef TARGET_WINDOWS
- %if TARGET_MSDOS == 16
-; cheap coding: put some variables here in the code segment. as real-mode
-; code there's nothing to stop us from leaving DS == CS on entry and letting
-; DPMI build an alias to our own code segment
-l_dpmi_mode db 0
-l_dpmi_rm_entry dd 0 ; also re-used to call entry!
- dw 0
-l_dpmi_pm_entry dd 0
-; we also need to record the segments given to us by the DPMI server so
-; that we can re-enter protected mode
-l_dpmi_segs dw 0,0,0,0
-this_process_psp dw 0
-
-; void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
-global _dpmi_enter_core
-_dpmi_enter_core:
- ; 16-bit or 32-bit?
- pushf
- pusha
- push ds
- push es
- push cs
- push ss
- cli
- mov ax,seg _dpmi_entered
- mov ds,ax
- xor ax,ax
- mov bl,byte [_dpmi_entered]
- mov byte [cs:l_dpmi_mode],bl ; the protected mode side of the function needs this
- cmp bl,32
- jnz .not32_ax
- or al,1 ; indicate 32-bit DPMI connection
-.not32_ax:
- ; so: AX=0 if 16-bit setup, AX=1 if 32-bit setup. Now for simplicity set DS==CS
- mov bx,seg _dpmi_private_data_segment ; NTS may be zero if DPMI doesn't need it
- mov es,bx
- mov es,[es:_dpmi_private_data_segment] ; NTS: ES = DPMI private data. Do not modify between here and call to DPMI entry
-
- mov bx,seg _dpmi_entry_point
- mov ds,bx
- mov bx,word [_dpmi_entry_point+0]
- mov word [cs:l_dpmi_rm_entry+0],bx
- mov bx,word [_dpmi_entry_point+2]
- mov word [cs:l_dpmi_rm_entry+2],bx
-
- mov bx,cs
- mov ds,bx
- call far word [cs:l_dpmi_rm_entry]
- jnc .entry_ok
- ; ENTRY FAILED. Set entered flag to zero and return
- mov ax,seg _dpmi_entered
- mov ds,ax
- mov byte [_dpmi_entered],0
- add sp,4 ; discard saved CS+SS
- pop es
- pop ds
- popa
- popf
- retnative
-; HERE: Entry succeeded. Get DPMI PM/RM entry points and then switch back to real mode.
-; note that because we entered with DS == CS the DPMI server should have CS != DS but both
-; refer to the same segment, as aliases. That makes our job simpler as we can use local storage
-; privately in the code segment.
-.entry_ok:
- mov ax,0x0306
- int 31h
-
- ; BX:CX real to protected mode entry point
- mov word [l_dpmi_pm_entry+0],cx
- mov word [l_dpmi_pm_entry+2],bx
-
- ; save the selectors preallocated by DPMI
- mov word [l_dpmi_segs+0],cs
- mov word [l_dpmi_segs+2],ds
- mov word [l_dpmi_segs+4],es
- mov word [l_dpmi_segs+6],ss
-
- ; SI:DI (16-bit) or SI:EDI (32-bit) protected mode to real mode entry point
- cmp byte [l_dpmi_mode],32
- jnz .store_16
- ; 32-bit storage, and return
- mov dword [l_dpmi_rm_entry+0],edi
- mov word [l_dpmi_rm_entry+4],si
- pop dx ; restore SS into DX. DX will become SS
- pop ax ; restore CS into AX. AX will become DS
- mov cx,ax ; CX will become ES
- mov si,ax ; SI will become CS
- mov bx,sp ; BX will become SP
- mov di,.exit_ok ; DI will become IP, so direct it at the exit point below
- jmp far dword [l_dpmi_rm_entry]
-.store_16:
- ; 16-bit storage, and return
- mov word [l_dpmi_rm_entry+0],di
- mov word [l_dpmi_rm_entry+2],si
- pop dx ; restore SS into DX. DX will become SS
- pop ax ; restore CS into AX. AX will become DS
- mov cx,ax ; CX will become ES
- mov si,ax ; SI will become CS
- mov bx,sp ; BX will become SP
- mov di,.exit_ok ; DI will become IP, so direct it at the exit point below
- jmp far word [l_dpmi_rm_entry]
-; jump back to realmode here
-.exit_ok:
-
-; copy results to host variables
- mov ax,word [cs:l_dpmi_pm_entry]
- mov bx,word [cs:l_dpmi_pm_entry+2]
- mov cx,seg _dpmi_pm_entry
- mov ds,cx
- mov word [_dpmi_pm_entry+0],ax
- mov word [_dpmi_pm_entry+2],bx
-
- mov ax,word [cs:l_dpmi_rm_entry]
- mov bx,word [cs:l_dpmi_rm_entry+2]
- mov cx,word [cs:l_dpmi_rm_entry+4]
- mov dx,seg _dpmi_rm_entry
- mov ds,dx
- mov word [_dpmi_rm_entry+0],ax
- mov word [_dpmi_rm_entry+2],bx
- mov word [_dpmi_rm_entry+4],cx
-
- mov ax,word [cs:l_dpmi_segs+0]
- mov dx,seg _dpmi_pm_cs
- mov ds,dx
- mov word [_dpmi_pm_cs],ax
-
- mov ax,word [cs:l_dpmi_segs+2]
- mov dx,seg _dpmi_pm_ds
- mov ds,dx
- mov word [_dpmi_pm_ds],ax
-
- mov ax,word [cs:l_dpmi_segs+4]
- mov dx,seg _dpmi_pm_es
- mov ds,dx
- mov word [_dpmi_pm_es],ax
-
- mov ax,word [cs:l_dpmi_segs+6]
- mov dx,seg _dpmi_pm_ss
- mov ds,dx
- mov word [_dpmi_pm_ss],ax
-
- ; now that DPMI is active, we have to hook real-mode INT 21h
- ; to catch program termination, so we can forward that to the DPMI
- ; server for proper DPMI cleanup
- call dpmi_hook_int21
-
- pop es
- pop ds
- popa
- popf
- retnative
- %endif
-%endif
-
-; INT 21h hook:
-; We use DPMI entry and thunking back to real mode to let the host
-; program remain 16-bit. BUT: there's a problem. if the host program
-; exits normally with INT 21h via real mode, the DPMI server never gets
-; the message and it remains stuck running in the background. To make
-; DPMI exit normally, we have to hook INT 21h and reflect AH=0x4C to
-; protected mode.
-%ifndef TARGET_WINDOWS
- %if TARGET_MSDOS == 16
-old_int21h dd 0
-dpmi_hook_int21:
- push es
- push ax
- push bx
- push cx
- xor ax,ax
- mov es,ax
- mov ax,cs
- mov bx,word [es:(0x21*4)]
- mov cx,word [es:(0x21*4)+2]
- mov word [es:(0x21*4)],dpmi_int21_hook_exit
- mov word [es:(0x21*4)+2],ax
- mov word [cs:old_int21h+0],bx
- mov word [cs:old_int21h+2],cx
-
- ; also keep track of this process's PSP segment, so we can readily
- ; identify WHO is calling INT 21h AH=0x4C and forward to DPMI only
- ; for our process, not any other process.
- mov ah,0x62
- int 21h
- mov word [cs:this_process_psp],bx
-
- pop cx
- pop bx
- pop ax
- pop es
- ret
-
-; Our INT 21h hook. We're looking for any INT 21h AH=0x4C call coming from
-; this process. If the call comes from any other program in memory, the call
-; is forwarded without modification, so that DPMI does not prematurely exit
-; when subprocesses started by this program terminate.
-;
-; This hack seems silly but apparently most DPMI servers do not monitor real-mode
-; INT 21h for the AH=0x4C call. If they never see the termination call from
-; protected mode, then they never clean up for this process and in most cases
-; (especially Windows) end up leaking selectors and other resources. So to avoid
-; memory leaks, we must forward INT 21h AH=0x4C to the protected mode side of
-; the DPMI server.
-;
-; TODO: This hook should also catch INT 21h AH=31 Terminate and Stay Resident,
-; DPMI needs to keep those too!
-;
-; FIXME: How will this code catch cases where the calling program calls INT 21h
-; from protected mode to terminate? Worst case scenario: DPMI cleans up
-; and we never get a chance to remove our INT 21h hook.
-dpmi_int21_hook_exit:
- cmp ah,0x4C
- jz .catch_exit
- jmp far word [cs:old_int21h]
-.catch_exit:
- ; this is our process terminating, not some subprocess, right?
- ; we want to forward termination only for this process, not anyone else.
- push ax
- push bx
- mov ah,0x62 ; get PSP segment
- int 21h
- cmp bx,word [cs:this_process_psp]
- jz .catch_exit_psp
- pop bx
- pop ax
- jmp far word [cs:old_int21h]
-.catch_exit_psp:
- pop bx
- pop ax
- ; restore the old vector
- push es
- push ax
- push bx
- push cx
- xor ax,ax
- mov es,ax
- mov ax,cs
- mov bx,word [cs:old_int21h+0]
- mov cx,word [cs:old_int21h+2]
- mov word [es:(0x21*4)],bx
- mov word [es:(0x21*4)+2],cx
- pop cx
- pop bx
- pop ax
- pop es
- ; OK. Switch into protected mode.
- ; use the segment values given to us by the DPMI server.
- cli
- mov bp,ax ; save AX
- mov ax,word [cs:l_dpmi_segs+2] ; AX becomes DS (so load DS from DPMI env)
- mov cx,ax ; CX becomes ES
- mov dx,ax ; DX becomes SS (doesn't matter)
- mov bx,sp ; BX becomes SP (doesn't matter)
- mov si,word [cs:l_dpmi_segs+0] ; SI becomes CS (so load CS from DPMI env)
- mov di,.catch_exit_pmode ; DI becomes IP
- jmp far word [cs:l_dpmi_pm_entry]
-.catch_exit_pmode:
- mov ax,bp
- mov ah,0x4C
- int 21h ; now issue INT 21h AH=0x4C where the DPMI server can see it
- hlt
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef TARGET_WINDOWS
-
-; WARNING: The caller must have ensured we are running on a 386 or higher, and that
-; the DPMI entry points were obtained
-
-; __cdecl: right-to-left argument passing (meaning: caller does "push sz", "push lsrc", "push dst"...)
-l_lin2fm_params:
-l_lin2fm_param_dst: dd 0 ; unsigned char far *dst
-l_lin2fm_param_lsrc: dd 0 ; uint32_t lsrc
-l_lin2fm_param_sz: dd 0 ; uint32_t sz
- ; = 12 bytes
-
-l_rm_ret dw 0
-l_rm_reentry dd 0
- dw 0
-
-; TODO: Export these so they are visible as C variables
-; we need these selectors for copy operation
-l_lin2fm_src_sel dw 0
-l_lin2fm_dst_sel dw 0
-
-; dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss
-; int __cdecl dpmi_lin2fmemcpy_32(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-global _dpmi_lin2fmemcpy_32
-_dpmi_lin2fmemcpy_32:
- push bp
- mov bp,sp
-
- ; copy params, we need them in protected mode
- mov eax,dword [bp+cdecl_param_offset+0]
- mov dword [cs:l_lin2fm_params+0],eax
- mov eax,dword [bp+cdecl_param_offset+4]
- mov dword [cs:l_lin2fm_params+4],eax
- mov eax,dword [bp+cdecl_param_offset+8]
- mov dword [cs:l_lin2fm_params+8],eax
-
- pusha ; save all regs
-
- push ds
- push es
-
- push cs ; realmode re-entry needs this
- push ss ; realmode re-entry needs this
- push ds ; realmode re-entry needs this
-
- mov ax,seg _dpmi_pm_entry
- mov ds,ax
-
- xor ax,ax
- mov word [cs:l_rm_ret],ax
-
- mov eax,dword [_dpmi_rm_entry+0]
- mov dword [cs:l_rm_reentry+0],eax
-
- mov ax,word [_dpmi_rm_entry+4]
- mov word [cs:l_rm_reentry+4],ax
-
- mov ax,word [_dpmi_pm_ds]
- mov cx,ax
- mov dx,word [_dpmi_pm_ss]
- mov bx,sp
- mov si,word [_dpmi_pm_cs]
- mov di,.entry_pm
- call far word [_dpmi_pm_entry]
- ; didn't make it. error return
- add sp,6 ; do not restore SS+CS+DS, just discard
- pop es
- pop ds
- popa
- pop bp
- xor ax,ax ; return 0 == no copy made
- retnative
-.entry_pm:
-
- ; we need to allocate two selectors to do the copy operation with
- cmp word [l_lin2fm_src_sel],0
- jnz .sel_avail ; if != 0, then skip code
- ; allocate two descriptors
- xor ax,ax
- mov cx,2
- int 31h
- jnc .sel_alloced ; if carry clear, continue
- jmp .go_to_exit_pm ; else return to RM with retval == 0
-.sel_alloced:
- ; we got two descriptors, store them
- mov word [l_lin2fm_src_sel],ax
- add ax,8 ; obviously...
- mov word [l_lin2fm_dst_sel],ax
- ; we need to make them data selectors
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_src_sel]
- mov cl,0xF0 ; P=1 DPL=3 data expand-up r/o. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_src_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
- ; and the other one
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_dst_sel]
- mov cl,0xF2 ; P=1 DPL=3 data expand-up r/w. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_dst_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
-.sel_avail:
- ; OK, pull in source address (flat) from param and set the selector base
- mov ax,0x0007
- mov bx,word [l_lin2fm_src_sel]
- mov dx,word [l_lin2fm_param_lsrc+0] ; CX:DX = base
- mov cx,word [l_lin2fm_param_lsrc+2]
- int 31h
- ; and the dest address (realmode seg:off) too
- movzx eax,word [l_lin2fm_param_dst+2]
- shl eax,4
- movzx ebx,word [l_lin2fm_param_dst+0]
- add eax,ebx
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,word [l_lin2fm_dst_sel]
- mov ax,0x0007
- int 31h
- ; alright then, do the memcpy
- mov cx,word [l_lin2fm_param_sz]
- mov word [l_rm_ret],cx ; set return value too
- push ds
- push es
- cld
- mov ax,word [l_lin2fm_src_sel]
- mov bx,word [l_lin2fm_dst_sel]
- mov ds,ax
- mov es,bx
- xor si,si
- mov di,si
- rep movsb ; ES:DI <- DS:SI
- pop es
- pop ds
-.go_to_exit_pm:
- ; NTS: when dpmi_enter_core() did it's job it made sure DS == CS
- ; so the DPMI server would make DS an alias of CS in protected mode
- pop ax ; AX = realmode DS
- mov cx,ax
- pop dx ; DX = realmode SS
- pop si ; SI = realmode CS
- mov bx,sp
- mov di,.exit_pm
- call far dword [l_rm_reentry] ; NTS: We're using the 32-bit DPMI server, the RM entry point is 16:32 format
-.exit_pm: ; NTS: Don't forget CS+DS+SS was pushed but the PM part popped them as part of returning
- pop es
- pop ds
- popa
-
- pop bp
- mov ax,word [cs:l_rm_ret]
- retnative
-
-; NOTE: This version of the code is written to work with 16-bit DPMI servers,
-; and to work within the constraint that we could be run on a 286 where
-; 32-bit registers are not available.
-; dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss
-; int __cdecl dpmi_lin2fmemcpy_16(unsigned char far *dst,uint32_t lsrc,uint32_t sz);
-global _dpmi_lin2fmemcpy_16
-_dpmi_lin2fmemcpy_16:
- push bp
- mov bp,sp
-
- ; copy params, we need them in protected mode
- mov ax,word [bp+cdecl_param_offset+0]
- mov word [cs:l_lin2fm_params+0],ax
- mov ax,word [bp+cdecl_param_offset+2]
- mov word [cs:l_lin2fm_params+2],ax
- mov ax,word [bp+cdecl_param_offset+4]
- mov word [cs:l_lin2fm_params+4],ax
- mov ax,word [bp+cdecl_param_offset+6]
- mov word [cs:l_lin2fm_params+6],ax
- mov ax,word [bp+cdecl_param_offset+8]
- mov word [cs:l_lin2fm_params+8],ax
- mov ax,word [bp+cdecl_param_offset+10]
- mov word [cs:l_lin2fm_params+10],ax
-
- pusha ; save all regs
-
- push ds
- push es
-
- push cs ; realmode re-entry needs this
- push ss ; realmode re-entry needs this
- push ds ; realmode re-entry needs this
-
- mov ax,seg _dpmi_pm_entry
- mov ds,ax
-
- xor ax,ax
- mov word [cs:l_rm_ret],ax
-
- mov eax,dword [_dpmi_rm_entry+0]
- mov dword [cs:l_rm_reentry+0],eax
-
- mov ax,word [_dpmi_rm_entry+4]
- mov word [cs:l_rm_reentry+4],ax
-
- mov ax,word [_dpmi_pm_ds]
- mov cx,ax
- mov dx,word [_dpmi_pm_ss]
- mov bx,sp
- mov si,word [_dpmi_pm_cs]
- mov di,.entry_pm
- call far word [_dpmi_pm_entry]
- ; didn't make it. error return
- add sp,6 ; do not restore SS+CS+DS, just discard
- pop es
- pop ds
- popa
- pop bp
- xor ax,ax ; return 0 == no copy made
- retnative
-.entry_pm:
-
- ; we need to allocate two selectors to do the copy operation with
- cmp word [l_lin2fm_src_sel],0
- jnz .sel_avail ; if != 0, then skip code
- ; allocate two descriptors
- xor ax,ax
- mov cx,2
- int 31h
- jnc .sel_alloced ; if carry clear, continue
- jmp .go_to_exit_pm ; else return to RM with retval == 0
-.sel_alloced:
- ; we got two descriptors, store them
- mov word [l_lin2fm_src_sel],ax
- add ax,8 ; obviously...
- mov word [l_lin2fm_dst_sel],ax
- ; we need to make them data selectors
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_src_sel]
- mov cl,0xF0 ; P=1 DPL=3 data expand-up r/o. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_src_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
- ; and the other one
- mov ax,0x0009 ; DPMI Set Descriptor Access Rights
- mov bx,word [l_lin2fm_dst_sel]
- mov cl,0xF2 ; P=1 DPL=3 data expand-up r/w. I know DPMI says it must equal our level, but Windows always runs us Ring-3 so we can assume
- xor ch,ch ; 16-bit selector (we are 16-bit code!)
- int 31h
- jc short $ ; FIXME:For now, hang if the request failed
- mov ax,0x0008 ; DPMI Set Selector Limit
- mov bx,word [l_lin2fm_dst_sel]
- xor cx,cx
- xor dx,dx
- dec dx ; CX:DX = 0000:FFFF
- int 31h
-.sel_avail:
- ; OK, pull in source address (flat) from param and set the selector base
- mov ax,0x0007
- mov bx,word [l_lin2fm_src_sel]
- mov dx,word [l_lin2fm_param_lsrc+0] ; CX:DX = base
- mov cx,word [l_lin2fm_param_lsrc+2]
- int 31h
- ; and the dest address (realmode seg:off) too
- mov dx,word [l_lin2fm_param_dst+2] ; DX = (seg << 4) + offset, CX = (seg >> 12) + (carry flag result of computing DX)
- mov cx,dx
- shr cx,12
- shl dx,4
- add dx,word [l_lin2fm_param_dst+0]
- adc cx,0 ; CX:DX = 32-bit linear address
- mov bx,word [l_lin2fm_dst_sel]
- mov ax,0x0007
- int 31h
- ; alright then, do the memcpy
- mov cx,word [l_lin2fm_param_sz]
- mov word [l_rm_ret],cx ; set return value too
- push ds
- push es
- cld
- mov ax,word [l_lin2fm_src_sel]
- mov bx,word [l_lin2fm_dst_sel]
- mov ds,ax
- mov es,bx
- xor si,si
- mov di,si
- rep movsb ; ES:DI <- DS:SI
- pop es
- pop ds
-.go_to_exit_pm:
- ; NTS: when dpmi_enter_core() did it's job it made sure DS == CS
- ; so the DPMI server would make DS an alias of CS in protected mode
- pop ax ; AX = realmode DS
- mov cx,ax
- pop dx ; DX = realmode SS
- pop si ; SI = realmode CS
- mov bx,sp
- mov di,.exit_pm
- call far word [l_rm_reentry] ; NTS: We're using the 16-bit DPMI server, the RM entry point is 16:16 format
-.exit_pm: ; NTS: Don't forget CS+DS+SS was pushed but the PM part popped them as part of returning
- pop es
- pop ds
- popa
-
- pop bp
- mov ax,word [cs:l_rm_ret]
- retnative
-
- %endif
-%endif
+++ /dev/null
-/* dosbox.c
- *
- * Detect whether or not we're running under the DOSBox emulator
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-static const char *dosbox_fakebios = "DOSBox FakeBIOS v1.0";
-#endif
-
-/* the ROM area doesn't change. so remember our last result */
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-static signed char dosbox_detect_cache = -1;
-#endif
-
-int detect_dosbox_emu() {
-#if defined(TARGET_OS2)
- /* TODO: So... how does one read the ROM BIOS area from OS/2? */
- return 0;
-#elif defined(TARGET_WINDOWS)
- /* TODO: I know that from within Windows there are various ways to scan the ROM BIOS area.
- * Windows 1.x and 2.x (if real mode) we can just use MK_FP as we do under DOS, but
- * we have to use alternate means if Windows is in protected mode. Windows 2.x/3.x protected
- * mode (and because of compatibility, Windows 95/98/ME), there are two methods open to us:
- * One is to use selector constants that are hidden away in KRNL386.EXE with names like _A0000,
- * _B0000, etc. They are data selectors that when loaded into the segment registers point to
- * their respective parts of DOS adapter ROM and BIOS ROM. Another way is to use the Win16
- * API to create a data selector that points to the BIOS. Windows 386 Enhanced mode may map
- * additional things over the unused parts of adapter ROM, but experience shows that it never
- * relocates or messes with the VGA BIOS or with the ROM BIOS,
- *
- * My memory is foggy at this point, but I remember that under Windows XP SP2, one of the
- * above Win16 methods still worked even from under the NT kernel.
- *
- * For Win32 applications, if the host OS is Windows 3.1 Win32s or Windows 95/98/ME, we can
- * take advantage of a strange quirk in the way the kernel maps the lower 1MB. For whatever
- * reason, the VGA RAM, adapter ROM, and ROM BIOS areas are left open even for Win32 applications
- * with no protection. Thus, a Win32 programmer can just make a pointer like
- * char *a = (char*)0xA0000 and scribble on legacy VGA RAM to his heart's content (though on
- * modern PCI SVGA hardware the driver probably instructs the card to disable VGA compatible
- * mapping). In fact, this ability to scribble on RAM directly is at the heart of one of Microsoft's
- * earliest and hackiest "Direct Draw" interfaces known as "DISPDIB.DLL", a not-to-well documented
- * library responsible for those Windows 3.1 multimedia apps and games that were somehow able to
- * run full-screen 320x200x256 color VGA despite being Windows GDI-based apps. Ever wonder how the
- * MCI AVI player was able to go full-screen when DirectX and WinG were not invented yet? Now you
- * know :)
- *
- * There are some VFW codecs out there as well, that also like to abuse DISPDIB.DLL for "fullscreen"
- * modes. One good example is the old "Motion Pixels" codec, that when asked to go fullscreen,
- * uses DISPDIB.DLL and direct VGA I/O port trickery to effectively set up a 320x480 256-color mode,
- * which it then draws on "fake hicolor" style to display the video (though a bit dim since you're
- * sort of watching a video through a dithered mesh, but...)
- *
- * In case you were probably wondering, no, Windows NT doesn't allow Win32 applications the same
- * privilege. Win32 apps writing to 0xA0000 would page fault and crash. Curiously enough though,
- * NTVDM.EXE does seem to open up the 0xA0000-0xFFFFF memory area to Win16 applications if they
- * use the right selectors and API calls. */
- return 0;
-#else
- int i;
-# if TARGET_MSDOS == 32
- const char *scan;
-# else
- const char far *scan;
-# endif
-
- probe_dos();
- if (dosbox_detect_cache >= 0)
- return (int)dosbox_detect_cache;
-
-# if TARGET_MSDOS == 32
- if (dos_flavor == DOS_FLAVOR_FREEDOS) {
- /* FIXME: I have no idea why but FreeDOS 1.0 has a strange conflict with DOS32a where if this code
- * tries to read the ROM BIOS it causes a GPF and crashes (or sometimes runs off into the
- * weeds leaving a little garbage on the screen). DOS32a's register dump seems to imply that
- * at one point our segment limits were suddenly limited to 1MB (0xFFFFF). I have no clue
- * what the hell is triggering it, but I know from testing we can avoid that crash by not
- * scanning. */
- if (freedos_kernel_version == 0x000024UL) /* 0.0.36 */
- return (dosbox_detect_cache=0);
- }
-# endif
-
-/* signs that we're running under DOSBOX:
- * - the majority of the adapter ROM area is 0x00 (not 0xFF or any other value). Here we check 0xE000:0xFF00 and 0xF000:0x000.
- * - an ASCII string is visible at 0xF000:0xE061: "DOSBox FakeBIOS v1.0" */
-
-# if TARGET_MSDOS == 32
- scan = (const char*)0xEFF00UL;
-# else
- scan = (const char far*)MK_FP(0xE000,0xFF00);
-# endif
-
- for (i=0;i < 256;i++) {
- if (scan[i] != 0)
- return (dosbox_detect_cache=0);
- }
-
-# if TARGET_MSDOS == 32
- scan = (const char*)0xF0000UL;
-# else
- scan = (const char far*)MK_FP(0xF000,0x0000);
-# endif
- for (i=0;i < 256;i++) {
- if (scan[i] != 0)
- return (dosbox_detect_cache=0);
- }
-
-# if TARGET_MSDOS == 32
- scan = (const char*)0xFE061UL;
-# else
- scan = (const char far*)MK_FP(0xF000,0xE061);
-# endif
- i = 0;
- do {
- if (dosbox_fakebios[i] != scan[i])
- return (dosbox_detect_cache=0);
- } while (dosbox_fakebios[i++] != 0);
-
- return (dosbox_detect_cache=1);
-#endif
-}
-
+++ /dev/null
-/* dosbox.h
- *
- * Detect whether or not we're running under the DOSBox emulator
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdint.h>
-
-int detect_dosbox_emu();
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-int dos_device_next(struct dos_device_enum *e) {
- e->raw = e->next;
- if (e->raw == NULL || e->count >= 512 || e->no == 0xFFFFU)
- return 0;
-
- e->no = *((uint16_t FAR*)(e->raw + 0x0));
- e->ns = *((uint16_t FAR*)(e->raw + 0x2));
- e->attr = *((uint16_t FAR*)(e->raw + 0x04));
- e->entry = *((uint16_t FAR*)(e->raw + 0x06));
- e->intent = *((uint16_t FAR*)(e->raw + 0x08));
- if (!(e->attr & 0x8000)) {
- /* block device */
- _fmemcpy(e->name,e->raw+0x0B,8); e->name[7] = 0;
- if (e->name[0] < 33 || e->name[0] >= 127) e->name[0] = 0;
- }
- else {
- /* char device */
- _fmemcpy(e->name,e->raw+0x0A,8); e->name[8] = 0;
- }
- e->count++;
-
-#if TARGET_MSDOS == 32
- e->next = (unsigned char*)((((uint32_t)(e->ns)) << 4UL) + e->no);
-#else
- e->next = (unsigned char FAR*)MK_FP(e->ns,e->no);
-#endif
-
- return 1;
-}
-
-int dos_device_first(struct dos_device_enum *e) {
- unsigned int offset = 0x22; /* most common, DOS 3.1 and later */
-
- if (dos_LOL == NULL)
- return 0;
-
- if (dos_version < 0x200) /* We don't know where the first device is in DOS 1.x */
- return 0;
- else if (dos_version < 0x300)
- offset = 0x17;
- else if (dos_version == 0x300)
- offset = 0x28;
-
- e->no = 0;
- e->ns = 0;
- e->count = 0;
- e->raw = e->next = dos_LOL + offset;
- if (_fmemcmp(e->raw+0xA,"NUL ",8) != 0) /* should be the NUL device driver */
- return 0;
-
- return dos_device_next(e);
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
-int8_t dpmi_no_0301h = -1; /* whether or not the DOS extender provides function 0301h */
-#endif
-
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
-uint16_t dpmi_flags=0;
-uint16_t dpmi_version=0;
-unsigned char dpmi_init=0;
-uint32_t dpmi_entry_point=0;
-unsigned char dpmi_present=0;
-unsigned char dpmi_processor_type=0;
-uint16_t dpmi_private_data_length_paragraphs=0;
-uint16_t dpmi_private_data_segment=0xFFFF; /* when we DO enter DPMI, we store the private data segment here. 0 = no private data. 0xFFFF = not yet entered */
-unsigned char dpmi_entered = 0; /* 0=not yet entered, 16=entered as 16bit, 32=entered as 32bit */
-uint64_t dpmi_rm_entry = 0;
-uint32_t dpmi_pm_entry = 0;
-
-/* once having entered DPMI, keep track of the selectors registers given to us in p-mode */
-uint16_t dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss;
-
-void __cdecl dpmi_enter_core(); /* Watcom's inline assembler is too limiting to carry out the DPMI entry and switch back */
-#endif
-
-/* 16-bit real mode DOS or 16-bit protected mode Windows */
-void probe_dpmi() {
-#if defined(TARGET_OS2)
- /* OS/2 apps do not run under DPMI */
-#elif TARGET_MSDOS == 32 && defined(TARGET_WINDOWS)
- /* Win32 apps do not bother with DPMI */
-#else
- if (!dpmi_init) {
- /* BUGFIX: WINE (Wine Is Not an Emulator) can run Win16 applications
- * but does not emulate the various low level interrupts one
- * can call. To avoid crashing under WINE we must not use
- * direct interrupts. */
- if (windows_emulation == WINEMU_WINE) {
- dpmi_present = 0;
- dpmi_init = 1;
- return;
- }
-
- {
- unsigned char present=0,proc=0;
- uint16_t version=0,privv=0,flags=0;
- uint32_t entry=0;
-
- __asm {
- push es
- mov ax,0x1687
- int 2Fh
- or ax,ax
- jnz err1
- mov present,1
- mov flags,bx
- mov proc,cl
- mov version,dx
- mov privv,si
- mov word ptr [entry+0],di
- mov word ptr [entry+2],es
- pop es
-err1:
- }
-
- dpmi_flags = flags;
- dpmi_present = present;
- dpmi_version = version;
- dpmi_entry_point = entry;
- dpmi_processor_type = proc;
- dpmi_private_data_segment = 0xFFFF;
- dpmi_private_data_length_paragraphs = privv;
- }
-
-#if TARGET_MSDOS == 32 || defined(TARGET_WINDOWS)
- /* when we ask for the "entry point" we mean we want the real-mode entrypoint.
- * apparently some DPMI servers like Windows XP+NTVDM.EXE translate ES:DI coming
- * back to a protected mode entry point, which is not what we're looking for.
- *
- * Interesting fact: When compiled as a Win16 app, the DPMI call actually works,
- * but returns an entry point appropriate for Win16 apps. So.... apparently we
- * can enter DPMI protected mode from within Win16? Hmm.... that might be something
- * fun to experiment with :) */
- if (dpmi_present) {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x1687;
- mux_realmode_2F_call(&rc);
- if ((rc.eax&0xFFFF) == 0) {
- dpmi_flags = rc.ebx&0xFFFF;
- dpmi_present = 1;
- dpmi_version = rc.edx&0xFFFF;
- dpmi_entry_point = (((uint32_t)rc.es << 16UL) & 0xFFFF0000UL) + (uint32_t)(rc.edi&0xFFFFUL);
- dpmi_processor_type = rc.ecx&0xFF;
- dpmi_private_data_segment = 0xFFFF;
- dpmi_private_data_length_paragraphs = rc.esi&0xFFFF;
- }
- else {
- dpmi_present = 0;
- }
- }
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
- dpmi_no_0301h = 0;
-#endif
- dpmi_init = 1;
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_OS2)
- if (dpmi_present) {
- /* Thanks to bullshit like DOS4/GW we have to test the extender to know
- whether or not core routines we need are actually there or not. If they
- are not, then alternative workarounds are required. The primary reason
- for this test is to avoid HIMEM.SYS API code returning nonsensical values
- caused by DOS4/GW not supporting such vital functions as DPMI 0301H:
- Call far real-mode procedure. Knowing this should also fix the VESA BIOS
- test bug where the protected-mode version is unable to use the BIOS's
- direct-call window bank-switching function.
-
- At least, this code so far can rely on DPMI function 0300H: call real-mode
- interrupt.*/
-
- /* test #1: allocate a 16-bit region, put a RETF instruction there,
- and ask the DPMI server to call it (0301H test).
-
- Success:
- Registers unchanged
- CF=0
-
- Failure (DOS4/GW):
- CF=1
- AX=0301H (wait wha?) */
- {
- uint16_t sel = 0;
- struct dpmi_realmode_call rc={0};
- unsigned char *proc = dpmi_alloc_dos(16,&sel);
- if (proc != NULL) {
- *proc = 0xCB; /* <- RETF */
-
- rc.cs = ((size_t)proc) >> 4UL;
- rc.ip = ((size_t)proc) & 0xFUL;
- if (dpmi_test_rm_entry_call(&rc) != 0)
- dpmi_no_0301h = 1;
-
- dpmi_free_dos(sel);
- }
- }
- }
-#endif
- }
-#endif
-}
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS)
-int dpmi_private_alloc() {
- unsigned short sss=0;
-
- if (!dpmi_present || dpmi_private_data_segment != 0xFFFFU)
- return 1; /* OK, nothing to do */
-
- if (dpmi_private_data_length_paragraphs == 0) {
- dpmi_private_data_segment = 0;
- return 0;
- }
-
- __asm {
- push ds
- mov ah,0x48
- mov bx,seg dpmi_private_data_length_paragraphs
- mov ds,bx
- mov bx,dpmi_private_data_length_paragraphs
- int 21h
- pop ds
- jc fail1
- mov sss,ax
-fail1:
- }
-
- if (sss == 0)
- return 0;
-
- dpmi_private_data_segment = sss;
- return 1;
-}
-
-/* NTS: This enters DPMI. There is no exit from DPMI. And if you re-enter DPMI by switching back to protected mode,
- * you only serve to confuse the server somewhat.
- *
- * Re-entry results:
- * - Windows XP: Allows it, even going 16 to 32 bit mode, but the console window gets confused and drops our
- * output when changing bit size.
- * - Windows 9x: Allows it, doesn't allow changing bit mode, so once in 16-bit mode you cannot enter 32-bit mode.
- * The mode persists until the DOS Box exits.
- *
- * This also means that once you init in one mode, you cannot re-enter another mode. If you init in 16-bit DPMI,
- * you cannot init into 32-bit DPMI.
- *
- * If all you want is the best mode, call with mode == 0xFF instead to automatically select. */
-int dpmi_enter(unsigned char mode) {
-/* TODO: Cache results, only need to scan once */
- if (mode == 0xFF) {
- if ((cpu_basic_level == -1 || cpu_basic_level >= 3) && (dpmi_flags&1) == 1)
- mode = 32; /* if 32-bit capable DPMI server and 386 or higher, choose 32-bit */
- else
- mode = 16; /* for all else, choose 16-bit */
- }
-
- if (dpmi_entered != 0) {
- if (dpmi_entered != mode) return 0;
- return 1;
- }
-
- if (mode != 16 && mode != 32)
- return 0;
- if (mode == 32 && !(dpmi_flags & 1))
- return 0;
- if (dpmi_entry_point == 0)
- return 0;
- if (!dpmi_private_alloc())
- return 0;
- if (dpmi_private_data_length_paragraphs != 0 && dpmi_private_data_segment == 0)
- return 0;
- if (dpmi_private_data_segment == 0xFFFFU)
- return 0;
-
- dpmi_entered = mode;
- dpmi_enter_core();
- return (dpmi_entered != 0); /* NTS: dpmi_enter_core() will set dpmi_entered back to zero on failure */
-}
-#endif
-
-#if TARGET_MSDOS == 16 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* TODO: Switch into DPMI protected mode, allocate and setup selectors, do memcpy to
- * DOS realmode segment, then return to real mode. When the code is stable,
- * move it into hw/dos/dos.c. The purpose of this code is to allow 16-bit realmode
- * DOS programs to reach into DPMI linear address space, such as the Win 9x
- * kernel area when run under the Win 9x DPMI server. */
-int dpmi_lin2fmemcpy(unsigned char far *dst,uint32_t lsrc,uint32_t sz) {
- if (dpmi_entered == 32)
- return dpmi_lin2fmemcpy_32(dst,lsrc,sz);
- else if (dpmi_entered == 16) {
- _fmemset(dst,0,sz);
- return dpmi_lin2fmemcpy_16(dst,lsrc,sz);
- }
-
- return 0;
-}
-
-int dpmi_lin2fmemcpy_init() {
- probe_dpmi();
- if (!dpmi_present)
- return 0;
- if (!dpmi_enter(DPMI_ENTER_AUTO))
- return 0;
-
- return 1;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-const char *windows_emulation_str(uint8_t e) {
- switch (e) {
- case WINEMU_NONE: return "None";
- case WINEMU_WINE: return "WINE (Wine Is Not an Emulator)";
- default: break;
- }
-
- return "?";
-}
-
-const char *dos_flavor_str(uint8_t f) {
- switch (f) {
- case DOS_FLAVOR_NONE: return "None";
- case DOS_FLAVOR_MSDOS: return "MS-DOS";
- case DOS_FLAVOR_FREEDOS: return "FreeDOS";
- }
-
- return "?";
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && defined(WIN386) /* Watcom Win386 does NOT translate LPARAM for us */
-void far *win386_alt_winnt_MapAliasToFlat(DWORD farptr) {
- /* FIXME: This only works by converting a 16:16 pointer directly to 16:32.
- * It works perfectly fine in QEMU and DOSBox, but I seem to remember something
- * about the x86 architecture and possible ways you can screw up using 16-bit
- * data segments with 32-bit code. Are those rumors true? Am I going to someday
- * load up Windows 3.1/95 on an ancient PC and find out this code crashes
- * horribly or has random problems?
- *
- * We need this alternate path for Windows NT/2000/XP/Vista/7 because NTVDM.EXE
- * grants Watcom386 a limited ~2GB limit for the flat data segment (usually
- * 0x7B000000 or something like that) instead of the full 4GB limit the 3.x/9x/ME
- * kernels usually grant. This matters because without the full 4GB limit we can't
- * count on overflow/rollover to reach below our data segment base. Watcom386's
- * MapAliasToFlat() unfortunately assumes just that. If we were to blindly rely
- * on it, then we would work just fine under 3.x/9x/ME but crash under
- * NT/2000/XP/Vista/7 the minute we need to access below our data segment (such as,
- * when handling the WM_GETMINMAXINFO message the LPARAM far pointer usually
- * points somewhere into NTVDM.EXE's DOS memory area when we're usually located
- * at the 2MB mark or so) */
- return MK_FP(farptr>>16,farptr&0xFFFF);
-}
-
-void far *win386_help_MapAliasToFlat(DWORD farptr) {
- if (windows_mode == WINDOWS_NT)
- return win386_alt_winnt_MapAliasToFlat(farptr);
-
- return (void far*)MapAliasToFlat(farptr); /* MapAliasToFlat() returns near pointer, convert to far! */
-}
-#endif
-
+++ /dev/null
-/* dosntast.c
- *
- * Windows NT VDD driver, dynamically loaded by code that needs it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * This driver when loaded allows the DOS program to call Windows NT APIs
- * such as version information or to use the WINMM WAVE API instead of
- * NTVDM.EXE's shitty Sound Blaster emulation.
- */
-
-/* This is a Windows NT VDD driver */
-#define NTVDM_VDD_DRIVER
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-#include <i86.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <windows/ntvdm/ntvdmlib.h>
-#include <windows/ntvdm/ntvdmvdd.h>
-
-#define DEBUG
-
-/* this is a DLL for Win32 */
-#if TARGET_MSDOS == 16 || !defined(TARGET_WINDOWS)
-# error this is a DLL for Win32 only
-#endif
-
-static HMODULE this_vdd = 0;
-
-/* If the DOS portion of this code calls NTVDM.EXE to load the same DLL again, NTVDM.EXE
- * will do it, and allocate another handle. We'd rather not waste handles, so we leave
- * a "mark" in the BIOS data area for the DOS program to find and know whether we're
- * already loaded, and what handle to use. */
-static unsigned int vm_marked = 0;
-
-/* since 32-bit DOS builds must thunk to 16-bit mode to make calls, we use "fake" I/O
- * ports to control other aspects such as sound output to make it easier for the DOS
- * portion's interrupt controller to do it's job. But we never assume a fixed I/O port
- * base because, who knows, the user's NTVDM environment may have special VDD drivers
- * loaded. */
-static uint16_t vm_io_base = 0;
-#define VM_IO_PORTS 0x20
-
-/* +0x00 (WORD) W/O Function select. */
-/* +0x01 (WORD) W/O Sub-function select. */
-
-/* Interrupt handlers may use these, to save the current state and use the interface themselves
- * before restoring the interface for the code they interrupted.
- *
- * The idea being the DOS program should not have to CLI/STI all the time to avoid conflicts with their
- * own interrupt handlers. */
-
-/* +0x00 (INSB) R/O Read current function/subfunction selection [24 bytes] */
-/* +0x00 (OUTSB) W/O Write current function/subfunction selection [24 bytes] */
-
-#pragma pack(push,1)
-typedef struct {
- uint16_t function; /* +0x00 */
- uint16_t subfunction; /* +0x02 */
- uint16_t __reserved__1; /* +0x04 */
- uint16_t __reserved__2; /* +0x06 */
- uint16_t __reserved__3; /* +0x08 */
- uint16_t __reserved__4; /* +0x0A */
- uint16_t __reserved__5; /* +0x0C */
- uint16_t __reserved__6; /* +0x0E */
- uint16_t __reserved__7; /* +0x10 */
- uint16_t __reserved__8; /* +0x12 */
- uint16_t __reserved__9; /* +0x14 */
- uint16_t __reserved__A; /* +0x16 */
-} IOIF_STATE;
-
-typedef struct {
- WORD (*iop)(WORD param0);
- void (*insb)(BYTE *data,WORD count);
- void (*insw)(WORD *data,WORD count);
- void (*outsb)(BYTE *data,WORD count);
- void (*outsw)(WORD *data,WORD count);
-} IOIF_COMMAND;
-#pragma pack(pop)
-
-/* IO interface state */
-IOIF_STATE io_if={0};
-IOIF_COMMAND* io_if_command=NULL; /* what to do on command */
-
-/* What the fucking hell Watcom?
- * This function obviously never gets called, yet if I don't have it here
- * your linker suddenly decides the standard C libray doesn't exist? What the fuck? */
-BOOL WINAPI DllMain(HINSTANCE hInstance,DWORD fdwReason,LPVOID lpvReserved) {
- /* FIXME: If Watcom demands this function, then why the fuck isn't it getting called on DLL load?
- * What the fuck Open Watcom?!? */
- if (fdwReason == DLL_PROCESS_ATTACH) {
- this_vdd = hInstance;
- }
-
- return TRUE;
-}
-
-/* DOSNTAST_FUNCTION_GENERAL------------------------------------------------------------ */
-static void ioif_function_general_messagebox_outsb(BYTE *data,WORD count) {
- if (io_if.subfunction == DOSNTAST_FUN_GEN_SUB_MESSAGEBOX) {
- /* whatever ASCIIZ string DS:SI points to is passed by NTVDM.EXE to us */
- MessageBoxA(NULL,data,"DOSNTAST.VDD",MB_OK);
- }
-}
-
-static IOIF_COMMAND ioif_command_general_messagebox = {
- /* If only Watcom C/C++ supported GCC's .name = value structure definition style,
- * like what they do in the Linux kernel, we could make this a lot more obvious */
- NULL, /* iop */
- NULL, /* insb */
- NULL, /* insw */
- ioif_function_general_messagebox_outsb, /* outsb */
- NULL /* outsw */
-};
-
-/* this is called when Function == general and selection changes */
-static void ioif_function_general__SELECT() {
- switch (io_if.subfunction) {
- case DOSNTAST_FUN_GEN_SUB_MESSAGEBOX:
- io_if_command = &ioif_command_general_messagebox;
- break;
- default:
- io_if_command = NULL;
- break;
- }
-}
-/* DOSNTAST_FUNCTION_WINMM-------------------------------------------------------------- */
-static WORD ioif_function_winmm_waveOutGetNumDevs_iop(WORD param0) {
- return (WORD)waveOutGetNumDevs();
-}
-
-static IOIF_COMMAND ioif_command_winmm_waveOutGetNumDevs = {
- /* If only Watcom C/C++ supported GCC's .name = value structure definition style,
- * like what they do in the Linux kernel, we could make this a lot more obvious */
- ioif_function_winmm_waveOutGetNumDevs_iop,/* iop */
- NULL, /* insb */
- NULL, /* insw */
- NULL, /* outsb */
- NULL /* outsw */
-};
-
-static void ioif_function_winmm_waveOutOpen_outsb(BYTE *p,WORD count) {
- /* in: EAX = uDeviceID
- * EBX = dwCallbackInstance
- * DS:ESI = pwfx (WAVEFORMATEX*)
- * out: EAX = handle (or 0xFFFFFFFF if error)
- * EBX = error */
- /* TODO */
- setEAX(0xFFFFFFFF);
- setEBX(0xFFFFFFFF);
-}
-
-static IOIF_COMMAND ioif_command_winmm_waveOutOpen = {
- NULL, /* iop */
- NULL, /* insb */
- NULL, /* insw */
- ioif_function_winmm_waveOutOpen_outsb, /* outsb */
- NULL /* outsw */
-};
-
-static void ioif_function_winmm_waveOutGetDevCaps_insb(BYTE *p,WORD count) {
- /* EAX = uDeviceID
- * EBX = cbwoc (sizeof of WAVEOUTCAPS) */
- setEAX(waveOutGetDevCaps(getEAX(),(WAVEOUTCAPS*)p,getEBX()));
-}
-
-static IOIF_COMMAND ioif_command_winmm_waveOutGetDevCaps = {
- NULL, /* iop */
- ioif_function_winmm_waveOutGetDevCaps_insb,/* insb */
- NULL, /* insw */
- NULL, /* outsb */
- NULL /* outsw */
-};
-
-/* this is called when Function == general and selection changes */
-static void ioif_function_winmm__SELECT() {
- switch (io_if.subfunction) {
- case DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs:
- io_if_command = &ioif_command_winmm_waveOutGetNumDevs;
- break;
- case DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps:
- io_if_command = &ioif_command_winmm_waveOutGetDevCaps;
- break;
- case DOSNTAST_FUN_WINMM_SUB_waveOutOpen:
- io_if_command = &ioif_command_winmm_waveOutOpen;
- break;
- default:
- io_if_command = NULL;
- break;
- }
-}
-/* ------------------------------------------------------------------------------------- */
-void ioif_function__SELECT() {
- switch (io_if.function) {
- case DOSNTAST_FUNCTION_GENERAL:
- ioif_function_general__SELECT();
- break;
- case DOSNTAST_FUNCTION_WINMM:
- ioif_function_winmm__SELECT();
- break;
- default:
- io_if_command = NULL;
- }
-}
-
-WORD ioif_command(WORD param0) {
- if (io_if_command != NULL && io_if_command->iop != NULL)
- return io_if_command->iop(param0);
-
- return 0xFFFFU;
-}
-
-void ioif_command_insb(BYTE *data,WORD count) {
- if (io_if_command != NULL && io_if_command->insb != NULL)
- io_if_command->insb(data,count);
-}
-
-void ioif_command_insw(WORD *data,WORD count) {
- if (io_if_command != NULL && io_if_command->insw != NULL)
- io_if_command->insw(data,count);
-}
-
-void ioif_command_outsb(BYTE *data,WORD count) {
- if (io_if_command != NULL && io_if_command->outsb != NULL)
- io_if_command->outsb(data,count);
-}
-
-void ioif_command_outsw(WORD *data,WORD count) {
- if (io_if_command != NULL && io_if_command->outsw != NULL)
- io_if_command->outsw(data,count);
-}
-
-void save_ioif_state(IOIF_STATE *data,WORD count) {
- if (count < sizeof(IOIF_STATE)) return;
- *data = io_if;
-}
-
-void restore_ioif_state(IOIF_STATE *data,WORD count) {
- if (count < sizeof(IOIF_STATE)) return;
- io_if = *data;
- ioif_function__SELECT();
-}
-
-void ioif_function_select(WORD f) {
- /* setting the function resets subfunction to zero */
- io_if.function = f;
- io_if.subfunction = 0;
- ioif_function__SELECT();
-}
-
-void ioif_subfunction_select(WORD f) {
- io_if.subfunction = f;
- ioif_function__SELECT();
-}
-
-/* when a DOS program does REP OUTSW, NTVDM.EXE provides the translated DS:SI for us.
- * Nice. Except... when done from a 32-bit DOS program, it only translates DS:SI for us.
- * Not very good when our DOS code uses *DS:ESI* as a flat 32-bit program!
- *
- * Speaking of which Microsoft why the hell isn't there a function to tell if the DS
- * segment is 16-bit or 32-bit?!?
- *
- * NTS: This code assumes x86 32-bit NTVDM.EXE behavior where DOS memory is mapped to
- * the 0x00000-0xFFFFF area within the NTVDM process. */
-BYTE *NTVDM_DS_ESI_correct(BYTE *p) {
- /* if protected mode, replace the pointer given with a proper pointer to DS:ESI */
- if (getMSW() & 1) {
- /* NTS: x86 behavior: VdmMapFlat() just returns a pointer. There's an
- * "unmap" function but it's a stub. We take advantage of that.
- * No punishment for "mapping" without "unmapping" */
- return (BYTE*)VdmMapFlat(getDS(),getESI(),VDM_PM);
- }
-
- return (BYTE*)p;
-}
-
-BYTE *NTVDM_ES_EDI_correct(BYTE *p) {
- /* if protected mode, replace the pointer given with a proper pointer to DS:ESI */
- if (getMSW() & 1) {
- /* NTS: x86 behavior: VdmMapFlat() just returns a pointer. There's an
- * "unmap" function but it's a stub. We take advantage of that.
- * No punishment for "mapping" without "unmapping" */
- return (BYTE*)VdmMapFlat(getES(),getEDI(),VDM_PM);
- }
-
- return (BYTE*)p;
-}
-
-/* IO handler */
-VOID WINAPI io_inw(WORD iport,WORD *data) {
- if (iport == (vm_io_base+0x00)) /* function select */
- *data = io_if.function;
- else if (iport == (vm_io_base+0x01)) /* subfunction select */
- *data = io_if.subfunction;
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- *data = ioif_command(0xFFFFU);
- else
- *data = 0xFFFF; /* default */
-}
-
-VOID WINAPI io_inb(WORD iport,BYTE *data) {
- {
- WORD w;
- io_inw(iport,&w);
- *data = (BYTE)w; /* default: do whatever our word-size version would and return lower bits */
- }
-}
-
-VOID WINAPI io_insw(WORD iport,WORD *data,WORD count) {
- data = (WORD*)NTVDM_ES_EDI_correct((BYTE*)data);
-
- if (iport == (vm_io_base+0x00))
- save_ioif_state((IOIF_STATE*)data,count*2U); /* FIXME: Microsoft isn't clear: is "count" the count of WORDs? or BYTEs? */
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_insw(data,count);
-}
-
-VOID WINAPI io_insb(WORD iport,BYTE *data,WORD count) {
- data = NTVDM_ES_EDI_correct(data);
-
- if (iport == (vm_io_base+0x00))
- save_ioif_state((IOIF_STATE*)data,count);
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_insb(data,count);
-}
-
-VOID WINAPI io_outw(WORD iport,WORD data) {
- if (iport == (vm_io_base+0x00)) /* function select */
- ioif_function_select(data);
- else if (iport == (vm_io_base+0x01)) /* subfunction select */
- ioif_subfunction_select(data);
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command(data);
-}
-
-VOID WINAPI io_outb(WORD iport,BYTE data) {
- io_outw(iport,data); /* default: pass the byte value up to the word-size callback */
-}
-
-VOID WINAPI io_outsw(WORD iport,WORD *data,WORD count) {
- data = (WORD*)NTVDM_DS_ESI_correct((BYTE*)data);
-
- if (iport == (vm_io_base+0x00))
- restore_ioif_state((IOIF_STATE*)data,count*2U); /* FIXME: Microsoft isn't clear: is "count" the count of WORDs? or BYTEs? */
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_outsw(data,count);
-}
-
-VOID WINAPI io_outsb(WORD iport,BYTE *data,WORD count) {
- data = NTVDM_DS_ESI_correct(data);
-
- if (iport == (vm_io_base+0x00))
- restore_ioif_state((IOIF_STATE*)data,count);
- else if (iport == (vm_io_base+0x02)) /* command (param 0 in data) */
- ioif_command_outsb(data,count);
-}
-
-static void mark_vm() {
- unsigned char *ptr;
- unsigned int i=0xF0/*start at 0x40:0xF0*/,max=0x200;
-
- if (vm_marked) return;
-
- ptr = VdmMapFlat(0x40,0x00,VDM_V86);
- if (ptr == NULL) return;
-
- /* find an empty spot to place our signature. the client is expected
- * to write the handle value next to it */
- while (i < max) {
- if (!memcmp(ptr+i,"\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0",20))
- break;
-
- i++;
- }
-
- if (i < max)
- memcpy(ptr+i,"DOSNTAST.VDD\xFF\xFF\xFF\xFF",16);
-
- VdmUnmapFlat(0x40,0x00,(DWORD)ptr,VDM_V86);
- vm_marked = i+0x400;
-}
-
-static void remove_vm_mark() {
- unsigned char *ptr;
-
- if (vm_marked >= 0x400 && vm_marked <= 0x600) {
- ptr = VdmMapFlat(0x40,0x00,VDM_V86);
- if (ptr == NULL) return;
-
- memset(ptr+vm_marked-0x400,0,16);
-
- VdmUnmapFlat(0x40,0x00,(DWORD)ptr,VDM_V86);
- vm_marked = 0;
- }
-}
-
-static void choose_io_port() {
- VDD_IO_HANDLERS h;
- VDD_IO_PORTRANGE pr;
-
- if (vm_io_base != 0) return;
-
- /* FIXME: Remove this when Watcom C/C++ actually calls up to DllMain on entry point */
- if (this_vdd == NULL)
- this_vdd = GetModuleHandle("DOSNTAST.VDD");
- if (this_vdd == NULL) {
- MessageBox(NULL,"NO!","",MB_OK);
- return;
- }
-
- h.inb_handler = io_inb;
- h.inw_handler = io_inw;
- h.insb_handler = io_insb;
- h.insw_handler = io_insw;
- h.outb_handler = io_outb;
- h.outw_handler = io_outw;
- h.outsb_handler = io_outsb;
- h.outsw_handler = io_outsw;
-
- /* choose an I/O port */
- for (vm_io_base=0x1000;vm_io_base <= 0xF000;vm_io_base += 0x80) {
- pr.First = vm_io_base;
- pr.Last = vm_io_base + VM_IO_PORTS - 1;
-
- if (VDDInstallIOHook(this_vdd,1/*cPortRange*/,&pr,&h)) {
- /* got it */
- break;
- }
- }
-
- if (vm_io_base > 0xF000) {
- /* didn't find any */
- MessageBox(NULL,"Failed","",MB_OK);
- vm_io_base = 0;
- }
-}
-
-static void remove_io_port() {
- VDD_IO_PORTRANGE r;
-
- if (vm_io_base == 0) return;
- r.First = vm_io_base;
- r.Last = vm_io_base + VM_IO_PORTS - 1;
- VDDDeInstallIOHook(this_vdd,1,&r);
- vm_io_base = 0;
-}
-
-/* Microsoft documentation on this "init" routine is lacking */
-__declspec(dllexport) void WINAPI Init() {
- if (!vm_marked) mark_vm();
- if (vm_io_base == 0) choose_io_port();
-}
-
-__declspec(dllexport) void WINAPI Dispatch() {
- uint32_t command;
- char tmp[64];
-
- command = getEBX();
- if (command == DOSNTAST_INIT_REPORT_HANDLE) {
- setEBX(0x55AA55AA);
- setECX(vm_marked);
- }
- else if (command == DOSNTAST_GETVERSIONEX) {
- unsigned char *ptr = NULL;
- uint16_t seg;
- uint32_t ofs;
- uint8_t mode;
-
- seg = getDS();
- ofs = getESI();
- mode = (getCX() == 1) ? VDM_PM : VDM_V86;
-
- ptr = VdmMapFlat(seg,ofs,mode);
- if (ptr != NULL) {
- setEBX(GetVersionEx((OSVERSIONINFO*)ptr));
- VdmUnmapFlat(seg,ofs,(DWORD)ptr,mode);
- }
- }
- else if (command == DOSNTAST_GET_TICK_COUNT) {
- setEBX(GetTickCount());
- }
- /* the DOS program sends this when it's about to unload us.
- * I originally wanted DllMain to do this on PROCESS_DETACH but,
- * for some reason, that function isn't getting called. */
- else if (command == DOSNTAST_GET_IO_PORT) {
- setEBX(0x55AA55AA);
- setEDX(vm_io_base);
- }
- else if (command == DOSNTAST_NOTIFY_UNLOAD) {
- if (vm_io_base) remove_io_port();
- if (vm_marked) remove_vm_mark();
- setEBX(0x55AA55AA);
- }
- else {
- sprintf(tmp,"0x%08lX\n",(unsigned long)command);
- MessageBox(NULL,tmp,"Unknown command",MB_OK);
- }
-}
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define int386 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
-uint8_t ntvdm_dosntast_tried = 0;
-uint16_t ntvdm_dosntast_handle = (~0U);
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-uint16_t ntvdm_dosntast_io_base = 0;
-
-uint16_t ntvdm_dosntast_detect() {
- const char *str = "DOSNTAST.VDD";
- uint16_t str_len = 12;
- uint16_t handle = (~0U);
- unsigned int i,max=0x200;
-#if TARGET_MSDOS == 32
- unsigned char *p = (unsigned char*)0x400;
-#else
- unsigned char FAR *p = (unsigned char FAR*)MK_FP(0x40,0x00);
-#endif
-
- for (i=0;i <= (max-str_len);i++) {
-#if TARGET_MSDOS == 32
- if (memcmp(str,p+i,str_len) == 0)
- handle = *((uint16_t*)(p+i+str_len));
-#else
- if (_fmemcmp(str,p+i,str_len) == 0)
- handle = *((uint16_t FAR*)(p+i+str_len));
-#endif
-
- if (ntvdm_RM_ERR(handle))
- handle = DOSNTAST_HANDLE_UNASSIGNED;
- else
- break;
- }
-
- return handle;
-}
-
-int ntvdm_dosntast_load_vdd() {
- uint32_t t1=0,t2=0;
-
- /* TODO: Right now this works for the current path, or if it's in the Windows system dir.
- * Adopt a strategy where the user can also set an environment variable to say where
- * the DLL is. */
- ntvdm_dosntast_handle = ntvdm_RegisterModule("DOSNTAST.VDD","Init","Dispatch");
- if (ntvdm_RM_ERR(ntvdm_dosntast_handle)) return 0;
-
- /* test out the dispatch call: give the DLL back his handle */
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = DOSNTAST_INIT_REPORT_HANDLE_C;
- rc.ecx = ntvdm_dosntast_handle;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- t1 = rc.ebx;
- t2 = rc.ecx;
- }
-#else
- t1 = ntvdm_dosntast_handle;
- __asm {
- .386p
- push ebx
- push ecx
- mov ebx,DOSNTAST_INIT_REPORT_HANDLE
- mov eax,t1
- mov ecx,eax
- ntvdm_Dispatch_ins_asm_db
- mov t1,ebx
- mov t2,ecx
- pop ecx
- pop ebx
- }
-#endif
-
- if (t1 != 0x55AA55AA || !(t2 >= 0x400 && t2 <= 0x600)) {
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- return 0;
- }
-#if TARGET_MSDOS == 32
- if (memcmp((void*)t2,"DOSNTAST.VDD\xFF\xFF",14)) {
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- return 0;
- }
- *((uint16_t*)(t2+12)) = ntvdm_dosntast_handle;
-#else
- if (_fmemcmp(MK_FP(t2>>4,t2&0xF),"DOSNTAST.VDD\xFF\xFF",14)) {
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- return 0;
- }
- *((uint16_t FAR*)MK_FP((t2+12)>>4,(t2+12)&0xF)) = ntvdm_dosntast_handle;
-#endif
-
- return (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED)?1:0;
-}
-
-unsigned int ntvdm_dosntast_waveOutGetNumDevs() {
- if (ntvdm_dosntast_io_base == 0)
- return 0;
-
- /* FUNCTION */
- outpw(ntvdm_dosntast_io_base+0,DOSNTAST_FUNCTION_WINMM);
- /* SUBFUNCTION */
- outpw(ntvdm_dosntast_io_base+1,DOSNTAST_FUN_WINMM_SUB_waveOutGetNumDevs);
- /* COMMAND */
- return inpw(ntvdm_dosntast_io_base+2);
-}
-
-uint32_t ntvdm_dosntast_waveOutGetDevCaps(uint32_t uDeviceID,WAVEOUTCAPS *pwoc,uint16_t cbwoc) {
- uint32_t retv=0,port;
-
- if (ntvdm_dosntast_io_base == 0)
- return 0;
-
- /* FUNCTION */
- outpw(ntvdm_dosntast_io_base+0,DOSNTAST_FUNCTION_WINMM);
- /* SUBFUNCTION */
- outpw(ntvdm_dosntast_io_base+1,DOSNTAST_FUN_WINMM_SUB_waveOutGetDevCaps);
- /* COMMAND */
- port = ntvdm_dosntast_io_base+2;
-
-#if TARGET_MSDOS == 32
- __asm {
- .386p
- pushad
- /* we trust Watcom left ES == DS */
- mov edx,port
- mov eax,uDeviceID
- movzx ebx,cbwoc
- mov ecx,1
- mov edi,pwoc
- rep insb
- popad
- }
-#elif defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .386p
- push es
- pushad
- mov edx,port
- mov eax,uDeviceID
- movzx ebx,cbwoc
- mov ecx,1
- les di,pwoc
- rep insb
- popad
- pop es
- }
-#else
- __asm {
- .386p
- pushad
- push es
- mov ax,ds
- mov es,ax
- mov edx,port
- mov eax,uDeviceID
- movzx ebx,cbwoc
- mov ecx,1
- mov di,pwoc
- rep insb
- pop es
- popad
- }
-#endif
-
- return retv;
-}
-
-int ntvdm_dosntast_MessageBox(const char *text) {
- uint16_t port;
-
- if (ntvdm_dosntast_io_base == 0)
- return 0;
-
- /* FUNCTION */
- outpw(ntvdm_dosntast_io_base+0,DOSNTAST_FUNCTION_GENERAL);
- /* SUBFUNCTION */
- outpw(ntvdm_dosntast_io_base+1,DOSNTAST_FUN_GEN_SUB_MESSAGEBOX);
- /* COMMAND */
- port = ntvdm_dosntast_io_base+2;
-#if TARGET_MSDOS == 32
- __asm {
- .386p
- push esi
- push ecx
- push edx
- cld
- movzx edx,port
- mov esi,text
- mov ecx,1 /* NTS: duration dosn't matter, our DLL passes DS:SI directly to MessageBoxA */
- rep outsb
- pop edx
- pop ecx
- pop esi
- }
-#elif defined(__LARGE__) || defined(__COMPACT__)
- __asm {
- .386p
- push ds
- push si
- push cx
- push dx
- cld
- mov dx,port
- lds si,text
- mov cx,1
- rep outsb
- pop dx
- pop cx
- pop si
- pop ds
- }
-#else
- __asm {
- .386p
- push si
- push cx
- push dx
- cld
- mov dx,port
- mov si,text
- mov cx,1
- rep outsb
- pop dx
- pop cx
- pop si
- }
-#endif
-
- return 1;
-}
-
-/* initialize the library.
- * if dont_load_dosntast is set, then it will not load the VDD driver but will use the driver if already loaded */
-int ntvdm_dosntast_init() {
- uint32_t t1=0,t2=0;
-
- if (!ntvdm_dosntast_tried) {
- ntvdm_dosntast_tried = 1;
- ntvdm_dosntast_io_base = 0;
-
- if (lib_dos_option.dont_use_dosntast) {
- ntvdm_dosntast_handle = DOSNTAST_HANDLE_UNASSIGNED;
- return 0;
- }
-
- /* It turns out if you request the same DLL again and again, NTVDM.EXE will not return the
- * same handle, it will allocate another one. To avoid exhausting it handles, we first
- * detect whether the DLL is already loaded.
- *
- * We do this by scanning the 0x40-0x50 segments (the BIOS data area) for a signature value
- * placed by the DLL. Following the signature is the handle value. */
- ntvdm_dosntast_handle = ntvdm_dosntast_detect();
- if (ntvdm_dosntast_handle == DOSNTAST_HANDLE_UNASSIGNED && !lib_dos_option.dont_load_dosntast)
- ntvdm_dosntast_load_vdd();
-
- /* we need to know the IO port base */
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
- if (!ntvdm_rm_code_alloc())
- return ntvdm_RM_ERR_NOT_AVAILABLE;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = (uint32_t)(DOSNTAST_GET_IO_PORT_C); /* <= FIXME: "constant out of range" what the fuck are you talking about Watcom? */
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- t1 = rc.ebx;
- t2 = rc.edx;
- }
-#else
- t1 = ntvdm_dosntast_handle;
- __asm {
- .386p
- push ebx
- push edx
- mov ebx,DOSNTAST_GET_IO_PORT
- mov eax,t1
- ntvdm_Dispatch_ins_asm_db
- mov t1,ebx
- mov t2,edx
- pop edx
- pop ebx
- }
-#endif
-
- if (t1 == 0x55AA55AAUL)
- ntvdm_dosntast_io_base = (uint16_t)t2;
- }
- }
-
- return (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED)?1:0;
-}
-
-void ntvdm_dosntast_unload() {
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = DOSNTAST_NOTIFY_UNLOAD_C;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- }
-#else
- {
- const uint16_t h = ntvdm_dosntast_handle;
-
- __asm {
- .386p
- mov ebx,DOSNTAST_NOTIFY_UNLOAD
- mov ax,h
- ntvdm_Dispatch_ins_asm_db
- }
- }
-#endif
-
- ntvdm_UnregisterModule(ntvdm_dosntast_handle);
- ntvdm_dosntast_handle = DOSNTAST_HANDLE_UNASSIGNED;
- }
-}
-
-uint32_t ntvdm_dosntast_GetTickCount() {
- uint32_t retv = 0xFFFFFFFFUL;
-
- if (ntvdm_dosntast_handle == DOSNTAST_HANDLE_UNASSIGNED)
- return 0; /* failed */
- if (!ntvdm_rm_code_alloc())
- return 0;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.ebx = DOSNTAST_GET_TICK_COUNT_C;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- retv = rc.ebx;
- }
-#else
- {
- const uint16_t h = ntvdm_dosntast_handle;
-
- __asm {
- .386p
- push ebx
- mov ebx,DOSNTAST_GET_TICK_COUNT
- mov ax,h
- ntvdm_Dispatch_ins_asm_db
- mov retv,ebx
- pop ebx
- }
- }
-#endif
-
- return retv;
-}
-
-unsigned int ntvdm_dosntast_getversionex(OSVERSIONINFO *ovi) {
- unsigned int retv=0;
-
- if (ntvdm_dosntast_handle == DOSNTAST_HANDLE_UNASSIGNED)
- return 0; /* failed */
- if (!ntvdm_rm_code_alloc())
- return 0;
-
-#if TARGET_MSDOS == 32
- {
- uint16_t myds=0;
- struct dpmi_realmode_call rc={0};
- __asm mov myds,ds
- rc.ebx = DOSNTAST_GETVERSIONEX_C;
- rc.esi = (uint32_t)ovi;
- rc.ecx = 1;
- rc.ds = myds;
- ntvdm_DispatchCall_dpmi(ntvdm_dosntast_handle,&rc);
- retv = rc.ebx;
- }
-#else
- {
- const uint16_t s = FP_SEG(ovi),o = FP_OFF(ovi),h = ntvdm_dosntast_handle;
-
- __asm {
- .386p
- push ds
- push esi
- push ecx
- mov ebx,DOSNTAST_GETVERSIONEX
- xor esi,esi
- mov ax,h
- mov si,s
- mov ds,si
- mov si,o
- xor cx,cx
- ntvdm_Dispatch_ins_asm_db
- mov retv,bx
- pop esi
- pop ebx
- pop ds
- }
- }
-#endif
-
- return retv;
-}
-
-#endif
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NTVDM.EXE DOSNTAST.VDD call support */
-#include <windows/ntvdm/ntvdmlib.h>
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-extern uint8_t ntvdm_dosntast_tried;
-extern uint16_t ntvdm_dosntast_handle;
-#endif
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-extern uint16_t ntvdm_dosntast_io_base;
-
-int ntvdm_dosntast_init();
-void ntvdm_dosntast_unload();
-uint32_t ntvdm_dosntast_GetTickCount();
-int ntvdm_dosntast_MessageBox(const char *text);
-unsigned int ntvdm_dosntast_waveOutGetNumDevs();
-unsigned int ntvdm_dosntast_getversionex(OSVERSIONINFO *ovi);
-uint32_t ntvdm_dosntast_waveOutGetDevCaps(uint32_t uDeviceID,WAVEOUTCAPS *pwoc,uint16_t cbwoc);
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-int dos_parse_psp(uint16_t seg,struct dos_psp_cooked *e) {
- unsigned int i,o=0;
-
-#if TARGET_MSDOS == 32
- e->raw = (unsigned char*)((uint32_t)seg << 4UL);
-#else
- e->raw = (unsigned char FAR*)MK_FP(seg,0);
-#endif
- e->memsize = *((uint16_t FAR*)(e->raw + 0x02));
- e->callpsp = *((uint16_t FAR*)(e->raw + 0x16));
- e->env = *((uint16_t FAR*)(e->raw + 0x2C));
- for (i=0;i < (unsigned char)e->raw[0x80] && e->raw[0x81+i] == ' ';) i++; /* why is there all this whitespace at the start? */
- for (;i < (unsigned char)e->raw[0x80];i++) e->cmd[o++] = e->raw[0x81+i];
- e->cmd[o] = 0;
- return 1;
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2))
-unsigned short smartdrv_version = 0xFFFF;
-int smartdrv_fd = -1;
-#endif
-
-#if (TARGET_MSDOS == 16 || TARGET_MSDOS == 32) && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-int smartdrv_close() {
- if (smartdrv_fd >= 0) {
- close(smartdrv_fd);
- smartdrv_fd = -1;
- }
-
- return 0;
-}
-
-int smartdrv_flush() {
- if (smartdrv_version == 0xFFFF || smartdrv_version == 0)
- return 0;
-
- if (smartdrv_version >= 0x400) { /* SMARTDRV 4.xx and later */
-#if TARGET_MSDOS == 32
- __asm {
- push eax
- push ebx
- mov eax,0x4A10 ; SMARTDRV
- mov ebx,0x0001 ; FLUSH BUFFERS (COMMIT CACHE)
- int 0x2F
- pop ebx
- pop eax
- }
-#else
- __asm {
- push ax
- push bx
- mov ax,0x4A10 ; SMARTDRV
- mov bx,0x0001 ; FLUSH BUFFERS (COMMIT CACHE)
- int 0x2F
- pop bx
- pop ax
- }
-#endif
- }
- else if (smartdrv_version >= 0x300 && smartdrv_version <= 0x3FF) { /* SMARTDRV 3.xx */
- char buffer[0x1];
-#if TARGET_MSDOS == 32
-#else
- char far *bptr = (char far*)buffer;
-#endif
- int rd=0;
-
- if (smartdrv_fd < 0)
- return 0;
-
- buffer[0] = 0; /* flush cache */
-#if TARGET_MSDOS == 32
- /* FIXME: We do not yet have a 32-bit protected mode version.
- * DOS extenders do not appear to translate AX=0x4403 properly */
-#else
- __asm {
- push ax
- push bx
- push cx
- push dx
- push ds
- mov ax,0x4403 ; IOCTL SMARTAAR CACHE CONTROL
- mov bx,smartdrv_fd
- mov cx,0x1 ; 0x01 bytes
- lds dx,word ptr [bptr]
- int 0x21
- jc err1
- mov rd,ax ; CF=0, AX=bytes written
-err1: pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- }
-#endif
-
- if (rd == 0)
- return 0;
- }
-
- return 1;
-}
-
-int smartdrv_detect() {
- unsigned int rvax=0,rvbp=0;
-
- if (smartdrv_version == 0xFFFF) {
- /* Is Microsoft SMARTDRV 4.x or equivalent disk cache present? */
-
-#if TARGET_MSDOS == 32
- __asm {
- push eax
- push ebx
- push ecx
- push edx
- push esi
- push edi
- push ebp
- push ds
- mov eax,0x4A10 ; SMARTDRV 4.xx INSTALLATION CHECK AND HIT RATIOS
- mov ebx,0
- mov ecx,0xEBAB ; "BABE" backwards
- xor ebp,ebp
- int 0x2F ; multiplex (hope your DOS extender supports it properly!)
- pop ds
- mov ebx,ebp ; copy EBP to EBX. Watcom C uses EBP to refer to the stack!
- pop ebp
- mov rvax,eax ; we only care about EAX and EBP(now EBX)
- mov rvbp,ebx
- pop edi
- pop esi
- pop edx
- pop ecx
- pop ebx
- pop eax
- }
-#else
- __asm {
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- mov ax,0x4A10 ; SMARTDRV 4.xx INSTALLATION CHECK AND HIT RATIOS
- mov bx,0
- mov cx,0xEBAB ; "BABE" backwards
- xor bp,bp
- int 0x2F ; multiplex
- pop ds
- mov bx,bp ; copy BP to BX. Watcom C uses BP to refer to the stack!
- pop bp
- mov rvax,ax ; we only care about EAX and EBP(now EBX)
- mov rvbp,bx
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- }
-#endif
-
- if ((rvax&0xFFFF) == 0xBABE && (rvbp&0xFFFF) >= 0x400 && (rvbp&0xFFFF) <= 0x5FF) {
- /* yup. SMARTDRV 4.xx! */
- smartdrv_version = (rvbp&0xFF00) + (((rvbp>>4)&0xF) * 10) + (rvbp&0xF); /* convert BCD to decimal */
- }
-
- if (smartdrv_version == 0xFFFF) {
- char buffer[0x28];
-#if TARGET_MSDOS == 32
-#else
- char far *bptr = (char far*)buffer;
-#endif
- int rd=0;
-
- memset(buffer,0,sizeof(buffer));
-
- /* check for SMARTDRV 3.xx */
- smartdrv_fd = open("SMARTAAR",O_RDONLY);
- if (smartdrv_fd >= 0) {
- /* FIXME: The DOS library should provide a common function to do IOCTL read/write character "control channel" functions */
-#if TARGET_MSDOS == 32
- /* FIXME: We do not yet have a 32-bit protected mode version.
- * DOS extenders do not appear to translate AX=0x4402 properly */
-#else
- __asm {
- push ax
- push bx
- push cx
- push dx
- push ds
- mov ax,0x4402 ; IOCTL SMARTAAR GET CACHE STATUS
- mov bx,smartdrv_fd
- mov cx,0x28 ; 0x28 bytes
- lds dx,word ptr [bptr]
- int 0x21
- jc err1
- mov rd,ax ; CF=0, AX=bytes read
-err1: pop ds
- pop dx
- pop cx
- pop bx
- pop ax
- }
-#endif
-
- /* NTS: Despite reading back 0x28 bytes of data, this IOCTL
- * returns AX=1 for some reason. */
- if (rd > 0 && rd <= 0x28) {
- if (buffer[0] == 1/*write through flag*/ && buffer[15] == 3/*major version number*/) { /* SMARTDRV 3.xx */
- smartdrv_version = ((unsigned short)buffer[15] << 8) + ((unsigned short)buffer[14]);
- }
- else {
- close(smartdrv_fd);
- }
- }
- }
- }
-
- /* didn't find anything. then no SMARTDRV */
- if (smartdrv_version == 0xFFFF)
- smartdrv_version = 0;
- }
-
- return (smartdrv_version != 0);
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-/* as seen in the ROM area: "BIOS: "+NUL+"VirtualBox 4.1.8_OSE" around 0xF000:0x0130 */
-static const char *virtualbox_bios_str = "BIOS: ";
-static const char *virtualbox_vb_str = "VirtualBox ";
-#endif
-
-/* the ROM area doesn't change. so remember our last result */
-#if defined(TARGET_WINDOWS) || defined(TARGET_OS2)
-#else
-static signed char virtualbox_detect_cache = -1;
-#endif
-
-/* unlike DOSBox, VirtualBox's ROM BIOS contains it's version number, which we copy down here */
-char virtualbox_version_str[64]={0};
-
-int detect_virtualbox_emu() {
-#if defined(TARGET_OS2)
- /* TODO: So... how does one read the ROM BIOS area from OS/2? */
- return 0;
-#elif defined(TARGET_WINDOWS)
- /* TODO: I know that from within Windows there are various ways to scan the ROM BIOS area.
- * Windows 1.x and 2.x (if real mode) we can just use MK_FP as we do under DOS, but
- * we have to use alternate means if Windows is in protected mode. Windows 2.x/3.x protected
- * mode (and because of compatibility, Windows 95/98/ME), there are two methods open to us:
- * One is to use selector constants that are hidden away in KRNL386.EXE with names like _A0000,
- * _B0000, etc. They are data selectors that when loaded into the segment registers point to
- * their respective parts of DOS adapter ROM and BIOS ROM. Another way is to use the Win16
- * API to create a data selector that points to the BIOS. Windows 386 Enhanced mode may map
- * additional things over the unused parts of adapter ROM, but experience shows that it never
- * relocates or messes with the VGA BIOS or with the ROM BIOS,
- *
- * My memory is foggy at this point, but I remember that under Windows XP SP2, one of the
- * above Win16 methods still worked even from under the NT kernel.
- *
- * For Win32 applications, if the host OS is Windows 3.1 Win32s or Windows 95/98/ME, we can
- * take advantage of a strange quirk in the way the kernel maps the lower 1MB. For whatever
- * reason, the VGA RAM, adapter ROM, and ROM BIOS areas are left open even for Win32 applications
- * with no protection. Thus, a Win32 programmer can just make a pointer like
- * char *a = (char*)0xA0000 and scribble on legacy VGA RAM to his heart's content (though on
- * modern PCI SVGA hardware the driver probably instructs the card to disable VGA compatible
- * mapping). In fact, this ability to scribble on RAM directly is at the heart of one of Microsoft's
- * earliest and hackiest "Direct Draw" interfaces known as "DISPDIB.DLL", a not-to-well documented
- * library responsible for those Windows 3.1 multimedia apps and games that were somehow able to
- * run full-screen 320x200x256 color VGA despite being Windows GDI-based apps. Ever wonder how the
- * MCI AVI player was able to go full-screen when DirectX and WinG were not invented yet? Now you
- * know :)
- *
- * There are some VFW codecs out there as well, that also like to abuse DISPDIB.DLL for "fullscreen"
- * modes. One good example is the old "Motion Pixels" codec, that when asked to go fullscreen,
- * uses DISPDIB.DLL and direct VGA I/O port trickery to effectively set up a 320x480 256-color mode,
- * which it then draws on "fake hicolor" style to display the video (though a bit dim since you're
- * sort of watching a video through a dithered mesh, but...)
- *
- * In case you were probably wondering, no, Windows NT doesn't allow Win32 applications the same
- * privilege. Win32 apps writing to 0xA0000 would page fault and crash. Curiously enough though,
- * NTVDM.EXE does seem to open up the 0xA0000-0xFFFFF memory area to Win16 applications if they
- * use the right selectors and API calls. */
- return 0;
-#else
- int i,j;
-# if TARGET_MSDOS == 32
- const char *scan;
-# else
- const char far *scan;
-# endif
-
- probe_dos();
- if (virtualbox_detect_cache >= 0)
- return (int)virtualbox_detect_cache;
-
- virtualbox_detect_cache=0;
-
-# if TARGET_MSDOS == 32
- if (dos_flavor == DOS_FLAVOR_FREEDOS) {
- /* FIXME: I have no idea why but FreeDOS 1.0 has a strange conflict with DOS32a where if this code
- * tries to read the ROM BIOS it causes a GPF and crashes (or sometimes runs off into the
- * weeds leaving a little garbage on the screen). DOS32a's register dump seems to imply that
- * at one point our segment limits were suddenly limited to 1MB (0xFFFFF). I have no clue
- * what the hell is triggering it, but I know from testing we can avoid that crash by not
- * scanning. */
- if (freedos_kernel_version == 0x000024UL) /* 0.0.36 */
- return (virtualbox_detect_cache=0);
- }
-# endif
-
- /* test #1: the ROM BIOS region just prior to 0xF0000 is all zeros.
- * NTS: VirtualBox 4.1.8 also seems to have the ACPI tables at 0xE000:0x0000 */
-# if TARGET_MSDOS == 32
- scan = (const char*)0xEFF00;
-# else
- scan = (const char far*)MK_FP(0xE000,0xFF00);
-# endif
- for (i=0;i < 256;i++) {
- if (scan[i] != 0)
- return virtualbox_detect_cache;
- }
-
- /* test #2: somewhere within the first 4KB, are the strings "BIOS: " and
- * "VirtualBox " side by side separated by a NUL. The "VirtualBox" string is
- * followed by the version number, and "_OSE" if the open source version. */
-# if TARGET_MSDOS == 32
- scan = (const char*)0xF0000;
-# else
- scan = (const char far*)MK_FP(0xF000,0x0000);
-# endif
- for (i=0,j=0;i < 4096;i++) {
- if (scan[i] == virtualbox_bios_str[j]) {
- j++;
- if (virtualbox_bios_str[j] == 0 && scan[i+1] == 0) {
- /* good. found it. stop there. */
- i++;
- break;
- }
- }
- else {
- j=0;
- }
- }
- /* if we didn't find the first string, then give up */
- if (i >= 4096) return virtualbox_detect_cache;
-
- /* make sure the next string is "VirtualBox " */
- for (/*do not reset 'i'*/j=0;i < 4096;i++) {
- if (scan[i] == virtualbox_vb_str[j]) {
- j++;
- if (virtualbox_vb_str[j] == 0) {
- /* good. found it. stop there. */
- virtualbox_detect_cache = 1;
- break;
- }
- }
- else {
- j=0;
- }
- }
- if (i >= 4096) return virtualbox_detect_cache;
-
- /* 'i' now points at the version part of the string. copy it down */
- while (i < 4096 && scan[i] == ' ') i++;
- for (j=0;j < (sizeof(virtualbox_version_str)-1) && i < 4096;)
- virtualbox_version_str[j++] = scan[i++];
- virtualbox_version_str[j] = 0;
-
- return virtualbox_detect_cache;
-#endif
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-unsigned char vcpi_probed = 0;
-unsigned char vcpi_present = 0;
-unsigned char vcpi_major_version,vcpi_minor_version;
-
-/* NTS: According to the VCPI specification this call is only supposed to report
- * the physical memory address for anything below the 1MB boundary. And so
- * far EMM386.EXE strictly adheres to that rule by not reporting success for
- * addresses >= 1MB. The 32-bit limitation is a result of the VCPI system
- * call, since the physical address is returned in EDX. */
-uint32_t dos_linear_to_phys_vcpi(uint32_t pn) {
- uint32_t r=0xFFFFFFFFUL;
-
- __asm {
- .586p
- mov ax,0xDE06
- mov ecx,pn
- int 67h
- or ah,ah
- jnz err1 ; if AH == 0 then EDX = page phys addr
- mov r,edx
-err1:
- }
-
- return r;
-}
-
-#if !defined(TARGET_WINDOWS)
-static int int67_null() {
- uint32_t ptr;
-
-#if TARGET_MSDOS == 32
- ptr = ((uint32_t*)0)[0x67];
-#else
- ptr = *((uint32_t far*)MK_FP(0,0x67*4));;
-#endif
-
- return (ptr == 0);
-}
-#endif
-
-int probe_vcpi() {
-#if defined(TARGET_WINDOWS)
- if (!vcpi_probed) {
- /* NTS: Whoever said Windows 3.0 used VCPI at it's core, is a liar */
- vcpi_probed = 1;
- vcpi_present = 0;
- }
-#else
-/* =================== MSDOS ================== */
- unsigned char err=0xFF;
-
- if (!vcpi_probed) {
- vcpi_probed = 1;
-
- /* if virtual 8086 mode isn't active, then VCPI isn't there */
- /* FIXME: What about cases where VCPI might be there, but is inactive (such as: EMM386.EXE resident but disabled) */
- if (!cpu_v86_active)
- return 0;
-
- /* NOTE: VCPI can be present whether we're 16-bit real mode or
- * 32-bit protected mode. Unlike DPMI we cannot assume it's
- * present just because we're 32-bit. */
-
- /* Do not call INT 67h if the vector is uninitialized */
- if (int67_null())
- return 0;
-
- /* Do not attempt to probe for VCPI if Windows 3.1/95/98/ME
- * is running. Windows 9x blocks VCPI and if called, interrupts
- * our execution to inform the user that the program should be
- * run in DOS mode. */
- detect_windows();
- if (windows_mode != WINDOWS_NONE)
- return 0;
-
- /* NTS: we load DS for each var because Watcom might put it in
- * another data segment, especially in Large memory model.
- * failure to account for this was the cause of mysterious
- * hangs and crashes. */
- __asm {
- ; NTS: Save DS and ES because Microsoft EMM386.EXE
- ; appears to change their contents.
- push ds
- push es
- mov ax,0xDE00
- int 67h
- mov err,ah
-
- mov ax,seg vcpi_major_version
- mov ds,ax
- mov vcpi_major_version,bh
-
- mov ax,seg vcpi_minor_version
- mov ds,ax
- mov vcpi_minor_version,bl
-
- pop es
- pop ds
- }
-
- if (err != 0)
- return 0;
-
- vcpi_present = 1;
- }
-#endif
-
- return vcpi_present;
-}
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* DEBUG: Flush out calls that aren't there */
-#ifdef TARGET_OS2
-# define int86 ___EVIL___
-# define int386 ___EVIL___
-# define ntvdm_RegisterModule ___EVIL___
-# define ntvdm_UnregisterModule ___EVIL___
-# define _dos_getvect ___EVIL___
-# define _dos_setvect ___EVIL___
-#endif
-
-const char *windows_version_method = NULL;
-
-/* return value:
- * 0 = not running under Windows
- * 1 = running under Windows */
-const char *windows_emulation_comment_str = NULL;
-uint8_t windows_emulation = 0;
-uint16_t windows_version = 0; /* NOTE: 0 for Windows NT */
-uint8_t windows_mode = 0;
-uint8_t windows_init = 0;
-
-const char *windows_mode_strs[WINDOWS_MAX] = {
- "None",
- "Real",
- "Standard",
- "Enhanced",
- "NT",
- "OS/2"
-};
-
-/* TESTING (whether or not it correctly detects the presence of Windows):
- * Note that in some columns the API returns insufficient information and the
- * API has to use it's best guess on the correct value, which might be
- * inaccurate or wrong (marked: GUESSES).
- *
- * For Windows NT/2000/XP/Vista/7 tests, the code does not have any way of
- * knowing (yet) which version of the NT kernel is involved, so the best
- * it can offer is "I am running under NT" (marked as ONLY NT)
- *
- * OS, shell, configuration & mode Detects Correct mode Correct version
- * Microsoft Windows 3.0 (DOSBox 0.74)
- * 386 Enhanced Mode YES YES YES
- * 286 Standard Mode YES GUESSES YES
- * 8086 Real Mode YES GUESSES YES
- * Microsoft Windows 3.1 (DOSBox 0.74)
- * 386 Enhanced Mode YES YES YES
- * 286 Standard Mode YES YES YES
- * Microsoft Windows 3.11 (DOSBox 0.74)
- * 386 Enhanced Mode YES YES YES*
- * 286 Standard Mode YES YES YES*
- * * = Despite being v3.11 it still reports itself as v3.1
- * Microsoft Windows 95 (4.00.950) (DOS 7.00) (Qemu)
- * Normal YES YES* YES (4.0)
- * Safe mode YES YES* YES (4.0)
- * Prevent DOS apps detecting Windows NO - -
- * * = Reports self as "enhanced mode" which is really the only mode supported
- * Microsoft Windows 95 OSR2.5 (4.00.950 C) (DOS 7.10) (Qemu)
- * Normal YES YES YES (4.0)
- * Safe mode YES YES YES (4.0)
- * Microsoft Windows 95 SP1 (4.00.950a) (DOS 7.00) (Qemu)
- * Normal YES YES YES (4.0)
- * Safe mode YES YES YES (4.0)
- * Microsoft Windows 98 (4.10.1998) (DOS 7.10) (Qemu)
- * Normal YES YES YES (4.10)
- * Safe mode YES YES YES (4.10)
- * Microsoft Windows 98 SE (4.10.2222 A) (DOS 7.10) (Qemu)
- * Normal YES YES YES (4.10)
- * Safe mode YES YES YES (4.10)
- * Microsoft Windows ME (4.90.3000) (DOS 8.00) (Qemu)
- * Normal YES YES YES (4.90)
- * Safe mode YES YES YES (4.90)
- * Microsoft Windows 2000 Professional (5.00.2195) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional SP1 (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional SP2 (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
- * Microsoft Windows XP Professional SP3 (5.1.2600) (VirtualBox)
- * Normal YES N/A ONLY NT
-*/
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-/* it's nice to know if we're running under WINE (and therefore possibly Linux)
- * as opposed to real Windows, so that we can adjust our techniques accordingly.
- * I doubt for example that WINE would support Windows NT's NTVDM.EXE BOP codes,
- * or that our Win9x compatible VxD enumeration would know not to try enumerating
- * drivers. */
-void win32_probe_for_wine() { /* Probing for WINE from the Win32 layer */
- HMODULE ntdll;
-
- ntdll = LoadLibrary("NTDLL.DLL");
- if (ntdll) {
- const char *(__stdcall *p)() = (const char *(__stdcall *)())GetProcAddress(ntdll,"wine_get_version");
- if (p != NULL) {
- windows_emulation = WINEMU_WINE;
- windows_emulation_comment_str = p(); /* and the function apparently returns a string */
- }
- FreeLibrary(ntdll);
- }
-}
-#elif defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-void win16_probe_for_wine() { /* Probing for WINE from the Win16 layer */
- DWORD callw,retv;
-
- if (!genthunk32_init()) return;
- if (genthunk32w_ntdll == 0) return;
-
- callw = __GetProcAddress32W(genthunk32w_ntdll,"wine_get_version");
- if (callw == 0) return;
-
- retv = __CallProcEx32W(CPEX_DEST_STDCALL/*nothing to convert*/,0/*0 param*/,callw);
- if (retv == 0) return;
-
- windows_emulation = WINEMU_WINE;
- {
- /* NTS: We assume that WINE, just like real Windows, will not move or relocate
- * NTDLL.DLL and will not move the string it just returned. */
- /* TODO: You need a function the host program can call to free the selector
- * you allocated here, in case it wants to reclaim resources */
- uint16_t sel;
- uint16_t myds=0;
- __asm mov myds,ds
- sel = AllocSelector(myds);
- if (sel != 0) {
- /* the selector is directed at the string, then retained in this
- * code as a direct FAR pointer to WINE's version string */
- SetSelectorBase(sel,retv);
- SetSelectorLimit(sel,0xFFF); /* WINE's version string is rarely longer than 14 chars */
- windows_emulation_comment_str = MK_FP(sel,0);
- }
- }
-}
-#endif
-
-int detect_windows() {
-#if defined(TARGET_WINDOWS)
-# if TARGET_MSDOS == 32
-# ifdef WIN386
- /* Windows 3.0/3.1 with Win386 */
- if (!windows_init) {
- DWORD raw;
-
- windows_emulation = 0;
- windows_init = 1;
- windows_mode = WINDOWS_ENHANCED; /* most likely scenario is Windows 3.1 386 enhanced mode */
-
- raw = GetVersion();
- windows_version_method = "GetVersion";
- windows_version = (LOBYTE(LOWORD(raw)) << 8) | HIBYTE(LOWORD(raw));
- /* NTS: Microsoft documents GetVersion() as leaving bit 31 unset for NT, bit 31 set for Win32s and Win 9x/ME.
- * But that's not what the Win16 version of the function does! */
-
- if (dos_version == 0) probe_dos();
-
- /* Windows 3.1/9x/ME */
- raw = GetWinFlags();
- if (raw & WF_PMODE) {
- if (raw & WF_ENHANCED)
- windows_mode = WINDOWS_ENHANCED;
- else/* if (raw & WF_STANDARD)*/
- windows_mode = WINDOWS_STANDARD;
- }
- else {
- windows_mode = WINDOWS_REAL;
- }
-
- /* NTS: All 32-bit Windows systems since Windows NT 3.51 and Windows 95 return
- * major=3 minor=95 when Win16 applications query the version number. The only
- * exception to that rule is Windows NT 3.1, which returns major=3 minor=10,
- * the same version number returned by Windows 3.1. */
- if (windows_mode == WINDOWS_ENHANCED &&
- (dos_version >= 0x510 && dos_version <= 0x57f)/* MS-DOS v5.50 */ &&
- (windows_version == 0x035F /* Windows NT 4/2000/XP/Vista/7/8 */ ||
- windows_version == 0x030A /* Windows NT 3.1/3.5x */)) {
- /* if the real DOS version is 5.50 then we're under NT */
- windows_mode = WINDOWS_NT;
- }
-
- switch (dos_version>>8) {
- case 10: /* OS/2 1.x */
- case 20: /* OS/2 2.x (low=0), and OS/2 Warp 3 (low=30), and OS/2 Warp 4 (low=40) */
- windows_version_method = "Deduce from DOS version";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- break;
- };
- }
-# elif TARGET_WINDOWS >= 40 || defined(WINNT)
- /* Windows 95/98/ME/XP/2000/NT/etc. and Windows NT builds: We don't need to do anything.
- * The fact we're running means Windows is present */
- /* TODO: Clarify which Windows: Are we running under NT? or 9X/ME? What version? */
- if (!windows_init) {
- OSVERSIONINFO ovi;
-
- windows_emulation = 0;
- windows_init = 1;
- memset(&ovi,0,sizeof(ovi));
- ovi.dwOSVersionInfoSize = sizeof(ovi);
- GetVersionEx(&ovi);
-
- windows_version_method = "GetVersionEx";
- windows_version = (ovi.dwMajorVersion << 8) | ovi.dwMinorVersion;
- if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
- windows_mode = WINDOWS_NT;
- else
- windows_mode = WINDOWS_ENHANCED; /* Windows 3.1 Win32s, or Windows 95/98/ME */
-
- win32_probe_for_wine();
- }
-# elif TARGET_WINDOWS == 31
- /* Windows 3.1 with Win32s target build. Note that such programs run in the Win32 layer on Win95/98/ME/NT/2000/etc. */
- /* TODO: Clarify which Windows, using the limited set of functions available under Win32s, or perhaps using GetProcAddress
- * to use the later GetVersionEx() functions offered by Win95/98/NT/etc. */
- if (!windows_init) {
- DWORD raw;
-
- windows_emulation = 0;
- windows_init = 1;
- windows_mode = WINDOWS_ENHANCED; /* Assume Windows 3.1 386 Enhanced Mode. This 32-bit app couldn't run otherwise */
-
- raw = GetVersion();
- windows_version_method = "GetVersion";
- windows_version = (LOBYTE(LOWORD(raw)) << 8) | HIBYTE(LOWORD(raw));
- if (!(raw & 0x80000000UL)) { /* FIXME: Does this actually work? */
- /* Windows NT/2000/XP/etc */
- windows_mode = WINDOWS_NT;
- }
-
- /* TODO: GetProcAddress() GetVersionEx() and get the REAL version number from Windows */
-
- win32_probe_for_wine();
- }
-# else
-# error Unknown 32-bit Windows variant
-# endif
-# elif TARGET_MSDOS == 16
-# if TARGET_WINDOWS >= 30
- /* Windows 3.0/3.1, what we then want to know is what mode we're running under: Real? Standard? Enhanced?
- * The API function GetWinFlags() only exists in 3.0 and higher, it doesn't exist under 2.x */
- /* TODO */
- if (!windows_init) {
- DWORD raw;
-
- windows_emulation = 0;
- windows_init = 1;
- windows_mode = WINDOWS_ENHANCED; /* most likely scenario is Windows 3.1 386 enhanced mode */
-
- raw = GetVersion();
- windows_version_method = "GetVersion";
- windows_version = (LOBYTE(LOWORD(raw)) << 8) | HIBYTE(LOWORD(raw));
- /* NTS: Microsoft documents GetVersion() as leaving bit 31 unset for NT, bit 31 set for Win32s and Win 9x/ME.
- * But that's not what the Win16 version of the function does! */
-
- if (dos_version == 0) probe_dos();
-
- /* Windows 3.1/9x/ME */
- raw = GetWinFlags();
- if (raw & WF_PMODE) {
- if (raw & WF_ENHANCED)
- windows_mode = WINDOWS_ENHANCED;
- else/* if (raw & WF_STANDARD)*/
- windows_mode = WINDOWS_STANDARD;
- }
- else {
- windows_mode = WINDOWS_REAL;
- }
-
- /* NTS: All 32-bit Windows systems since Windows NT 3.51 and Windows 95 return
- * major=3 minor=95 when Win16 applications query the version number. The only
- * exception to that rule is Windows NT 3.1, which returns major=3 minor=10,
- * the same version number returned by Windows 3.1. */
- if (windows_mode == WINDOWS_ENHANCED &&
- (dos_version >= 0x510 && dos_version <= 0x57f)/* MS-DOS v5.50 */ &&
- (windows_version == 0x035F /* Windows NT 4/2000/XP/Vista/7/8 */ ||
- windows_version == 0x030A /* Windows NT 3.1/3.5x */)) {
- /* if the real DOS version is 5.50 then we're under NT */
- windows_mode = WINDOWS_NT;
- }
-
- switch (dos_version>>8) {
- case 10: /* OS/2 1.x */
- case 20: /* OS/2 2.x (low=0), and OS/2 Warp 3 (low=30), and OS/2 Warp 4 (low=40) */
- windows_version_method = "Deduce from DOS version";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- break;
- };
-
- /* If we're running under Windows 9x/ME or Windows NT/2000 we can thunk our way into
- * the Win32 world and call various functions to get a more accurate picture of the
- * Windows system we are running on */
- /* NTS: Under Windows NT 3.51 or later this technique is the only way to get the
- * true system version number. The Win16 GetVersion() will always return
- * some backwards compatible version number except for NT 3.1:
- *
- * Win16 Win32
- * +==========================
- * NT 3.1 | 3.1 3.1
- * NT 3.51 | 3.1 3.51
- * NT 4.0 | 3.95 4.0
- * 2000 | 3.95 5.0
- * XP | 3.95 5.1
- * Vista | 3.95 6.0
- * 7 | 3.95 6.1
- * 8 | 3.95 6.2
- *
- */
- if (genthunk32_init() && genthunk32w_kernel32_GetVersionEx != 0) {
- OSVERSIONINFO osv;
-
- memset(&osv,0,sizeof(osv));
- osv.dwOSVersionInfoSize = sizeof(osv);
- if (__CallProcEx32W(CPEX_DEST_STDCALL | 1/* convert param 1*/,
- 1/*1 param*/,genthunk32w_kernel32_GetVersionEx,
- (DWORD)((void far*)(&osv))) != 0UL) {
- windows_version_method = "GetVersionEx [16->32 CallProcEx32W]";
- windows_version = (osv.dwMajorVersion << 8) | osv.dwMinorVersion;
- if (osv.dwPlatformId == 2/*VER_PLATFORM_WIN32_NT*/)
- windows_mode = WINDOWS_NT;
- else
- windows_mode = WINDOWS_ENHANCED;
- }
- }
-
- win16_probe_for_wine();
- }
-# elif TARGET_WINDOWS >= 20
- /* Windows 2.x or higher. Use GetProcAddress() to locate GetWinFlags() if possible, else assume real mode
- * and find some other way to detect if we're running under the 286 or 386 enhanced versions of Windows 2.11 */
- /* TODO */
- if (!windows_init) {
- windows_init = 1;
- windows_version = 0x200;
- windows_mode = WINDOWS_REAL;
- windows_version_method = "Assuming";
- }
-# else
- /* Windows 1.x. No GetProcAddress, no GetWinFlags. Assume Real mode. */
- /* TODO: How exactly DO you get the Windows version in 1.1? */
- if (!windows_init) {
- windows_init = 1;
- windows_version = 0x101; /* Assume 1.1 */
- windows_mode = WINDOWS_REAL;
- windows_version_method = "Assuming";
- }
-# endif
-# else
-# error Unknown Windows bit target
-# endif
-#elif defined(TARGET_OS2)
- /* OS/2 16-bit or 32-bit. Obviously as something compiled for OS/2, we're running under OS/2 */
- if (!windows_init) {
- windows_version_method = "I'm an OS/2 program, therefore the environment is OS/2";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- windows_init = 1;
- }
-#else
- /* MS-DOS 16-bit or 32-bit. MS-DOS applications must try various obscure interrupts to detect whether Windows is running */
- /* TODO: How can we detect whether we're running under OS/2? */
- if (!windows_init) {
- union REGS regs;
-
- windows_version = 0;
- windows_mode = 0;
- windows_init = 1;
-
- switch (dos_version>>8) {
- case 10: /* OS/2 1.x */
- case 20: /* OS/2 2.x (low=0), and OS/2 Warp 3 (low=30), and OS/2 Warp 4 (low=40) */
- windows_version_method = "Deduce from DOS version";
- windows_version = dos_version;
- windows_mode = WINDOWS_OS2;
- break;
- };
-
- if (windows_version == 0) {
- regs.w.ax = 0x160A;
-#if TARGET_MSDOS == 32
- int386(0x2F,®s,®s);
-#else
- int86(0x2F,®s,®s);
-#endif
- if (regs.w.ax == 0x0000 && regs.w.bx >= 0x300 && regs.w.bx <= 0x700) { /* Windows 3.1 */
- windows_version = regs.w.bx;
- switch (regs.w.cx) {
- case 0x0002: windows_mode = WINDOWS_STANDARD; break;
- case 0x0003: windows_mode = WINDOWS_ENHANCED; break;
- default: windows_version = 0; break;
- }
-
- if (windows_mode != 0)
- windows_version_method = "INT 2Fh AX=160Ah";
- }
- }
-
- if (windows_version == 0) {
- regs.w.ax = 0x4680;
-#if TARGET_MSDOS == 32
- int386(0x2F,®s,®s);
-#else
- int86(0x2F,®s,®s);
-#endif
- if (regs.w.ax == 0x0000) { /* Windows 3.0 or DOSSHELL in real or standard mode */
- /* FIXME: Okay... if DOSSHELL triggers this test how do I tell between Windows and DOSSHELL? */
- /* Also, this call does NOT work when Windows 3.0 is in enhanced mode, and for Real and Standard modes
- * does not tell us which mode is active.
- *
- * As far as I can tell there really is no way to differentiate whether it is running in Real or
- * Standard mode, because on a 286 there is no "virtual 8086" mode. The only way Windows can run
- * DOS level code is to thunk back into real mode. So for all purposes whatsoever, we might as well
- * say that we're running in Windows Real mode because during that time slice we have complete control
- * of the CPU. */
- windows_version = 0x300;
- windows_mode = WINDOWS_REAL;
- windows_version_method = "INT 2Fh AX=4680h";
- }
- }
-
- if (windows_version == 0) {
- regs.w.ax = 0x1600;
-#if TARGET_MSDOS == 32
- int386(0x2F,®s,®s);
-#else
- int86(0x2F,®s,®s);
-#endif
- if (regs.h.al == 1 || regs.h.al == 0xFF) { /* Windows 2.x/386 */
- windows_version = 0x200;
- windows_mode = WINDOWS_ENHANCED;
- }
- else if (regs.h.al == 3 || regs.h.al == 4) {
- windows_version = (regs.h.al << 8) + regs.h.ah;
- windows_mode = WINDOWS_ENHANCED; /* Windows 3.0 */
- }
-
- if (windows_mode != 0)
- windows_version_method = "INT 2Fh AX=1600h";
- }
-
- if (windows_version == 0 && windows_mode == WINDOWS_NONE) {
- /* well... if the above fails, but the "true" DOS version is 5.50, then we're running under Windows NT */
- /* NOTE: Every copy of NT/2000/XP/Vista I have reports 5.50, but assuming that will continue is stupid.
- * Microsoft is free to change that someday. */
- if (dos_version == 0) probe_dos();
- if (dos_version >= 0x510 && dos_version <= 0x57f) { /* FIXME: If I recall Windows NT really does stick to v5.50, so this range check should be changed into == 5.50 */
- windows_mode = WINDOWS_NT;
- windows_version = 0;
- windows_version_method = "Assuming from DOS version number";
- }
- }
-
- /* now... if this is Windows NT, the next thing we can do is use NTVDM.EXE's
- * BOP opcodes to load a "helper" DLL that allows us to call into Win32 */
-# if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
- if (windows_mode == WINDOWS_NT && ntvdm_dosntast_init()) {
- /* OK. Ask for the version number */
- OSVERSIONINFO ovi;
-
- memset(&ovi,0,sizeof(ovi));
- ovi.dwOSVersionInfoSize = sizeof(ovi);
- if (ntvdm_dosntast_getversionex(&ovi)) {
- windows_version_method = "GetVersionEx [NTVDM.EXE + DOSNTAST.VDD]";
- windows_version = (ovi.dwMajorVersion << 8) | ovi.dwMinorVersion;
- if (ovi.dwPlatformId == 2/*VER_PLATFORM_WIN32_NT*/)
- windows_mode = WINDOWS_NT;
- else
- windows_mode = WINDOWS_ENHANCED;
- }
- }
-# endif
- }
-#endif
-
- return (windows_mode != WINDOWS_NONE);
-}
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386)
-/* API for exploiting the QT_Thunk Win32 -> Win16 thunking offered by Windows 9x/ME */
-unsigned char win9x_qt_thunk_probed = 0;
-unsigned char win9x_qt_thunk_available = 0;
-
-void (__stdcall *QT_Thunk)() = NULL;
-DWORD (__stdcall *LoadLibrary16)(LPSTR lpszLibFileName) = NULL;
-VOID (__stdcall *FreeLibrary16)(DWORD dwInstance) = NULL;
-HGLOBAL16 (__stdcall *GlobalAlloc16)(UINT flags,DWORD size) = NULL;
-HGLOBAL16 (__stdcall *GlobalFree16)(HGLOBAL16 handle) = NULL;
-DWORD (__stdcall *GlobalLock16)(HGLOBAL16 handle) = NULL;
-BOOL (__stdcall *GlobalUnlock16)(HGLOBAL16 handle) = NULL;
-VOID (__stdcall *GlobalUnfix16)(HGLOBAL16 handle) = NULL;
-VOID (__stdcall *GlobalFix16)(HGLOBAL16 handle) = NULL;
-DWORD (__stdcall *GetProcAddress16)(DWORD dwInstance, LPSTR lpszProcName) = NULL;
-DWORD win9x_kernel_win16 = 0;
-DWORD win9x_user_win16 = 0;
-
-int Win9xQT_ThunkInit() {
- if (!win9x_qt_thunk_probed) {
- Win32OrdinalLookupInfo nfo;
- HMODULE kern32;
-
- win9x_qt_thunk_probed = 1;
- win9x_qt_thunk_available = 0;
-
- if (dos_version == 0) probe_dos();
- if (windows_mode == 0) detect_windows();
- if (windows_mode != WINDOWS_ENHANCED) return 0; /* This does not work under Windows NT */
- if (windows_version < 0x400) return 0; /* This does not work on Windows 3.1 Win32s (FIXME: Are you sure?) */
-
- /* This hack relies on undocumented Win16 support routines hidden in KERNEL32.DLL.
- * They're so super seekret, Microsoft won't even let us get to them through GetProcAddress() */
- kern32 = GetModuleHandle("KERNEL32.DLL");
- if (windows_emulation == WINEMU_WINE) {
- /* FIXME: Direct ordinal lookup doesn't work. Returned
- * addresses point to invalid regions of KERNEL32.DLL.
- * I doubt WINE is even putting a PE-compatible image
- * of it out there.
- *
- * WINE does allow us to GetProcAddress ordinals
- * (unlike Windows 9x which blocks it) but I'm not
- * really sure the returned functions are anything
- * like the Windows 9x equivalent. If we assume they
- * are, this code seems unable to get the address of
- * KRNL386.EXE's "GETVERSION" function.
- *
- * So basically WINE's Windows 9x emulation is more
- * like Windows XP's Application Compatability modes
- * than any serious attempt at pretending to be
- * Windows 9x. And the entry points may well be
- * stubs or other random functions in the same way
- * that ordinal 35 is unrelated under Windows XP. */
- return 0;
- }
- else if (Win32GetOrdinalLookupInfo(kern32,&nfo)) {
- GlobalFix16 = (void*)Win32GetOrdinalAddress(&nfo,27);
- GlobalLock16 = (void*)Win32GetOrdinalAddress(&nfo,25);
- GlobalFree16 = (void*)Win32GetOrdinalAddress(&nfo,31);
- LoadLibrary16 = (void*)Win32GetOrdinalAddress(&nfo,35);
- FreeLibrary16 = (void*)Win32GetOrdinalAddress(&nfo,36);
- GlobalAlloc16 = (void*)Win32GetOrdinalAddress(&nfo,24);
- GlobalUnfix16 = (void*)Win32GetOrdinalAddress(&nfo,28);
- GlobalUnlock16 = (void*)Win32GetOrdinalAddress(&nfo,26);
- GetProcAddress16 = (void*)Win32GetOrdinalAddress(&nfo,37);
- QT_Thunk = (void*)GetProcAddress(kern32,"QT_Thunk");
- }
- else {
- GlobalFix16 = NULL;
- GlobalLock16 = NULL;
- GlobalFree16 = NULL;
- GlobalUnfix16 = NULL;
- LoadLibrary16 = NULL;
- FreeLibrary16 = NULL;
- GlobalAlloc16 = NULL;
- GlobalUnlock16 = NULL;
- GetProcAddress16 = NULL;
- QT_Thunk = NULL;
- }
-
- if (LoadLibrary16 && FreeLibrary16 && GetProcAddress16 && QT_Thunk) {
- /* Prove the API works by loading a reference to KERNEL */
- win9x_kernel_win16 = LoadLibrary16("KERNEL");
- if (win9x_kernel_win16 != 0) {
- win9x_qt_thunk_available = 1;
- }
-
- win9x_user_win16 = LoadLibrary16("USER");
- }
- }
-
- return win9x_qt_thunk_available;
-}
-
-void Win9xQT_ThunkFree() {
- if (win9x_kernel_win16) {
- FreeLibrary16(win9x_kernel_win16);
- win9x_kernel_win16 = 0;
- }
-}
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-unsigned char ToolHelpProbed = 0;
-HMODULE ToolHelpDLL = 0;
-BOOL (PASCAL FAR *__TimerCount)(TIMERINFO FAR *t) = NULL;
-BOOL (PASCAL FAR *__InterruptUnRegister)(HTASK htask) = NULL;
-BOOL (PASCAL FAR *__InterruptRegister)(HTASK htask,FARPROC callback) = NULL;
-
-int ToolHelpInit() {
- if (!ToolHelpProbed) {
- UINT oldMode;
-
- ToolHelpProbed = 1;
-
- /* BUGFIX: In case TOOLHELP.DLL is missing (such as when running under Windows 3.0)
- * this prevents sudden interruption by a "Cannot find TOOLHELP.DLL" error
- * dialog box */
- oldMode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
- ToolHelpDLL = LoadLibrary("TOOLHELP.DLL");
- SetErrorMode(oldMode);
- if (ToolHelpDLL != 0) {
- __TimerCount = (void far*)GetProcAddress(ToolHelpDLL,"TIMERCOUNT");
- __InterruptRegister = (void far*)GetProcAddress(ToolHelpDLL,"INTERRUPTREGISTER");
- __InterruptUnRegister = (void far*)GetProcAddress(ToolHelpDLL,"INTERRUPTUNREGISTER");
- }
- }
-
- return (ToolHelpDLL != 0) && (__TimerCount != NULL) && (__InterruptRegister != NULL) &&
- (__InterruptUnRegister != NULL);
-}
-
-void ToolHelpFree() {
- if (ToolHelpDLL) {
- FreeLibrary(ToolHelpDLL);
- ToolHelpDLL = 0;
- }
- __InterruptUnRegister = NULL;
- __InterruptRegister = NULL;
- __TimerCount = NULL;
-}
-#endif
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* NTVDM.EXE DOSNTAST.VDD call support */
-#include <windows/ntvdm/ntvdmlib.h>
-#endif
-
-enum {
- WINEMU_NONE=0,
- WINEMU_WINE
-};
-
-enum {
- WINDOWS_NONE=0,
- WINDOWS_REAL,
- WINDOWS_STANDARD,
- WINDOWS_ENHANCED,
- WINDOWS_NT,
- WINDOWS_OS2, /* Not Windows, OS/2 */
- /* Exact meaning: If we're a DOS/Windows program, then we know we're running under OS/2
- and OS/2 is emulating DOS/Windows. If we're an OS/2 program, then we're in our native
- environment */
- WINDOWS_MAX
-};
-
-extern const char *windows_mode_strs[WINDOWS_MAX];
-#define windows_mode_str(x) windows_mode_strs[x]
-
-extern uint8_t windows_mode;
-extern uint16_t windows_version;
-extern uint8_t windows_emulation;
-extern const char *windows_version_method;
-extern const char *windows_emulation_comment_str;
-
-/* TODO: Someday, these will become variables */
-
-/* whether the Windows emulation allows Win16 to call DPMI */
-#define windows_emulation_includes_dpmi 0
-
-int detect_windows();
-const char *windows_emulation_str(uint8_t e);
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386)
-# include <windows.h>
-# include <stdint.h>
-
-extern unsigned char win9x_qt_thunk_probed;
-extern unsigned char win9x_qt_thunk_available;
-
-typedef WORD HGLOBAL16; /* <- NTS: Taken from WINE header definitions */
-
-extern void (__stdcall *QT_Thunk)();
-extern DWORD (__stdcall *LoadLibrary16)(LPSTR lpszLibFileName);
-extern VOID (__stdcall *FreeLibrary16)(DWORD dwInstance);
-extern HGLOBAL16 (__stdcall *GlobalAlloc16)(UINT flags,DWORD size);
-extern HGLOBAL16 (__stdcall *GlobalFree16)(HGLOBAL16 handle);
-extern DWORD (__stdcall *GlobalLock16)(HGLOBAL16 handle);
-extern BOOL (__stdcall *GlobalUnlock16)(HGLOBAL16 handle);
-extern VOID (__stdcall *GlobalUnfix16)(HGLOBAL16 handle);
-extern DWORD (__stdcall *GetProcAddress16)(DWORD dwInstance, LPSTR lpszProcName);
-extern VOID (__stdcall *GlobalFix16)(HGLOBAL16 handle);
-
-extern DWORD win9x_kernel_win16;
-extern DWORD win9x_user_win16;
-
-int Win9xQT_ThunkInit();
-void Win9xQT_ThunkFree();
-#endif
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-# include <toolhelp.h>
-extern HMODULE ToolHelpDLL;
-extern unsigned char ToolHelpProbed;
-extern BOOL (PASCAL FAR *__TimerCount)(TIMERINFO FAR *t);
-extern BOOL (PASCAL FAR *__InterruptUnRegister)(HTASK htask);
-extern BOOL (PASCAL FAR *__InterruptRegister)(HTASK htask,FARPROC callback);
-
-int ToolHelpInit();
-void ToolHelpFree();
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-
-#if TARGET_MSDOS == 32
-int _dos_xread(int fd,void *buffer,int bsz) { /* NTS: The DOS extender takes care of translation here for us */
- int rd = -1;
- __asm {
- mov ah,0x3F
- mov ebx,fd
- mov ecx,bsz
- mov edx,buffer
- int 0x21
- mov ebx,eax
- sbb ebx,ebx
- or eax,ebx
- mov rd,eax
- }
- return rd;
-}
-#else
-int _dos_xread(int fd,void far *buffer,int bsz) {
- int rd = -1;
- __asm {
- mov ah,0x3F
- mov bx,fd
- mov cx,bsz
- mov dx,word ptr [buffer+0]
- mov si,word ptr [buffer+2]
- push ds
- mov ds,si
- int 0x21
- pop ds
- mov bx,ax
- sbb bx,bx
- or ax,bx
- mov rd,ax
- }
- return rd;
-}
-#endif
-
-#if TARGET_MSDOS == 32
-int _dos_xwrite(int fd,void *buffer,int bsz) { /* NTS: The DOS extender takes care of translation here for us */
- int rd = -1;
- __asm {
- mov ah,0x40
- mov ebx,fd
- mov ecx,bsz
- mov edx,buffer
- int 0x21
- mov ebx,eax
- sbb ebx,ebx
- or eax,ebx
- mov rd,eax
- }
- return rd;
-}
-#else
-int _dos_xwrite(int fd,void far *buffer,int bsz) {
- int rd = -1;
- __asm {
- mov ah,0x40
- mov bx,fd
- mov cx,bsz
- mov dx,word ptr [buffer+0]
- mov si,word ptr [buffer+2]
- push ds
- mov ds,si
- int 0x21
- pop ds
- mov bx,ax
- sbb bx,bx
- or ax,bx
- mov rd,ax
- }
- return rd;
-}
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if !defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-void far *dpmi_getexhandler(unsigned char n) {
- unsigned short s=0,o=0;
-
- __asm {
- mov ax,0x202
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,dx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int dpmi_setexhandler(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x),o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x203
- mov bl,n
- mov cx,s
- mov dx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-#endif
-
-#if !defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-void far *dpmi_getexhandler(unsigned char n) {
- unsigned short s=0;
- unsigned int o=0;
-
- __asm {
- mov ax,0x202
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,edx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int dpmi_setexhandler(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x);
- unsigned int o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x203
- mov bl,n
- mov cx,s
- mov edx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-unsigned int dpmi_test_rm_entry_call(struct dpmi_realmode_call *rc) {
- unsigned int res = 0;
-
- __asm {
- mov ax,0x0301
- xor bx,bx
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- jnc ok
-
- mov res,1 ; just incase some fucked up DPMI server returns CF=1 EAX=0
- or eax,eax
- jz ok
-
- mov res,eax ; OK store the error code as-is
-ok:
- }
-
- return res;
-}
-
-static unsigned char *alt_rm_call = NULL;
-static uint16_t alt_rm_call_sel = 0;
-
-/* using this hack, subvert INT 06h (invalid opcode exception)
- which the BIOS and DOS are unlikely to use during this hack */
-#define ALT_INT 0x06
-
-int dpmi_alternate_rm_call(struct dpmi_realmode_call *rc) {
- uint32_t oe;
-
- if (alt_rm_call == NULL) {
- alt_rm_call = dpmi_alloc_dos(32,&alt_rm_call_sel);
- if (alt_rm_call == NULL) {
- fprintf(stderr,"FATAL: DPMI alternate call: cannot alloc\n");
- return 0;
- }
- }
-
- /* Fuck you DOS4/GW! */
- /* prepare executable code */
- alt_rm_call[0] = 0x9A; /* CALL FAR IMM */
- *((uint16_t*)(alt_rm_call+1)) = rc->ip;
- *((uint16_t*)(alt_rm_call+3)) = rc->cs;
- alt_rm_call[5] = 0xCF; /* IRET */
-
- /* replace real-mode interrupt vector */
- _cli();
- oe = ((uint32_t*)0x00000000)[ALT_INT];
- ((uint32_t*)0x00000000)[ALT_INT] =
- (((uint32_t)alt_rm_call >> 4UL) << 16UL) | /* seg */
- ((uint32_t)alt_rm_call & 0xFUL); /* ofs */
- _sti();
-
- /* call it! */
- __asm {
- mov ax,0x0300
- mov bx,ALT_INT
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-
- /* restore interrupt vector */
- _cli();
- ((uint32_t*)0x00000000)[ALT_INT] = oe;
- _sti();
-
- return 1;
-}
-
-int dpmi_alternate_rm_call_stacko(struct dpmi_realmode_call *rc) {
- uint32_t oe;
-
- if (alt_rm_call == NULL) {
- alt_rm_call = dpmi_alloc_dos(32,&alt_rm_call_sel);
- if (alt_rm_call == NULL) {
- fprintf(stderr,"FATAL: DPMI alternate call: cannot alloc\n");
- return 0;
- }
- }
-
- /* Fuck you DOS4/GW! */
- /* prepare executable code */
- {
- static unsigned char code[] = {
- 0xFC, /* CLD */
- 0x8C,0xD0, /* MOV AX,SS */
- 0x8E,0xD8, /* MOV DS,AX */
- 0x8E,0xC0, /* MOV ES,AX */
- 0x89,0xE5, /* MOV BP,SP */
- 0x8D,0x76,0x06, /* LEA SI,[BP+6] <- 6 byte interrupt stack */
- 0x83,0xEC,0x20, /* SUB SP,0x20 */
- 0xB9,0x10,0x00, /* MOV CX,0x10 */
- 0x89,0xE7, /* MOV DI,SP */
- 0xF3,0xA5 /* REP MOVSW */
- };
- memcpy(alt_rm_call,code,0x16);
- }
-
- alt_rm_call[0x16] = 0x9A; /* CALL FAR IMM */
- *((uint16_t*)(alt_rm_call+0x16+1)) = rc->ip;
- *((uint16_t*)(alt_rm_call+0x16+3)) = rc->cs;
- alt_rm_call[0x16+5] = 0x89; /* MOV SP,BP */
- alt_rm_call[0x16+6] = 0xEC;
- alt_rm_call[0x16+7] = 0xCF; /* IRET */
-
- /* replace real-mode interrupt vector */
- _cli();
- oe = ((uint32_t*)0x00000000)[ALT_INT];
- ((uint32_t*)0x00000000)[ALT_INT] =
- (((uint32_t)alt_rm_call >> 4UL) << 16UL) | /* seg */
- ((uint32_t)alt_rm_call & 0xFUL); /* ofs */
- _sti();
-
- /* call it! */
- __asm {
- mov ax,0x0300
- mov bx,ALT_INT
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-
- /* restore interrupt vector */
- _cli();
- ((uint32_t*)0x00000000)[ALT_INT] = oe;
- _sti();
-
- return 1;
-}
-#undef ALT_INT
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void mux_realmode_2F_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x002F
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-#endif
-#if TARGET_MSDOS == 16 && defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-void mux_realmode_2F_call(struct dpmi_realmode_call far *rc) {
- __asm {
- push es
- mov ax,0x0300
- mov bx,0x002F
- xor cx,cx
- mov di,word ptr [rc+2]
- mov es,di
- mov di,word ptr [rc]
- int 0x31 ; call DPMI
- pop es
- }
-}
-#endif
-
+++ /dev/null
-/* emm.h
- *
- * Expanded Memory Manager library.
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifndef __HW_DOS_EMM_H
-#define __HW_DOS_EMM_H
-
-#if !defined(TARGET_OS2) && !defined(TARGET_WINDOWS)
-
-#include <stdio.h>
-#include <stdint.h>
-
-/* FIXME: 32-bit protected mode: Who the fuck keeps changing the
- value of ES?!? Watcom and our code rely on ES == DS! */
-#if TARGET_MSDOS == 32
-# define sanity() _sanity(__LINE__,__FILE__)
-static inline void _sanity(unsigned int line,const char *f) {
- uint16_t d=0,e=0;
-
- __asm {
- mov ax,ds
- mov d,ax
- mov ax,es
- mov e,ax
- }
-
- if (d != e) {
- fprintf(stderr,"%s(%u) DS(%X) != ES(%X)\n",f,line,d,e);
- abort();
- }
-}
-#else
-# define sanity()
-#endif
-
-#pragma pack(push,1)
-struct emm_phys_page_map {
- uint16_t segment;
- uint16_t number;
-};
-#pragma pack(pop)
-
-extern unsigned char emm_status;
-extern unsigned char emm_present;
-extern unsigned char emm_version;
-extern unsigned char emm_phys_pages;
-extern unsigned short emm_total_pages;
-extern unsigned int emm_page_frame_segment;
-extern unsigned short emm_unallocated_pages;
-extern struct emm_phys_page_map *emm_phys_map;
-
-int probe_emm();
-void emm_phys_pages_sort();
-void emm_update_page_count();
-int emm_alloc_pages(unsigned int pages);
-int emm_free_pages(unsigned int handle);
-unsigned short emm_last_phys_page_segment(unsigned int phys_page);
-int emm_map_page(unsigned int handle,unsigned int phys_page,unsigned int log_page);
-
-#define emm_was_probed() (emm_status != 0xFF)
-
-#endif /* !defined(TARGET_OS2) && !defined(TARGET_WINDOWS) */
-
-#endif /* __HW_DOS_EMM_H */
-
+++ /dev/null
-/* himemsys.c
- *
- * Support calls to use HIMEM.SYS
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-/* HIMEM.SYS api for DOS programs library
- *
- *
- *
- *
- * Testing:
- *
- * System/configuration Works? Supports >= 64MB?
- * DOSBox 0.74 YES NO, BUGS
- * DOSBox 0.74 +
- * Microsoft Windows 3.0
- * Real mode YES --
- * Standard mode NO -- Reports 0KB free memory (why?)
- * 386 Enhanced mode YES --
- * Microsoft Windows 3.1
- * Standard mode NO -- Reports 0KB free memory (why?)
- * 386 Enhanced mode YES --
- * Microsoft Windows 3.11
- * Standard mode NO -- Reports 0KB free memory (why?)
- * 386 Enhanced mode YES --
- * QEMU +
- * Microsoft Windows 95 (4.00.950)
- * Normal mode YES YES Allows my program to request more memory than available, then triggers the "needs MS-DOS mode" warning (PIF: XMS memory setting on "auto")
- * Normal mode (PIF: XMS=2MB) YES YES This program's attempts to alloc > 1MB fail (correctly). It still triggers the "needs MS-DOS mode" dialog
- * Safe mode YES YES Allows my program to request more memory than available, then triggers the "needs MS-DOS mode" warning (PIF: XMS memory setting on "auto")
- * MS-DOS mode (official) YES YES
- * MS-DOS mode (gui=0) YES YES
- * * NOTE: I also noticed that within the DOS box the Windows kernel denies all requests to lock a handle
- * Microsoft Windows 98 (4.10.1998)
- * Normal mode YES YES Same problem as Windows 95
- * MS-DOS mode (gui=0) YES YES
- * Microsoft Windows ME (4.90.3000)
- * Normal mode YES YES Same problem as Windows 95, triggers "needs MS-DOS mode" warning----Hey wait, Windows ME doesn't have a "DOS mode". A hilarious oversight by Microsoft.
- * Microsoft Windows 2000 Professional
- * Normal mode YES NO NTVDM is very conservative about HIMEM.SYS allocation, listing the largest block size as 919KB. So apparently the default is that MS-DOS
- * applications are allowed up to 1MB of extended memory? The usual MS-DOS configuration options are there, suggesting that in reality the
- * program should have NO extended memory (?). Apparently when you say "none" what it really means is "1MB". Locking the handle is permitted though.
- * The highest value you can enter in the PIF through the GUI is 65534. Setting to 65535 somehow triggers internally the "auto" setting, and is
- * the highest value the editor will let you type in.
- * Microsoft Windows XP Professional
- * Normal mode YES NO Same problems as Windows 2000
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/himemsys.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/*===================================== MS-DOS only ===================================*/
-
-unsigned long himem_sys_largest_free = 0;
-unsigned long himem_sys_total_free = 0;
-unsigned char himem_sys_present = 0;
-unsigned int himem_sys_version = 0;
-unsigned long himem_sys_entry = 0;
-unsigned char himem_sys_flags = 0;
-
-#if TARGET_MSDOS == 32
-static void himem_sys_realmode_2F_call(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x002F
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-
-/* WARNING: If this code is run under DOS4/GW it will silently fail.
- If the HIMEM.SYS test program spouts nonsense about a
- HIMEM.SYS that is v0.00 and has some random amount of memory
- open, that's why. Make sure you link with dos32a. If that's
- not possible, then run your program with dos32 like this:
-
- dos32a <program> */
-static void himem_sys_realmode_entry_call(struct dpmi_realmode_call *rc) {
- rc->ip = himem_sys_entry & 0xFFFF;
- rc->cs = (himem_sys_entry >> 16UL);
-
- if (dpmi_no_0301h > 0) {
- /* Fuck you DOS4/GW! */
- dpmi_alternate_rm_call(rc);
- }
- else {
- __asm {
- mov ax,0x0301
- xor bx,bx
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
- }
-}
-
-int probe_himem_sys() {
- struct dpmi_realmode_call rc={0};
- union REGS regs;
-
- himem_sys_present = 0;
-
-#if TARGET_MSDOS == 32
- /* WAIT!!! We might be running under DOS4/GW. Make sure we can
- call real-mode subroutines with the DPMI server. */
- if (dpmi_no_0301h < 0) probe_dpmi();
-#endif
-
- regs.w.ax = 0x4300;
- int386(0x2F,®s,®s);
- if (regs.h.al != 0x80) return 0;
- himem_sys_present = 1;
-
- /* use the realmode DPMI call to ensure the DPMI server does not screw up (translate) the segment register */
- rc.eax = 0x4310;
- himem_sys_realmode_2F_call(&rc);
- himem_sys_entry =
- ((unsigned long)rc.es << 16UL) |
- ((unsigned long)rc.ebx & 0xFFFFUL);
-
- /* get version info, and autodetect whether it supports extended functions */
- rc.eax = 0;
- himem_sys_realmode_entry_call(&rc);
- himem_sys_version = rc.eax & 0xFFFF;
- himem_sys_flags = (rc.edx & 1) ? HIMEM_F_HMA : 0; /* FIXME: Am I crazy, or does HIMEM.SYS suddenly stop mentioning HMA when we call from protected mode? */
-
- rc.ebx = 0;
- rc.eax = 0x8800;
- himem_sys_realmode_entry_call(&rc);
- himem_sys_flags = (rc.ebx & 0xFF == 0x80) ? 0 : HIMEM_F_4GB;
-
- return 1;
-}
-
-int himem_sys_global_a20(int enable) {
- struct dpmi_realmode_call rc={0};
- if (!himem_sys_present) return 0;
- rc.eax = ((enable > 0) ? 3 : 4) << 8;
- himem_sys_realmode_entry_call(&rc);
- return rc.eax;
-}
-
-int himem_sys_local_a20(int enable) {
- struct dpmi_realmode_call rc={0};
- if (!himem_sys_present) return 0;
- rc.eax = ((enable > 0) ? 5 : 6) << 8;
- himem_sys_realmode_entry_call(&rc);
- return rc.eax;
-}
-
-int himem_sys_query_a20() {
- struct dpmi_realmode_call rc={0};
- if (!himem_sys_present) return 0;
- rc.eax = 7 << 8;
- himem_sys_realmode_entry_call(&rc);
- return rc.eax;
-}
-
-/* NTS: This function will likely set largest & free variables to zero,
- * because most 32-bit DOS extenders take up all extended memory to do their work */
-void himem_sys_update_free_memory_status() {
- struct dpmi_realmode_call rc={0};
- if (!himem_sys_present) return;
-
- if (himem_sys_flags & HIMEM_F_4GB) {
- rc.eax = 0x88 << 8;
- himem_sys_realmode_entry_call(&rc);
- himem_sys_largest_free = rc.eax;
- himem_sys_total_free = rc.edx;
- }
- else {
- rc.eax = 8 << 8;
- himem_sys_realmode_entry_call(&rc);
- himem_sys_largest_free = rc.eax & 0xFFFF;
- himem_sys_total_free = rc.edx & 0xFFFF;
- }
-}
-
-int __cdecl himem_sys_alloc(unsigned long size/* in KB---not bytes*/) {
- struct dpmi_realmode_call rc={0};
- int handle = -1;
-
- if (himem_sys_present) {
- if (himem_sys_flags & HIMEM_F_4GB) {
- rc.eax = 0x89 << 8;
- rc.edx = size;
- himem_sys_realmode_entry_call(&rc);
- if ((rc.eax & 0xFFFF) == 1) handle = rc.edx & 0xFFFF;
- }
- else {
- if (size >= 65535UL) return -1;
- rc.eax = 9 << 8;
- rc.edx = size & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- if ((rc.eax & 0xFFFF) == 1) handle = rc.edx & 0xFFFF;
- }
- }
-
- return handle;
-}
-
-int himem_sys_free(int handle) {
- struct dpmi_realmode_call rc={0};
- rc.eax = 10 << 8;
- rc.edx = handle & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- return (int)(rc.eax & 0xFFFF);
-}
-
-int himem_sys_move(unsigned int dst_handle,uint32_t dst_offset,unsigned int src_handle,uint32_t src_offset,uint32_t length) {
- struct dpmi_realmode_call rc={0};
- unsigned char *tmp;
- uint16_t tmpsel=0;
- int retv = 0;
-
- if ((tmp = (unsigned char*)dpmi_alloc_dos(16,&tmpsel)) == NULL)
- return 0;
-
- if (himem_sys_present) {
- /* for src or dest references with handle == 0 the HIMEM.SYS driver actually
- * takes SEG:OFFSET but we allow the caller to give us a physical memory addr. */
- if (src_handle == 0)
- src_offset = ((src_offset << 12) & 0xFFFF0000UL) | (src_offset & 0xFUL);
- if (dst_handle == 0)
- dst_offset = ((dst_offset << 12) & 0xFFFF0000UL) | (dst_offset & 0xFUL);
-
- *((uint32_t*)(tmp+0x0)) = length;
- *((uint16_t*)(tmp+0x4)) = src_handle;
- *((uint32_t*)(tmp+0x6)) = src_offset;
- *((uint16_t*)(tmp+0xA)) = dst_handle;
- *((uint32_t*)(tmp+0xC)) = dst_offset;
- {
- const uint16_t ofsv = (uint16_t)tmp & 0xFUL;
- const uint16_t segv = (uint16_t)((size_t)tmp >> 4UL);
- rc.eax = 0x0B << 8;
- rc.esi = ofsv;
- rc.ds = segv;
- rc.es = segv;
- himem_sys_realmode_entry_call(&rc);
- retv = rc.eax & 0xFFFF;
- }
- }
-
- dpmi_free_dos(tmpsel);
- return retv;
-}
-
-uint32_t himem_sys_lock(unsigned int handle) {
- struct dpmi_realmode_call rc={0};
- uint32_t o = 0UL;
-
- if (himem_sys_present) {
- rc.eax = 0x0C << 8;
- rc.edx = handle & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- if (rc.eax & 1) o = ((rc.edx & 0xFFFF) << 16) | (rc.ebx & 0xFFFF);
- }
-
- return o;
-}
-
-int himem_sys_unlock(unsigned int handle) {
- struct dpmi_realmode_call rc={0};
- int retv = 0;
-
- if (himem_sys_present) {
- rc.eax = 0x0D << 8;
- rc.edx = handle & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- retv = rc.eax & 0xFFFF;
- }
-
- return retv;
-}
-
-int himem_sys_realloc(unsigned int handle,unsigned long size/* in KB---not bytes*/) {
- struct dpmi_realmode_call rc={0};
- int retv = 0;
-
- if (himem_sys_present) {
- if (himem_sys_flags & HIMEM_F_4GB) {
- rc.eax = 0x8F << 8;
- rc.ebx = size;
- rc.edx = handle & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- retv = rc.eax & 0xFFFF;
- }
- if (retv == 0) {
- if (size >= 65535UL) return 0;
- rc.eax = 0x0F << 8;
- rc.ebx = size;
- rc.edx = handle & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- retv = rc.eax & 0xFFFF;
- }
- }
-
- return retv;
-}
-
-int himem_sys_get_handle_info(unsigned int handle,struct himem_block_info *b) {
- struct dpmi_realmode_call rc={0};
- int retv = 0;
-
- if (himem_sys_present) {
- if (himem_sys_flags & HIMEM_F_4GB) {
- rc.eax = 0x8E << 8;
- rc.edx = handle & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- b->block_length_kb = rc.edx;
- b->lock_count = (rc.ebx >> 8) & 0xFF;
- b->free_handles = rc.ebx & 0xFF;
- retv = rc.eax & 0xFFFF;
- }
- if (retv == 0) {
- rc.eax = 0x0E << 8;
- rc.edx = handle & 0xFFFF;
- himem_sys_realmode_entry_call(&rc);
- b->block_length_kb = rc.edx & 0xFFFF;
- b->lock_count = (rc.ebx >> 8) & 0xFF;
- b->free_handles = rc.ebx & 0xFF;
- retv = rc.eax & 0xFFFF;
- }
- }
-
- return retv;
-}
-#else /* 16-bit real mode */
-int probe_himem_sys() {
- struct SREGS sregs;
- union REGS regs;
-
- himem_sys_present = 0;
- /* NTS: If this is an 8086, then there is no extended memory, and therefore no reason to call HIMEM.SYS */
- if (cpu_basic_level < 0) cpu_probe();
- if (cpu_basic_level < 2) return 0;
-
- regs.w.ax = 0x4300;
- int86(0x2F,®s,®s);
- if (regs.h.al != 0x80) return 0;
- himem_sys_present = 1;
-
- regs.w.ax = 0x4310;
- int86x(0x2F,®s,®s,&sregs);
- himem_sys_entry =
- ((unsigned long)sregs.es << 16UL) |
- ((unsigned long)regs.w.bx);
-
- __asm {
- xor ah,ah ; function 0x00
- call [himem_sys_entry]
- mov himem_sys_version,ax
- and dl,1 ; DX=1 if HMA present, else 0 if not. Your HIMEM.SYS is noncompliant if any other values were put here
- mov himem_sys_flags,dl ; this maps to HIMEM_F_HMA
- }
-
- /* does this HIMEM.SYS support the extended functions to address more than 64MB of memory? */
- __asm {
- mov ah,0x88 ; function 0x88: query any free memory
- mov bl,0x80
- call [himem_sys_entry]
- cmp bl,0x80 ; BL=0x80 if error (unsupported)
- jz label1
- or himem_sys_flags,2 ; <- HIMEM_F_4GB
-label1:
- }
-
- /* Unfortunately, there are HIMEM.SYS implementations that will respond to the extended commands, but fail
- to read or make use of the upper 16 bits of the registers. These broken implementations are easy to check
- for: just allocate a block that is 64MB in size (DX == 0 but EDX == 0x00010000) and if the allocation
- succeeds, use the Get Block Info command to verify that it is in fact 64MB in size. The broken implementation
- will create a zero-length block (which is legal in the HIMEM.SYS standard) and will say so when we ask.
-
- Known HIMEM.SYS broken emulation:
- DOSBox 0.74:
- - Responds to extended commands as if newer HIMEM.SYS but ignores upper 16 bits. You might as well
- just call the original API functions you'll get just as far. DOSBox doesn't emulate more than 64MB
- anyway. */
- if (himem_sys_flags & HIMEM_F_4GB) {
- int h = himem_sys_alloc(0x10000UL);
- if (h != -1) {
- struct himem_block_info binf;
- if (himem_sys_get_handle_info(h,&binf)) {
- if (binf.block_length_kb == 0 || binf.block_length_kb == 1) {
- /* Nope. Our 64MB allocation was mis-interpreted as a zero-length allocation request */
- himem_sys_flags &= ~HIMEM_F_4GB;
- }
- }
- himem_sys_free(h);
- }
- }
-
- return 1;
-}
-
-int himem_sys_global_a20(int enable) {
- int retv=0;
-
- if (!himem_sys_present) return 0;
- enable = (enable > 0) ? 3 : 4;
-
- __asm {
- mov ah,byte ptr enable
- call [himem_sys_entry]
- mov retv,ax
- }
-
- return retv;
-}
-
-int himem_sys_local_a20(int enable) {
- int retv=0;
-
- if (!himem_sys_present) return 0;
- enable = (enable > 0) ? 5 : 6;
-
- __asm {
- mov ah,byte ptr enable
- call [himem_sys_entry]
- mov retv,ax
- }
-
- return retv;
-}
-
-int himem_sys_query_a20() {
- int retv=0;
-
- if (!himem_sys_present) return 0;
-
- __asm {
- mov ah,7
- call [himem_sys_entry]
- mov retv,ax
- }
-
- return retv;
-}
-
-void himem_sys_update_free_memory_status() {
- if (!himem_sys_present) return;
-
- if (himem_sys_flags & HIMEM_F_4GB) {
- __asm {
- mov ah,0x88
- call [himem_sys_entry]
-
- mov word ptr himem_sys_largest_free,ax
- db 0x66,0xC1,0xE8,0x10 ; shr eax,16
- mov word ptr himem_sys_largest_free+2,ax
-
- mov word ptr himem_sys_total_free,dx
- db 0x66,0xC1,0xEA,0x10 ; shr edx,16
- mov word ptr himem_sys_total_free+2,dx
- }
- }
- else {
- __asm {
- mov ah,8
- call [himem_sys_entry]
-
- mov word ptr himem_sys_largest_free,ax
- mov word ptr himem_sys_largest_free+2,0
-
- mov word ptr himem_sys_total_free,dx
- mov word ptr himem_sys_total_free+2,0
- }
- }
-}
-
-/* WARNING: do not remove the __cdecl declaration, the hack below relies on it.
- * Watcom's native register protocol will copy the long value to a 16-bit
- * word on stack and then we won't get the full value. */
-int __cdecl himem_sys_alloc(unsigned long size/* in KB---not bytes*/) {
- int handle = -1;
-
- if (himem_sys_present) {
- if (himem_sys_flags & HIMEM_F_4GB) {
- __asm {
- mov ah,0x89
- db 0x66
- mov dx,word ptr size ; the 0x66 makes it 'mov edx,size'
- call [himem_sys_entry]
- test al,1
- jnz alloc_ok
- xor dx,dx
- dec dx
-alloc_ok: mov handle,dx
- }
- }
- if (handle == -1) {
- if (size >= 65535UL) return -1;
-
- __asm {
- mov ah,9
- mov dx,word ptr size
- call [himem_sys_entry]
- test al,1
- jnz alloc_ok
- xor dx,dx
- dec dx
-alloc_ok: mov handle,dx
- }
- }
- }
-
- return handle;
-}
-
-int himem_sys_free(int handle) {
- int retv = 0;
-
- if (himem_sys_present) {
- __asm {
- mov ah,10
- mov dx,handle
- call [himem_sys_entry]
- mov retv,ax
- }
- }
-
- return retv;
-}
-
-int himem_sys_move(unsigned int dst_handle,uint32_t dst_offset,unsigned int src_handle,uint32_t src_offset,uint32_t length) {
- unsigned char tmp[16]; /* struct */
- int retv = 0;
-
- if (himem_sys_present) {
- /* for src or dest references with handle == 0 the HIMEM.SYS driver actually
- * takes SEG:OFFSET but we allow the caller to give us a physical memory addr. */
- if (src_handle == 0)
- src_offset = ((src_offset << 12) & 0xFFFF0000UL) | (src_offset & 0xFUL);
- if (dst_handle == 0)
- dst_offset = ((dst_offset << 12) & 0xFFFF0000UL) | (dst_offset & 0xFUL);
-
- *((uint32_t*)(tmp+0x0)) = length;
- *((uint16_t*)(tmp+0x4)) = src_handle;
- *((uint32_t*)(tmp+0x6)) = src_offset;
- *((uint16_t*)(tmp+0xA)) = dst_handle;
- *((uint32_t*)(tmp+0xC)) = dst_offset;
- {
- const void far *x = (void far*)tmp;
- const uint16_t ofsv = FP_OFF(x);
- const uint16_t segv = FP_SEG(x);
- const uint16_t dsseg = 0;
- __asm {
- mov ax,ds
- mov dsseg,ax
- }
- assert(segv == dsseg);
- __asm {
- mov ah,11
- mov si,ofsv
- call [himem_sys_entry]
- mov retv,ax
- }
- }
- }
-
- return retv;
-}
-
-uint32_t himem_sys_lock(unsigned int handle) {
- uint32_t o = 0UL;
-
- if (himem_sys_present) {
- __asm {
- mov ah,12
- mov dx,handle
- call [himem_sys_entry]
- test al,1
- jnz lockend
- xor bx,bx
- mov dx,bx
-lockend: mov word ptr o,bx
- mov word ptr o+2,dx
- }
- }
-
- return o;
-}
-
-int himem_sys_unlock(unsigned int handle) {
- int retv = 0;
-
- if (himem_sys_present) {
- __asm {
- mov ah,13
- mov dx,handle
- call [himem_sys_entry]
- mov retv,ax
- }
- }
-
- return retv;
-}
-
-int __cdecl himem_sys_realloc(unsigned int handle,unsigned long size/* in KB---not bytes*/) {
- int retv = 0;
-
- if (himem_sys_present) {
- if (himem_sys_flags & HIMEM_F_4GB) {
- __asm {
- mov ah,0x8F
- db 0x66
- mov bx,word ptr size ; the 0x66 makes it 'mov ebx,size'
- mov dx,handle
- call [himem_sys_entry]
- mov retv,ax
- }
- }
- if (retv == 0) {
- if (size >= 65535UL) return 0;
-
- __asm {
- mov ah,15
- mov bx,word ptr size
- mov dx,handle
- call [himem_sys_entry]
- mov retv,ax
- }
- }
- }
-
- return retv;
-}
-
-int himem_sys_get_handle_info(unsigned int handle,struct himem_block_info *b) {
- int retv = 0;
-
- if (himem_sys_present) {
- if (himem_sys_flags & HIMEM_F_4GB) {
- __asm {
- mov ah,0x8E
- mov dx,handle
- call [himem_sys_entry]
- mov si,word ptr b
- db 0x66
- mov word ptr [si],dx ; becomes dword ptr [esi]
- mov byte ptr [si+4],bh ; lock count
- mov byte ptr [si+5],bl ; free handles
- mov retv,ax
- }
- }
- if (retv == 0) {
- __asm {
- mov ah,14
- mov dx,handle
- call [himem_sys_entry]
- mov si,word ptr b
- mov word ptr [si],dx
- mov word ptr [si+2],0
- mov byte ptr [si+4],bh ; lock count
- mov byte ptr [si+5],bl ; free handles
- mov retv,ax
- }
- }
- }
-
- return retv;
-}
-#endif
-
-#endif /* !defined(TARGET_WINDOWS) && !defined(TARGET_OS2) */
-
+++ /dev/null
-/* lol.c
- *
- * Test program: Make use of the MS-DOS "List of Lists" to print various things
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-/* FIXME: MS-DOS 6.22 under QEMU: This hangs, or causes QEMU to crash? */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-
-int main() {
- int i,c,line = 0;
- unsigned char FAR *LOL;
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- printf(" Flavor: '%s'\n",dos_flavor_str(dos_flavor));
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (detect_dosbox_emu())
- printf("I am also running under DOSBox\n");
-
- if ((LOL = dos_list_of_lists()) != NULL) {
- printf("DOS List of Lists at ");
-#if TARGET_MSDOS == 32
- printf("0x%08lX\n",(unsigned long)LOL);
-#else
- printf("%04x:%04x\n",FP_SEG(LOL),FP_OFF(LOL));
-#endif
- }
- else {
- printf("Unable to locate the DOS 'list of lists'\n");
- return 0;
- }
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
-
- /* list MCBs */
- {
- struct dos_psp_cooked pspnfo;
- struct dos_mcb_enum men;
-
- if (dos_mcb_first(&men)) {
- printf("Resident MCBs\n"); line++;
- do {
- mcb_filter_name(&men);
-
- printf("[%04x]: %02x PSP=%04x size=%04x %-8s ",
- men.cur_segment,men.type,men.psp,men.size,men.name);
- for (i=0;i < 32;i++) {
- c = men.ptr[i];
- if (c >= 32 && c <= 126) printf("%c",c);
- else printf(".");
- }
- printf("\n");
-
- if (men.psp >= 0x80 && men.psp < 0xFFFFU && dos_parse_psp(men.psp,&pspnfo)) {
- printf(" PSP memsize=%04xh callpsp=%04xh env=%04xh command='%s'\n",
- pspnfo.memsize,pspnfo.callpsp,pspnfo.env,pspnfo.cmd);
-
- if (++line >= 20) {
- line -= 20;
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- }
-
- if (++line >= 20) {
- line -= 20;
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- } while (dos_mcb_next(&men));
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- }
-
- /* list devices */
- {
- struct dos_device_enum denu;
-
- if (dos_device_first(&denu)) {
- printf("Device drivers\n"); line++;
- do {
- printf(" ATTR=%04Xh entry=%04Xh int=%04Xh %s\n",denu.attr,denu.entry,denu.intent,denu.name);
-
- if (++line >= 20) {
- line -= 20;
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- } while (dos_device_next(&denu));
-
- /* ENTER for next, ESC to stop */
- while ((c=getch()) != 13) {
- if (c == 27) return 0;
- }
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-/* ntastrm.c
- *
- * Utility program: Manually trigger the removal of the DOSNTAST driver.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * If a program using DOSNTAST fails to unload the driver, it will remain resident.
- * This program allows you to remove it manually if that happens. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/dosntvdm.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- /* probe_dos() and detect_windows() should NOT auto-load the DOSNTAST driver.
- * we're going to unload it if resident. */
- lib_dos_option.dont_load_dosntast=1;
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- printf(" Method: '%s'\n",dos_version_method);
-
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%u\n",windows_version>>8,windows_version&0xFF);
- printf(" Method: '%s'\n",windows_version_method);
- if (windows_emulation != WINEMU_NONE)
- printf(" Emulation: '%s'\n",windows_emulation_str(windows_emulation));
- if (windows_emulation_comment_str != NULL)
- printf(" Emulation comment: '%s'\n",windows_emulation_comment_str);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
- printf("DOSNTAST.VDD driver was loaded (handle=%u), unloading...\n",ntvdm_dosntast_handle);
- ntvdm_dosntast_unload();
- }
-#endif
-
- return 0;
-}
-
+++ /dev/null
-
-DOS support library
- dos.obj ......................... Helper functions for DOS I/O to far and huge memory
- emm.obj ......................... Utility library to make use of the Expanded Memory Manager (usually, EMM386.EXE)
- dosbox.obj ...................... Utility function to detect if we're running in the DOSBox emulator
- biosext.obj ..................... Utility function for real-mode software to use BIOS INT 15H AH=0x87 extended memory copy function
- himemsys.obj .................... Utility library to make use of Extended Memory via HIMEM.SYS
+++ /dev/null
-/* test.c
- *
- * Test program: Various info about DOS
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/dosntvdm.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-#endif
-
-int main() {
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- printf(" Method: '%s'\n",dos_version_method);
- printf(" Flavor: '%s'\n",dos_flavor_str(dos_flavor));
- if (dos_flavor == DOS_FLAVOR_FREEDOS) {
- printf(" FreeDOS kernel %u.%u.%u (%lX)\n",
- (unsigned int)((freedos_kernel_version >> 16UL) & 0xFFUL),
- (unsigned int)((freedos_kernel_version >> 8UL) & 0xFFUL),
- (unsigned int)((freedos_kernel_version) & 0xFFUL),
- (unsigned long)freedos_kernel_version);
- if (freedos_kernel_version_str != NULL) {
-#if TARGET_MSDOS == 32
- printf(" FreeDOS kernel version string: %s\n",
- freedos_kernel_version_str);
-#else
- printf(" FreeDOS kernel version string: %Fs\n",
- freedos_kernel_version_str);
-#endif
- }
- }
-
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%u\n",windows_version>>8,windows_version&0xFF);
- printf(" Method: '%s'\n",windows_version_method);
- if (windows_emulation != WINEMU_NONE)
- printf(" Emulation: '%s'\n",windows_emulation_str(windows_emulation));
- if (windows_emulation_comment_str != NULL)
- printf(" Emulation comment: '%s'\n",windows_emulation_comment_str);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
-#if defined(NTVDM_CLIENT) && !defined(TARGET_WINDOWS)
- if (ntvdm_dosntast_handle != DOSNTAST_HANDLE_UNASSIGNED) {
- OSVERSIONINFO o;
- WAVEOUTCAPS woc;
- unsigned int i,j;
- uint32_t dw;
-
- printf("This program is using the DOSNTAST.VDD driver (handle=%u io=0x%03X)\n",ntvdm_dosntast_handle,ntvdm_dosntast_io_base);
-
- printf("GetTickCount() = %lu\n",ntvdm_dosntast_GetTickCount());
- printf("waveOutGetNumDevs() = %d\n",j=ntvdm_dosntast_waveOutGetNumDevs());
- for (i=0;i < j;i++) {
- memset(&woc,0,sizeof(woc));
- if ((dw=ntvdm_dosntast_waveOutGetDevCaps(i,&woc,sizeof(woc))) == 0) {
- printf(" [%u]: %s v%u.%u\n",i,woc.szPname,woc.vDriverVersion>>8,woc.vDriverVersion&0xFF);
- printf(" MID=0x%04lX PID=0x%04lX FMTS=0x%08lX chan=%u\n",
- (unsigned long)woc.wMid,
- (unsigned long)woc.wPid,
- (unsigned long)woc.dwFormats,
- woc.wChannels);
- printf(" CAPS: ");
- if (woc.dwSupport & WAVECAPS_LRVOLUME) printf("LRVOL ");
- if (woc.dwSupport & WAVECAPS_PITCH) printf("PITCH ");
- if (woc.dwSupport & WAVECAPS_PLAYBACKRATE) printf("PLAYRATE ");
- if (woc.dwSupport & WAVECAPS_SYNC) printf("SYNC ");
- if (woc.dwSupport & WAVECAPS_VOLUME) printf("VOL ");
- if (woc.dwSupport & WAVECAPS_SAMPLEACCURATE) printf("SAMPLEACCURATE ");
- printf("\n");
- }
- else {
- printf(" [%u]: Cannot read err=0x%08lX\n",i,dw);
- }
- }
-
- printf("GetVersionEx() = ");
- o.dwOSVersionInfoSize = sizeof(o);
- if (ntvdm_dosntast_getversionex(&o)) {
- printf("v%lu.%lu build #%lu platform=%lu '%s'",
- o.dwMajorVersion,
- o.dwMinorVersion,
- o.dwBuildNumber,
- o.dwPlatformId,
- o.szCSDVersion);
- }
- else {
- printf("failed?");
- }
- printf("\n");
-
- ntvdm_dosntast_MessageBox("Hello!\n\nIf you can read this, DOS programs are able to use the driver successfully!");
- }
-#endif
-
- if (detect_dosbox_emu())
- printf("I am also running under DOSBox\n");
- if (detect_virtualbox_emu())
- printf("I am also running under Sun/Oracle VirtualBox %s\n",virtualbox_version_str);
-
- probe_dpmi();
-#if dpmi_present != 0
- if (dpmi_present) {
- printf("DPMI present:\n");
-# if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS))
- if (dpmi_no_0301h > 0) printf(" - DPMI function 0301H: Call real-mode far routine NOT AVAILABLE\n");
- printf(" - Flags: 0x%04x\n",dpmi_flags);
- printf(" - Entry: %04x:%04x (real mode)\n",(unsigned int)(dpmi_entry_point>>16UL),(unsigned int)(dpmi_entry_point & 0xFFFFUL));
- printf(" - Processor type: %02x\n",dpmi_processor_type);
- printf(" - Version: %u.%u\n",dpmi_version>>8,dpmi_version&0xFF);
- printf(" - Private data length: %u paras\n",dpmi_private_data_length_paragraphs);
-# endif
- }
-#endif
-
- if (probe_vcpi()) {
- printf("VCPI present (v%d.%d)\n",
- vcpi_major_version,
- vcpi_minor_version);
- }
-
-#ifdef WINFCON_STOCK_WIN_MAIN
- {
- char c;
-
- printf("---------[Type junk here]---------\n");
- do {
- c = getch();
- if (c == 27) break;
- else if (c == 13) printf("\n");
- else printf("%c",c);
- } while (1);
- }
-#endif
-
- return 0;
-}
-
+++ /dev/null
-/* testbext.c
- *
- * Test program: Use INT 15h to copy extended memory.
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * This program shows that the API works, and also reveals whether or not
- * the BIOS API is limited to 16MB. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/biosext.h>
-
-int main() {
-#if TARGET_MSDOS == 16
- {
- unsigned int i;
- unsigned long addr;
- unsigned char tmp[16];
-
- printf("Copying data out of extended memory via BIOS\n");
- for (addr=0xFFF80UL;addr < 0x100000UL;addr += sizeof(tmp)) {
- memset(tmp,0,sizeof(tmp));
- if (bios_extcopy(ptr2phys(tmp),addr,16)) {
- printf("Problem copying\n");
- break;
- }
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- for (i=0;i < 16;i++) printf("%c",tmp[i] >= 32 ? tmp[i] : ' ');
- printf("\n");
- }
- while (getch() != 13);
-
- printf("Copying data out of extended memory via BIOS (16MB higher)\n");
- for (addr=0x10FFF80UL;addr < 0x1100000UL;addr += sizeof(tmp)) {
- memset(tmp,0,sizeof(tmp));
- if (bios_extcopy(ptr2phys(tmp),addr,16)) {
- printf("Problem copying\n");
- break;
- }
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- for (i=0;i < 16;i++) printf("%c",tmp[i] >= 32 ? tmp[i] : ' ');
- printf("\n");
- }
- while (getch() != 13);
- }
-#else
- printf("Test does not apply to 32-bit builds\n");
-#endif
-
- return 0;
-}
-
+++ /dev/null
-/* testdpmi.c
- *
- * Test program: DPMI entry/exit functions
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-
-#ifdef TARGET_WINDOWS
-#error wrong target
-#endif
-
-int main(int argc,char **argv) {
- unsigned char want = DPMI_ENTER_AUTO;
-
- if (argc > 1) {
- want = atoi(argv[1]);
- if (want < 16 || want > 32) return 1;
- }
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- printf(" Method: '%s'\n",dos_version_method);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- printf(" Method: '%s'\n",windows_version_method);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- probe_dpmi();
- if (!dpmi_present) {
- printf("This test requires DPMI\n");
- return 1;
- }
-
- printf("DPMI present:\n");
-#if dpmi_no_0301h != 0
- if (dpmi_no_0301h > 0) printf(" - DPMI function 0301H: Call real-mode far routine NOT AVAILABLE\n");
-#endif
- printf(" - Flags: 0x%04x\n",dpmi_flags);
- printf(" - Entry: %04x:%04x (real mode)\n",(unsigned int)(dpmi_entry_point>>16UL),(unsigned int)(dpmi_entry_point & 0xFFFFUL));
- printf(" - Processor type: %02x\n",dpmi_processor_type);
- printf(" - Version: %u.%u\n",dpmi_version>>8,dpmi_version&0xFF);
- printf(" - Private data length: %u paras\n",dpmi_private_data_length_paragraphs);
-
- /* enter DPMI. the routine will briefly run in protected mode before finding it's way
- * back to real mode where it can return back to this function */
- if (!dpmi_enter(want)) {
- printf("Unable to enter DPMI server\n");
- return 1;
- }
- printf("Allocated DPMI private segment: 0x%04x\n",dpmi_private_data_segment);
- printf("DPMI entered as %u-bit.\n",dpmi_entered);
- printf(" - PM CS:%04x DS:%04x ES:%04x SS:%04x\n",dpmi_pm_cs,dpmi_pm_ds,dpmi_pm_es,dpmi_pm_ss);
- printf(" - Real to protected entry: %04x:%04x [rmode]\n",
- (unsigned int)(dpmi_pm_entry>>16UL),(unsigned int)(dpmi_pm_entry&0xFFFFUL));
- if (dpmi_entered == 32)
- printf(" - Protected to real entry: %04x:%08lx [pmode]\n",
- (unsigned int)((dpmi_rm_entry>>32ULL)&0xFFFFUL),(unsigned long)(dpmi_rm_entry&0xFFFFFFFFUL));
- else
- printf(" - Protected to real entry: %04x:%04x [pmode]\n",
- (unsigned int)(dpmi_rm_entry>>16UL),(unsigned int)(dpmi_rm_entry&0xFFFFUL));
-
- return 0;
-}
-
+++ /dev/null
-/* testsmrt.c
- *
- * Test program: Demonstrate SMARTDRV detection code.
- * (C) 2014 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosbox.h>
-
-int main() {
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- printf(" Flavor: '%s'\n",dos_flavor_str(dos_flavor));
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (smartdrv_detect()) {
- printf("SMARTDRV %u.%02u detected!\n",smartdrv_version>>8,smartdrv_version&0xFF);
- printf("Now flushing\n");
- smartdrv_flush();
- printf("Made it.\n");
- smartdrv_close();
- }
-
- return 0;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/tgusmega.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-struct mega_em_info megaem_info={0};
-
-int gravis_mega_em_detect(struct mega_em_info *x) {
-/* TODO: Cache results, only need to scan once */
- union REGS regs={0};
- regs.w.ax = 0xFD12;
- regs.w.bx = 0x3457;
-#if TARGET_MSDOS == 32
- int386(0x21,®s,®s);
-#else
- int86(0x21,®s,®s);
-#endif
- if (regs.w.ax == 0x5678) {
- x->intnum = regs.h.cl;
- x->version = regs.w.dx;
- x->response = regs.w.bx;
-
- if (x->version == 0) {
- if (x->response == 0x1235)
- x->version = 0x200;
- else if (x->response == 0x1237)
- x->version = 0x300;
- }
- return 1;
- }
- return 0;
-}
-#endif
-
+++ /dev/null
-
-#include <stdint.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-# define HAVE_GUS_MEGAEM_DETECT
-struct mega_em_info {
- unsigned char intnum;
- uint16_t version;
- uint16_t response;
-};
-
-extern struct mega_em_info megaem_info;
-
-int gravis_mega_em_detect(struct mega_em_info *x);
-#endif
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/tgussbos.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* returns interrupt vector */
-/* these functions are duplicates of the ones in the ULTRASND library
- because it matters to this library whether or not we're talking to
- Gravis Ultrasound and shitty SB emulation */
-int gravis_sbos_detect() {
- unsigned char FAR *ex;
- uint16_t s,o;
- int i = 0x78;
-
- while (i < 0x90) {
-#if TARGET_MSDOS == 32
- o = *((uint16_t*)(i*4U));
- s = *((uint16_t*)((i*4U)+2U));
-#else
- o = *((uint16_t far*)MK_FP(0,(uint16_t)i*4U));
- s = *((uint16_t far*)MK_FP(0,((uint16_t)i*4U)+2U));
-#endif
-
- if (o == 0xFFFF || s == 0x0000 || s == 0xFFFF) {
- i++;
- continue;
- }
-
- /* we're looking for "SBOS" signature */
-#if TARGET_MSDOS == 32
- ex = (unsigned char*)((s << 4UL) + 0xA);
- if (memcmp(ex,"SBOS",4) == 0) return i;
-#else
- ex = MK_FP(s,0xA);
- if (_fmemcmp(ex,"SBOS",4) == 0) return i;
-#endif
-
- i++;
- }
-
- return -1;
-}
-#endif
-
+++ /dev/null
-
-int gravis_sbos_detect();
-
+++ /dev/null
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/tgusumid.h>
-
-#if !defined(TARGET_WINDOWS) && !defined(TARGET_OS2)
-/* returns interrupt vector */
-int gravis_ultramid_detect() {
- unsigned char FAR *ex;
- uint16_t s,o;
- int i = 0x78;
-
- while (i < 0x90) {
-#if TARGET_MSDOS == 32
- o = *((uint16_t*)(i*4U));
- s = *((uint16_t*)((i*4U)+2U));
-#else
- o = *((uint16_t far*)MK_FP(0,(uint16_t)i*4U));
- s = *((uint16_t far*)MK_FP(0,((uint16_t)i*4U)+2U));
-#endif
-
- if (o == 0xFFFF || s == 0x0000 || s == 0xFFFF) {
- i++;
- continue;
- }
-
- /* we're looking for "ULTRAMID" signature */
-#if TARGET_MSDOS == 32
- ex = (unsigned char*)((s << 4UL) + 0x103);
- if (memcmp(ex,"ULTRAMID",8) == 0) return i;
-#else
- ex = MK_FP(s,0x103);
- if (_fmemcmp(ex,"ULTRAMID",8) == 0) return i;
-#endif
-
- i++;
- }
-
- return -1;
-}
-#endif /* !defined(TARGET_WINDOWS) */
-
+++ /dev/null
-
-int gravis_ultramid_detect();
-
+++ /dev/null
--fr=nul -fo=dos386f/.obj -i=.. -i../.. -e=2 -zq -mf -d0 -bt=dos -oilrtfm -wx -fp3 -3r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=386 -DMMODE=f -q dosdpmi.c
+++ /dev/null
-/* tstbiom.c
- *
- * Test program: BIOS extended memory layout and reporting
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/biosmem.h>
-
-int main() {
-#if TARGET_MSDOS == 16
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- {
- unsigned int l;
- if (biosmem_size_88(&l)) {
- printf("BIOS memory (INT 15H AH=0x88)\n");
- printf(" Total memory: %uKB (%uMB)\n",l,l >> 10UL);
- }
- }
-
- {
- unsigned int l,h;
- if (biosmem_size_E801(&l,&h)) {
- printf("BIOS memory (INT 15H AX=0xE801)\n");
- printf(" Total memory: 1MB + %uKB + %luKB = %luKB (%luMB)\n",
- l,(unsigned long)h * 64UL,(unsigned long)l + ((unsigned long)h * 64UL) + 1024UL,
- ((unsigned long)l + ((unsigned long)h * 64UL) + 1024UL) >> 10UL);
- if (l != 0) printf(" 1-16MB: 0x%08lX-0x%08lX\n",0x100000UL,0x100000UL + ((unsigned long)l << 10UL) - 1UL);
- if (h != 0) printf(" 16MB+: 0x%08lX-0x%08lX\n",0x1000000UL,0x1000000UL + ((unsigned long)h << 16UL) - 1UL);
- }
- }
-
- {
- struct bios_E820 nfo;
- unsigned long index,pindex;
- int len;
-
- index = pindex = 0;
- if ((len=biosmem_size_E820(&index,&nfo)) > 0) {
- printf("BIOS memory (INT 15H AX=E820)\n");
- do {
- printf(" len=%u index=0x%02lX 0x%012llx-0x%012llx type=0x%02lx attr=0x%02lx\n",
- len,(unsigned long)pindex,
- (unsigned long long)nfo.base,
- (unsigned long long)(nfo.base + nfo.length - 1ULL),
- nfo.type,nfo.ext_attributes);
- if (index == 0) break; /* the BIOS will return with EBX == 0 when returning the last item */
- pindex = index;
- } while ((len=biosmem_size_E820(&index,&nfo)) > 0);
- }
- }
-#else /* == 32 */
- printf("This program is pointless in 32-bit protected mode\n");
-#endif
- return 0;
-}
-
+++ /dev/null
-/* tsthimem.c
- *
- * Test program: HIMEM.SYS functions
- * (C) 2010-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/himemsys.h>
-
-int main() {
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (probe_himem_sys()) {
- int h1,h2,h3;
-
- printf("HIMEM.SYS detected. Entry point %04x:%04x. v%x.%02x\n",
- (unsigned int)((himem_sys_entry >> 16) & 0xFFFFUL),
- (unsigned int)(himem_sys_entry & 0xFFFFUL),
- (unsigned int)(himem_sys_version >> 8),
- (unsigned int)(himem_sys_version & 0xFF));
-
- if (himem_sys_flags & HIMEM_F_HMA)
- printf(" - HMA is present\n");
- if (himem_sys_flags & HIMEM_F_4GB)
- printf(" - Extensions are present to address up to 4GB of memory\n");
-
- printf("A20 status: %u\n",himem_sys_query_a20());
- printf("Global A20 line: "); fflush(stdout);
- printf("en=%d ",himem_sys_global_a20(1)); fflush(stdout);
- printf("query=%d ",himem_sys_query_a20(1)); fflush(stdout);
- printf("dis=%d ",himem_sys_global_a20(0)); fflush(stdout);
- printf("query=%d ",himem_sys_query_a20(1)); fflush(stdout);
- printf("\n");
-
- printf("Local A20 line: "); fflush(stdout);
- printf("en=%d ",himem_sys_local_a20(1)); fflush(stdout);
- printf("query=%d ",himem_sys_query_a20(1)); fflush(stdout);
- printf("dis=%d ",himem_sys_local_a20(0)); fflush(stdout);
- printf("query=%d ",himem_sys_query_a20(1)); fflush(stdout);
- printf("\n");
-
- himem_sys_update_free_memory_status();
- printf("Free memory: %luKB (largest block %luKB)\n",
- (unsigned long)himem_sys_total_free,
- (unsigned long)himem_sys_largest_free);
-
- printf("Attempting to alloc 4KB: ");
- h1 = himem_sys_alloc(4); /* NTS: This is in KB, not bytes */
- if (h1 != -1) printf("ok, handle %u\n",h1);
- else printf("failed\n");
-
- printf("Attempting to alloc 64KB: ");
- h2 = himem_sys_alloc(46); /* NTS: This is in KB, not bytes */
- if (h2 != -1) printf("ok, handle %u\n",h2);
- else printf("failed\n");
-
- printf("Attempting to alloc 1MB: ");
- h3 = himem_sys_alloc(1024); /* NTS: This is in KB, not bytes */
- if (h3 != -1) printf("ok, handle %u\n",h3);
- else printf("failed\n");
-
- if (h1 != -1) {
- if (!himem_sys_free(h1)) printf(" - Free failed\n");
- }
- if (h2 != -1) {
- if (!himem_sys_free(h2)) printf(" - Free failed\n");
- }
- if (h3 != -1) {
- if (!himem_sys_free(h3)) printf(" - Free failed\n");
- }
-
- printf("Attempting to alloc 1MB (for writing to): ");
- h3 = himem_sys_alloc(1024); /* NTS: This is in KB, not bytes */
- if (h3 != -1) {
- uint32_t ofs;
- unsigned int i;
- struct himem_block_info binf;
-#if TARGET_MSDOS == 32
- char *msg;
- unsigned char *tmp;
- uint16_t tmpsel=0,msgsel=0;
- const char *msgref = "Testing 123 hello";
-#else
- unsigned char tmp[16];
- const char *msg = "Testing 123 hello";
-#endif
-
-#if TARGET_MSDOS == 32
- tmp = dpmi_alloc_dos(16,&tmpsel);
- if (tmp == NULL) abort();
- msg = dpmi_alloc_dos(strlen(msgref)+16,&msgsel);
- if (msg == NULL) abort();
- memcpy(msg,msgref,strlen(msgref)+1);
-#endif
-
- printf("ok, handle %u\n",h3);
-
- if (himem_sys_get_handle_info(h3,&binf)) {
- printf("Handle info:\n");
- printf(" Lock count=%u Free handles=%u Size=%luKB\n",
- (unsigned int)binf.lock_count,
- (unsigned int)binf.free_handles,
- (unsigned long)binf.block_length_kb);
- }
- else {
- printf("Cannot get handle info\n");
- }
-
-#if TARGET_MSDOS == 32
- if (!himem_sys_move(h3,0,0/*conventional memory*/,(unsigned long)(msg),16))
-#else
- if (!himem_sys_move(h3,0,0/*conventional memory*/,((unsigned long)FP_SEG(msg) << 4UL) + (unsigned long)FP_OFF(msg),sizeof(tmp)))
-#endif
- printf("Copy didn't work\n");
-
- for (i=0;i < 16;i += 2) {
- tmp[i+0] = 0x55;
- tmp[i+1] = 0xAA;
- }
-
-#if TARGET_MSDOS == 32
- if (!himem_sys_move(0/*conventional memory*/,(unsigned long)(tmp),h3,0,16))
-#else
- if (!himem_sys_move(0/*conventional memory*/,((unsigned long)FP_SEG(tmp) << 4UL) + (unsigned long)FP_OFF(tmp),h3,0,sizeof(tmp)))
-#endif
- printf("Copy didn't work\n");
-
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- printf("\n");
-
- ofs = himem_sys_lock(h3);
- if (ofs != 0UL) {
- printf(" - Locked: Physical memory address 0x%08lX\n",(unsigned long)ofs);
- if (!himem_sys_unlock(h3)) printf(" - Cannot unlock\n");
- }
- else {
- printf(" - Cannot lock\n");
- }
-
- printf("now resizing to 2MB\n");
- if (himem_sys_realloc(h3,2048)) {
-#if TARGET_MSDOS == 32
- if (!himem_sys_move(0/*conventional memory*/,(unsigned long)(tmp),h3,0,16))
-#else
- if (!himem_sys_move(0/*conventional memory*/,((unsigned long)FP_SEG(tmp) << 4UL) + (unsigned long)FP_OFF(tmp),h3,0,sizeof(tmp)))
-#endif
- printf("Copy didn't work\n");
-
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- printf("\n");
-
- ofs = himem_sys_lock(h3);
- if (ofs != 0UL) {
- printf(" - Locked: Physical memory address 0x%08lX\n",(unsigned long)ofs);
- if (!himem_sys_unlock(h3)) printf(" - Cannot unlock\n");
- }
- else {
- printf(" - Cannot lock\n");
- }
- }
- else {
- printf(" - Cannot realloc\n");
- }
-
- if (!himem_sys_free(h3)) printf(" - Free failed\n");
-
-#if TARGET_MSDOS == 32
- dpmi_free_dos(tmpsel); tmp=NULL;
- dpmi_free_dos(msgsel); msg=NULL;
-#endif
- }
- else printf("failed\n");
-
- printf("Attempting to alloc 129MB (for writing to): ");
- h3 = himem_sys_alloc(129UL * 1024UL); /* NTS: This is in KB, not bytes */
- if (h3 != -1) {
- uint32_t ofs;
- unsigned int i;
- unsigned char tmp[16];
- struct himem_block_info binf;
- const char *msg = "Testing 123 hello";
-
- printf("ok, handle %u\n",h3);
-
- if (himem_sys_get_handle_info(h3,&binf)) {
- printf("Handle info:\n");
- printf(" Lock count=%u Free handles=%u Size=%luKB\n",
- (unsigned int)binf.lock_count,
- (unsigned int)binf.free_handles,
- (unsigned long)binf.block_length_kb);
- }
- else {
- printf("Cannot get handle info\n");
- }
-
-#if TARGET_MSDOS == 32
- if (!himem_sys_move(h3,0,0/*conventional memory*/,(unsigned long)(msg),16))
-#else
- if (!himem_sys_move(h3,0,0/*conventional memory*/,((unsigned long)FP_SEG(msg) << 4UL) + (unsigned long)FP_OFF(msg),sizeof(tmp)))
-#endif
- printf("Copy didn't work\n");
-
- for (i=0;i < 16;i += 2) {
- tmp[i+0] = 0x55;
- tmp[i+1] = 0xAA;
- }
-
-#if TARGET_MSDOS == 32
- if (!himem_sys_move(0/*conventional memory*/,(unsigned long)(tmp),h3,0,16))
-#else
- if (!himem_sys_move(0/*conventional memory*/,((unsigned long)FP_SEG(tmp) << 4UL) + (unsigned long)FP_OFF(tmp),h3,0,sizeof(tmp)))
-#endif
- printf("Copy didn't work\n");
-
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- printf("\n");
-
- ofs = himem_sys_lock(h3);
- if (ofs != 0UL) {
- printf(" - Locked: Physical memory address 0x%08lX\n",(unsigned long)ofs);
- if (!himem_sys_unlock(h3)) printf(" - Cannot unlock\n");
- }
- else {
- printf(" - Cannot lock\n");
- }
-
- printf("now resizing to 144MB\n");
- if (himem_sys_realloc(h3,144UL*1024UL)) {
- if (himem_sys_get_handle_info(h3,&binf)) {
- printf("Handle info:\n");
- printf(" Lock count=%u Free handles=%u Size=%luKB\n",
- (unsigned int)binf.lock_count,
- (unsigned int)binf.free_handles,
- (unsigned long)binf.block_length_kb);
- }
- else {
- printf("Cannot get handle info\n");
- }
-
-#if TARGET_MSDOS == 32
- if (!himem_sys_move(0/*conventional memory*/,(unsigned long)(tmp),h3,0,16))
-#else
- if (!himem_sys_move(0/*conventional memory*/,((unsigned long)FP_SEG(tmp) << 4UL) + (unsigned long)FP_OFF(tmp),h3,0,sizeof(tmp)))
-#endif
- printf("Copy didn't work\n");
-
- for (i=0;i < 16;i++) printf("%02x ",tmp[i]);
- printf("\n");
-
- ofs = himem_sys_lock(h3);
- if (ofs != 0UL) {
- printf(" - Locked: Physical memory address 0x%08lX\n",(unsigned long)ofs);
- if (!himem_sys_unlock(h3)) printf(" - Cannot unlock\n");
- }
- else {
- printf(" - Cannot lock\n");
- }
- }
- else {
- printf(" - Cannot realloc\n");
- }
-
- if (!himem_sys_free(h3)) printf(" - Free failed\n");
- }
- else printf("failed\n");
- }
- else {
- printf("HIMEM.SYS not found\n");
- }
-
- return 0;
-}
-
+++ /dev/null
-/* tstlp.c
- *
- * Test program: DOS memory map awareness library
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-
-#if TARGET_MSDOS == 32
-uint16_t cpu_read_my_cs() {
- uint16_t r=0;
-
- __asm {
- push cs
- pop ax
- mov r,ax
- }
-
- return r;
-}
-#endif
-
-int main() {
-#if TARGET_MSDOS == 32
- uint16_t sg;
- int c;
-#endif
-
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (detect_dosbox_emu())
- printf("I am also running under DOSBox\n");
-
-#if TARGET_MSDOS == 16
- /* TODO: Someday the dos_ltp() code will work in 16-bit mode, for environments like EMM386.EXE v86 or from within
- * the 16-bit Windows 3.1 world */
- printf("This program is intended to test memory mapping under 32-bit protected mode and does not apply to 16-bit real mode\n");
-#else
- if (!dos_ltp_probe()) {
- printf("DOS linear->physical translation probe failed\n");
- return 1;
- }
-
- sg = cpu_read_my_cs();
- printf("Results:\n");
- printf(" Paging: %u (CPU paging enabled)\n",dos_ltp_info.paging);
- printf(" DOS remap: %u (memory below 1MB is remapped, not 1:1)\n",dos_ltp_info.dos_remap);
- printf(" Should lock pages: %u (Extender may page to disk or move pages)\n",dos_ltp_info.should_lock_pages);
- printf(" Can't xlate: %u (No way to determine physical mem addr)\n",dos_ltp_info.cant_xlate);
- printf(" Using PAE: %u (DOS extender is using PAE)\n",dos_ltp_info.using_pae);
- printf(" DMA DOS xlate: %u (DMA is translated too, virtualized)\n",dos_ltp_info.dma_dos_xlate);
- printf(" use VCPI xlate: %u (VCPI server can provide translation)\n",dos_ltp_info.vcpi_xlate);
- printf(" CR0: 0x%08lx\n",dos_ltp_info.cr0);
- printf(" CR3: 0x%08lx\n",dos_ltp_info.cr3);
- printf(" CR4: 0x%08lx\n",dos_ltp_info.cr4);
- printf(" CS: 0x%04x %s CPL=%u\n",(unsigned int)sg,sg & 4 ? "LDT" : "GDT",sg&3);
-
- while ((c=getch()) != 13) {
- if (c == 27) return 1;
- }
-
- {
- uint32_t l;
- uint64_t p;
- int line=0;
-
- printf("Map test (32MB):\n");
- for (l=0;l < (32UL << 20UL);l += 4096) {
- printf("0x%08lX: ",l); fflush(stdout);
- p = dos_linear_to_phys(l);
- if (p == DOS_LTP_FAILED) printf("N/A\n");
- else printf("0x%08llX\n",p);
-
- if (++line >= 24) {
- line -= 24;
- while ((c=getch()) != 13) {
- if (c == 27) return 1;
- }
- }
- }
- }
-#endif
-
- return 0;
-}
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-/* Watcom C does not provide getvect/setvect for Win16, so we abuse the DPMI server within and provide one anyway */
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-void far *win16_getexhandler(unsigned char n) {
- unsigned short s=0,o=0;
-
- __asm {
- mov ax,0x202
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,dx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int win16_setexhandler(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x),o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x203
- mov bl,n
- mov cx,s
- mov dx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-void far *win16_getvect(unsigned char n) {
- unsigned short s=0,o=0;
-
- __asm {
- mov ax,0x204
- mov bl,n
- xor cx,cx
- xor dx,dx
- int 31h
- mov s,cx
- mov o,dx
- }
-
- return MK_FP(s,o);
-}
-
-/* NTS: This only allows for exception interrupts 0x00-0x1F */
-int win16_setvect(unsigned char n,void far *x) {
- unsigned short s=FP_SEG(x),o=FP_OFF(x);
- int c=1;
-
- __asm {
- mov ax,0x205
- mov bl,n
- mov cx,s
- mov dx,o
- int 31h
- jnc ok
- mov c,0
-ok:
- }
-
- return c;
-}
-
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 16
-
-/* if provided by the system, these functions allow library and application code to call out to the Win32 world from Win16.
- * Which is absolutely necessary given that Win16 APIs tend to lie for compatibility reasons. */
-
-DWORD genthunk32w_ntdll = 0;
-DWORD genthunk32w_kernel32 = 0;
-DWORD genthunk32w_kernel32_GetVersion = 0;
-DWORD genthunk32w_kernel32_GetVersionEx = 0;
-DWORD genthunk32w_kernel32_GetLastError = 0;
-BOOL __GenThunksExist = 0;
-BOOL __GenThunksChecked = 0;
-DWORD (PASCAL FAR *__LoadLibraryEx32W)(LPCSTR lpName,DWORD reservedhfile,DWORD dwFlags) = NULL;
-BOOL (PASCAL FAR *__FreeLibrary32W)(DWORD hinst) = NULL;
-DWORD (PASCAL FAR *__GetProcAddress32W)(DWORD hinst,LPCSTR name) = NULL;
-DWORD (PASCAL FAR *__GetVDMPointer32W)(LPVOID ptr,UINT mask) = NULL;
-DWORD (PASCAL FAR *__CallProc32W)(DWORD procaddr32,DWORD convertMask,DWORD params,...) = NULL; /* <- FIXME: How to use? */
-DWORD (_cdecl _far *__CallProcEx32W)(DWORD params,DWORD convertMask,DWORD procaddr32,...) = NULL;
-
-int genthunk32_init() {
- if (!__GenThunksChecked) {
- HMODULE kern32;
-
- genthunk32_free();
- __GenThunksExist = 0;
- __GenThunksChecked = 1;
- kern32 = GetModuleHandle("KERNEL");
- if (kern32 != NULL) {
- __LoadLibraryEx32W = (void far*)GetProcAddress(kern32,"LOADLIBRARYEX32W");
- __FreeLibrary32W = (void far*)GetProcAddress(kern32,"FREELIBRARY32W");
- __GetProcAddress32W = (void far*)GetProcAddress(kern32,"GETPROCADDRESS32W");
- __GetVDMPointer32W = (void far*)GetProcAddress(kern32,"GETVDMPOINTER32W");
- __CallProcEx32W = (void far*)GetProcAddress(kern32,"_CALLPROCEX32W"); /* <- Hey thanks Microsoft
- maybe if your docs mentioned
- the goddamn underscore I would
- have an easier time linking to it */
- __CallProc32W = (void far*)GetProcAddress(kern32,"CALLPROC32W");
-
- if (__LoadLibraryEx32W && __FreeLibrary32W && __GetProcAddress32W && __GetVDMPointer32W &&
- __CallProc32W && __CallProcEx32W) {
- __GenThunksExist = 1;
-
- genthunk32w_kernel32 = __LoadLibraryEx32W("KERNEL32.DLL",0,0);
- if (genthunk32w_kernel32 != 0) {
- genthunk32w_kernel32_GetVersion =
- __GetProcAddress32W(genthunk32w_kernel32,"GetVersion");
- genthunk32w_kernel32_GetVersionEx =
- __GetProcAddress32W(genthunk32w_kernel32,"GetVersionExA");
- genthunk32w_kernel32_GetLastError =
- __GetProcAddress32W(genthunk32w_kernel32,"GetLastError");
- }
-
- genthunk32w_ntdll = __LoadLibraryEx32W("NTDLL.DLL",0,0);
- }
- }
- }
-
- return __GenThunksExist;
-}
-
-void genthunk32_free() {
- genthunk32w_kernel32_GetVersion = 0;
- genthunk32w_kernel32_GetVersionEx = 0;
- genthunk32w_kernel32_GetLastError = 0;
- if (genthunk32w_kernel32) {
- __FreeLibrary32W(genthunk32w_kernel32);
- genthunk32w_kernel32 = 0;
- }
-}
-
-#endif
-
+++ /dev/null
-/* dos.c
- *
- * Code to detect the surrounding DOS/Windows environment and support routines to work with it
- * (C) 2009-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-#endif
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/dosntvdm.h>
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386)
-
-/* this library of code deals with the problem of getting ordinal-only exported functions out of KERNEL32.DLL in
- * Windows 9x/ME. GetProcAddress() won't do it for us, so instead, we forcibly read it out from memory ourself.
- * That's what you get for being a jack-ass about Win16 compatibility Microsoft */
-
-/* Note that this code would work under Windows 9x/ME and NT/2000/XP, but it is only needed for 9x/ME.
- * Windows XP SP2 and later change the handle slightly to try and confuse code like this (they take the HANDLE
- * value of the module and set the least significant bit), and I have reason to believe Microsoft will eventually
- * outright change the interface to make the handle an actual opaque handle someday (while of course making it
- * utterly impossible for programs like us to get to the API functions we need to do our fucking job). Because they're
- * Microsoft, and that's what they do with the Windows API. */
-
-/* How to use: Use the 32-bit GetModuleHandle() function to get the HMODULE value. In Windows so far, this HMODULE
- * value is literally the linear memory address where Windows loaded (or mapped) the base of the DLL image, complete
- * with MS-DOS header and PE image. This hack relies on that to then traverse the PE structure directly and forcibly
- * retrieve from the ordinal export table the function we desire. */
-
-/* returns: DWORD* pointer to PE image's export ordinal table, *entries is filled with the number of entries, *base
- * is filled with the ordinal number of the first entry. */
-
-static IMAGE_NT_HEADERS *Win32ValidateHModuleMSDOS_PE_Header(BYTE *p) {
- if (!memcmp(p,"MZ",2)) {
- /* then at offset 0x3C there should be the offset to the PE header */
- DWORD offset = *((DWORD*)(p+0x3C));
- if (offset < 0x40 || offset > 0x10000) return NULL;
- p += offset;
- if (IsBadReadPtr(p,4096)) return NULL;
- if (!memcmp(p,"PE\0\0",4)) {
- /* wait, before we celebrate, make sure it's sane! */
- IMAGE_NT_HEADERS *pp = (IMAGE_NT_HEADERS*)p;
-
- if (pp->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
- return NULL;
- if (pp->FileHeader.SizeOfOptionalHeader < 88) /* <- FIXME */
- return NULL;
- if (pp->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
- return NULL;
-
- return pp;
- }
- }
-
- return NULL;
-}
-
-static IMAGE_DATA_DIRECTORY *Win32GetDataDirectory(IMAGE_NT_HEADERS *p) {
- return p->OptionalHeader.DataDirectory;
-}
-
-DWORD *Win32GetExportOrdinalTable(HMODULE mod,DWORD *entries,DWORD *base,DWORD *base_addr) {
- IMAGE_EXPORT_DIRECTORY *exdir;
- IMAGE_DATA_DIRECTORY *dir;
- IMAGE_NT_HEADERS *ptr;
-
- /* Hack for Windows XP SP2: Clear the LSB, the OS sets it for some reason */
- mod = (HMODULE)((DWORD)mod & 0xFFFFF000UL);
- /* reset vars */
- *entries = *base = 0;
- if (mod == NULL) return NULL;
-
- /* the module pointer should point an image of the DLL in memory. Right at the pointer we should see
- * the letters "MZ" and the MS-DOS stub EXE header */
- ptr = Win32ValidateHModuleMSDOS_PE_Header((BYTE*)mod);
- if (ptr == NULL) return NULL;
-
- /* OK, now locate the Data Directory. The number of entries is in ptr->OptionalHeader.NumberOfRvaAndSizes */
- dir = Win32GetDataDirectory(ptr);
- if (ptr == NULL) return NULL;
-
- /* the first directory is the Export Address Table */
- exdir = (IMAGE_EXPORT_DIRECTORY*)((DWORD)mod + (DWORD)dir->VirtualAddress);
- if (IsBadReadPtr(exdir,2048)) return NULL;
-
- *base = exdir->Base;
- *entries = exdir->NumberOfFunctions;
- *base_addr = (DWORD)mod;
- return (DWORD*)((DWORD)mod + exdir->AddressOfFunctions);
-}
-
-int Win32GetOrdinalLookupInfo(HMODULE mod,Win32OrdinalLookupInfo *info) {
- DWORD *x = Win32GetExportOrdinalTable(mod,&info->entries,&info->base,&info->base_addr);
- if (x == NULL) return 0;
- info->table = x;
- return 1;
-}
-
-void *Win32GetOrdinalAddress(Win32OrdinalLookupInfo *nfo,unsigned int ord) {
- if (nfo == NULL || nfo->table == NULL) return NULL;
- if (ord < nfo->base) return NULL;
- if (ord >= (nfo->base+nfo->entries)) return NULL;
- return (void*)((char*)nfo->table[ord-nfo->base] + nfo->base_addr);
-}
-#endif
-
+++ /dev/null
-/* winfcon.c
- *
- * Fake console for Windows applications where a console is not available.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- *
- * This code allows the DOS/CPU test code to print to a console despite the
- * fact that Windows 3.0/3.1 and Win32s do not provide a console. For this
- * code to work, the program must include specific headers and #define a
- * macro. The header will then redefine various standard C functions to
- * redirect their use into this program. This code is not used for targets
- * that provide a console.
- */
-
-#ifdef TARGET_WINDOWS
-# include <windows.h>
-# include <windows/apihelp.h>
-#else
-# error what
-#endif
-
-#include <setjmp.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <conio.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/winfcon.h>
-
-#ifdef WIN_STDOUT_CONSOLE
-
-/* _export is not valid for Win32. this silences a Watcom linker warning */
-#if TARGET_MSDOS == 32
-# define winproc_export
-#else
-# define winproc_export _export
-#endif
-
-#undef read
-#undef write
-#undef getch
-#undef isatty
-
-#define KBSIZE 256
-
-static char _win_WindowProcClass[128];
-
-/* If we stick all these variables in the data segment and reference
- * them directly, then we'll work from a single instance, but run into
- * problems with who's data segment to use once we run in multiple
- * instances. The problem, is that when an application creates a
- * window of our class, the Window Proc is not guaranteed to be called
- * with our DS segment/selector. In fact, it often seems to be the
- * data segment of the first instance by which the window class was
- * created. And under Windows 3.0, unless you used __loadds and
- * MakeProcInstance, the DS segment could be any random segment
- * that happened to be there when you were called.
- *
- * Our Window Proc below absolves itself of these problems by storing
- * the pointer to the context in the Window data associated with the
- * window (GetWindowLong/SetWindowLong), then using only that context
- * pointer for maintaining itself.
- *
- * This DS segment limitation only affects the Window procedure and
- * any functions called by the Window procedure. Other parts, like
- * WinMain, do not have to worry about whether DS is correct and the
- * data segment will always be the current instance running.
- *
- * Note that the above limitations are only an issue for the Win16
- * world. The Win32 world is free from this hell and so we only
- * have to maintain one context structure. */
-typedef struct _win_console_ctx {
- char console[80*25];
- char _win_kb[KBSIZE];
- int conHeight,conWidth;
- int _win_kb_i,_win_kb_o;
- int monoSpaceFontHeight;
-#if TARGET_MSDOS == 32 && defined(WIN386)
- short int monoSpaceFontWidth;
-#else
- int monoSpaceFontWidth;
-#endif
- HFONT monoSpaceFont;
- int pendingSigInt;
- int userReqClose;
- int allowClose;
- int conX,conY;
- jmp_buf exit_jmp;
- HWND hwndMain;
- int myCaret;
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
- WORD my_ds;
-#endif
-};
-
-HINSTANCE _win_hInstance;
-static struct _win_console_ctx _this_console;
-static char temprintf[1024];
-
-#if TARGET_MSDOS == 32 && defined(WIN386)
-# define USER_GWW_CTX 0
-# define USER_GWW_MAX 6
-#elif TARGET_MSDOS == 16
-# define USER_GWW_CTX 0
-# define USER_GWW_MAX 4
-#else
-# define USER_GWW_MAX 0
-#endif
-#define USER_GCW_MAX 0
-
-HWND _win_hwnd() {
- return _this_console.hwndMain;
-}
-
-int _win_kb_insert(struct _win_console_ctx FAR *ctx,char c) {
- if ((ctx->_win_kb_i+1)%KBSIZE == ctx->_win_kb_o) {
- MessageBeep(-1);
- return -1;
- }
-
- ctx->_win_kb[ctx->_win_kb_i] = c;
- if (++ctx->_win_kb_i >= KBSIZE) ctx->_win_kb_i = 0;
- return 0;
-}
-
-void _win_sigint() {
- void (*sig)(int x) = signal(SIGINT,SIG_DFL);
- if (sig != SIG_IGN && sig != SIG_DFL) sig(SIGINT);
- signal(SIGINT,sig);
- if (sig == SIG_DFL) longjmp(_this_console.exit_jmp,1);
-}
-
-void _win_sigint_post(struct _win_console_ctx FAR *ctx) {
- /* because doing a longjmp() out of a Window proc is very foolish */
- ctx->pendingSigInt = 1;
-}
-
-#if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
-FARPROC _win_WindowProc_MPI;
-#endif
-/* NTS: Win16 only: DS (data segment) is NOT necessarily the data segment of the instance
- * that spawned the window! Any attempt to access local variables will likely refer
- * to the copy in the first instance */
-/* NTS: All code in this routine deliberately does not refer to the local data segment, unless it
- * has to (which it does through the segment value in the context). This reduces problems with
- * the screwy callback design in Windows 3.0/3.1. */
-/* NTS: Do NOT use __loadds on this function prototype. It will seem to work, but because __loadds
- * reloads the (cached) instance data segment it will cause all instances to crash when you
- * spawn multiple instances and then close the first one you spawned. NOT using __loadds
- * removes that crash. */
-WindowProcType_NoLoadDS winproc_export _win_WindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam) {
-#if TARGET_MSDOS == 32 && defined(WIN386)
- struct _win_console_ctx FAR *_ctx_console;
- {
- unsigned short s = GetWindowWord(hwnd,USER_GWW_CTX);
- unsigned int o = GetWindowLong(hwnd,USER_GWW_CTX+2);
- _ctx_console = (void far *)MK_FP(s,o);
- }
- if (_ctx_console == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
-#elif TARGET_MSDOS == 16
- struct _win_console_ctx FAR *_ctx_console;
- _ctx_console = (void far *)GetWindowLong(hwnd,USER_GWW_CTX);
- if (_ctx_console == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
-#else
-# define _ctx_console (&_this_console)
-#endif
-
- if (message == WM_GETMINMAXINFO) {
-#if TARGET_MSDOS == 32 && defined(WIN386) /* Watcom Win386 does NOT translate LPARAM for us */
- MINMAXINFO FAR *mm = (MINMAXINFO FAR*)win386_help_MapAliasToFlat(lparam);
- if (mm == NULL) return DefWindowProc(hwnd,message,wparam,lparam);
-#else
- MINMAXINFO FAR *mm = (MINMAXINFO FAR*)(lparam);
-#endif
- mm->ptMaxSize.x = (_ctx_console->monoSpaceFontWidth * _ctx_console->conWidth) +
- (2 * GetSystemMetrics(SM_CXFRAME));
- mm->ptMaxSize.y = (_ctx_console->monoSpaceFontHeight * _ctx_console->conHeight) +
- (2 * GetSystemMetrics(SM_CYFRAME)) + GetSystemMetrics(SM_CYCAPTION);
- mm->ptMinTrackSize.x = mm->ptMaxSize.x;
- mm->ptMinTrackSize.y = mm->ptMaxSize.y;
- mm->ptMaxTrackSize.x = mm->ptMaxSize.x;
- mm->ptMaxTrackSize.y = mm->ptMaxSize.y;
- return 0;
- }
- else if (message == WM_CLOSE) {
- if (_ctx_console->allowClose) DestroyWindow(hwnd);
- else _win_sigint_post(_ctx_console);
- _ctx_console->userReqClose = 1;
- }
- else if (message == WM_DESTROY) {
- _ctx_console->allowClose = 1;
- _ctx_console->userReqClose = 1;
- if (_ctx_console->myCaret) {
- HideCaret(hwnd);
- DestroyCaret();
- _ctx_console->myCaret = 0;
- }
-
- PostQuitMessage(0);
- _ctx_console->hwndMain = NULL;
- return 0; /* OK */
- }
- else if (message == WM_SETCURSOR) {
- if (LOWORD(lparam) == HTCLIENT) {
- SetCursor(LoadCursor(NULL,IDC_ARROW));
- return 1;
- }
- else {
- return DefWindowProc(hwnd,message,wparam,lparam);
- }
- }
- else if (message == WM_ACTIVATE) {
- if (wparam) {
- if (!_ctx_console->myCaret) {
- CreateCaret(hwnd,NULL,_ctx_console->monoSpaceFontWidth,_ctx_console->monoSpaceFontHeight);
- SetCaretPos(_ctx_console->conX * _ctx_console->monoSpaceFontWidth,
- _ctx_console->conY * _ctx_console->monoSpaceFontHeight);
- ShowCaret(hwnd);
- _ctx_console->myCaret = 1;
- }
- }
- else {
- if (_ctx_console->myCaret) {
- HideCaret(hwnd);
- DestroyCaret();
- _ctx_console->myCaret = 0;
- }
- }
-
- /* BUGFIX: Microsoft Windows 3.1 SDK says "return 0 if we processed the message".
- * Yet if we actually do, we get funny behavior. Like if I minimize another
- * application's window and then activate this app again, every keypress
- * causes Windows to send WM_SYSKEYDOWN/WM_SYSKEYUP. Somehow passing it
- * down to DefWindowProc() solves this. */
- return DefWindowProc(hwnd,message,wparam,lparam);
- }
- else if (message == WM_CHAR) {
- if (wparam > 0 && wparam <= 126) {
- if (wparam == 3) {
- /* CTRL+C */
- if (_ctx_console->allowClose) DestroyWindow(hwnd);
- else _win_sigint_post(_ctx_console);
- }
- else {
- _win_kb_insert(_ctx_console,(char)wparam);
- }
- }
- }
- else if (message == WM_ERASEBKGND) {
- RECT um;
-
- if (GetUpdateRect(hwnd,&um,FALSE)) {
- HBRUSH oldBrush,newBrush;
- HPEN oldPen,newPen;
-
- newPen = (HPEN)GetStockObject(NULL_PEN);
- newBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
-
- oldPen = SelectObject((HDC)wparam,newPen);
- oldBrush = SelectObject((HDC)wparam,newBrush);
-
- Rectangle((HDC)wparam,um.left,um.top,um.right+1,um.bottom+1);
-
- SelectObject((HDC)wparam,oldBrush);
- SelectObject((HDC)wparam,oldPen);
- }
-
- return 1; /* Important: Returning 1 signals to Windows that we processed the message. Windows 3.0 gets really screwed up if we don't! */
- }
- else if (message == WM_PAINT) {
- RECT um;
-
- if (GetUpdateRect(hwnd,&um,TRUE)) {
- PAINTSTRUCT ps;
- HFONT of;
- int y;
-
- BeginPaint(hwnd,&ps);
- SetBkMode(ps.hdc,OPAQUE);
- SetBkColor(ps.hdc,RGB(255,255,255));
- SetTextColor(ps.hdc,RGB(0,0,0));
- of = (HFONT)SelectObject(ps.hdc,_ctx_console->monoSpaceFont);
- for (y=0;y < _ctx_console->conHeight;y++) {
- TextOut(ps.hdc,0,y * _ctx_console->monoSpaceFontHeight,
- _ctx_console->console + (_ctx_console->conWidth * y),
- _ctx_console->conWidth);
- }
- SelectObject(ps.hdc,of);
- EndPaint(hwnd,&ps);
- }
-
- return 0; /* Return 0 to signal we processed the message */
- }
- else {
- return DefWindowProc(hwnd,message,wparam,lparam);
- }
-
- return 0;
-}
-
-int _win_kbhit() {
- _win_pump();
- return _this_console._win_kb_i != _this_console._win_kb_o;
-}
-
-int _win_getch() {
- do {
- if (_win_kbhit()) {
- int c = (int)((unsigned char)_this_console._win_kb[_this_console._win_kb_o]);
- if (++_this_console._win_kb_o >= KBSIZE) _this_console._win_kb_o = 0;
- return c;
- }
-
- _win_pump_wait();
- } while (1);
-
- return -1;
-}
-
-int _win_kb_read(char *p,int sz) {
- int cnt=0;
-
- while (sz-- > 0)
- *p++ = _win_getch();
-
- return cnt;
-}
-
-int _win_kb_write(const char *p,int sz) {
- int cnt=0;
-
- while (sz-- > 0)
- _win_putc(*p++);
-
- return cnt;
-}
-
-int _win_read(int fd,void *buf,int sz) {
- if (fd == 0) return _win_kb_read((char*)buf,sz);
- else if (fd == 1 || fd == 2) return -1;
- else return read(fd,buf,sz);
-}
-
-int _win_write(int fd,const void *buf,int sz) {
- if (fd == 0) return -1;
- else if (fd == 1 || fd == 2) return _win_kb_write(buf,sz);
- else return write(fd,buf,sz);
-}
-
-int _win_isatty(int fd) {
- if (fd == 0 || fd == 1 || fd == 2) return 1; /* we're emulating one, so, yeah */
- return isatty(fd);
-}
-
-void _win_pump_wait() {
- MSG msg;
-
- if (GetMessage(&msg,NULL,0,0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
-
- if (_this_console.pendingSigInt) {
- _this_console.pendingSigInt = 0;
- _win_sigint();
- }
-}
-
-void _win_pump() {
- MSG msg;
-
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
- /* Hack: Windows has this nice "GetTickCount()" function that has serious problems
- * maintaining a count if we don't process the message pump! Doing this
- * prevents portions of this code from getting stuck in infinite loops
- * waiting for the damn timer to advance. Note that this is a serious
- * problem that only plagues Windows 3.1 and earlier. Windows 95 doesn't
- * have this problem. */
- PostMessage(_this_console.hwndMain,WM_USER,0,0);
-#endif
- if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
- do {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- } while (PeekMessage(&msg,NULL,0,0,PM_REMOVE));
- }
-
- if (_this_console.pendingSigInt) {
- _this_console.pendingSigInt = 0;
- _win_sigint();
- }
-}
-
-void _win_update_cursor() {
- if (_this_console.myCaret)
- SetCaretPos(_this_console.conX * _this_console.monoSpaceFontWidth,
- _this_console.conY * _this_console.monoSpaceFontHeight);
-}
-
-void _win_redraw_line_row() {
- if (_this_console.conY >= 0 && _this_console.conY < _this_console.conHeight) {
- HDC hdc = GetDC(_this_console.hwndMain);
- HFONT of;
-
- SetBkMode(hdc,OPAQUE);
- SetBkColor(hdc,RGB(255,255,255));
- SetTextColor(hdc,RGB(0,0,0));
- of = (HFONT)SelectObject(hdc,_this_console.monoSpaceFont);
- if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
- TextOut(hdc,0,_this_console.conY * _this_console.monoSpaceFontHeight,
- _this_console.console + (_this_console.conWidth * _this_console.conY),_this_console.conWidth);
- if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
- SelectObject(hdc,of);
- ReleaseDC(_this_console.hwndMain,hdc);
- }
-}
-
-void _win_redraw_line_row_partial(int x1,int x2) {
- if (x1 >= x2) return;
-
- if (_this_console.conY >= 0 && _this_console.conY < _this_console.conHeight) {
- HDC hdc = GetDC(_this_console.hwndMain);
- HFONT of;
-
- SetBkMode(hdc,OPAQUE);
- SetBkColor(hdc,RGB(255,255,255));
- SetTextColor(hdc,RGB(0,0,0));
- of = (HFONT)SelectObject(hdc,_this_console.monoSpaceFont);
- if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
- TextOut(hdc,x1 * _this_console.monoSpaceFontWidth,_this_console.conY * _this_console.monoSpaceFontHeight,
- _this_console.console + (_this_console.conWidth * _this_console.conY) + x1,x2 - x1);
- if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
- SelectObject(hdc,of);
- ReleaseDC(_this_console.hwndMain,hdc);
- }
-}
-
-void _win_scrollup() {
- HDC hdc = GetDC(_this_console.hwndMain);
- if (_this_console.myCaret) HideCaret(_this_console.hwndMain);
- BitBlt(hdc,0,0,_this_console.conWidth * _this_console.monoSpaceFontWidth,
- _this_console.conHeight * _this_console.monoSpaceFontHeight,hdc,
- 0,_this_console.monoSpaceFontHeight,SRCCOPY);
- if (_this_console.myCaret) ShowCaret(_this_console.hwndMain);
- ReleaseDC(_this_console.hwndMain,hdc);
-
- memmove(_this_console.console,_this_console.console+_this_console.conWidth,
- (_this_console.conHeight-1)*_this_console.conWidth);
- memset(_this_console.console+((_this_console.conHeight-1)*_this_console.conWidth),
- ' ',_this_console.conWidth);
-}
-
-void _win_newline() {
- _this_console.conX = 0;
- if ((_this_console.conY+1) == _this_console.conHeight) {
- _win_redraw_line_row();
- _win_scrollup();
- _win_redraw_line_row();
- _win_update_cursor();
- _gdi_pause();
- }
- else {
- _win_redraw_line_row();
- _this_console.conY++;
- }
-}
-
-/* write to the console. does NOT redraw the screen unless we get a newline or we need to scroll up */
-void _win_putc(char c) {
- if (c == 10) {
- _win_newline();
- }
- else if (c == 13) {
- _this_console.conX = 0;
- _win_redraw_line_row();
- _win_update_cursor();
- _gdi_pause();
- }
- else {
- if (_this_console.conX < _this_console.conWidth)
- _this_console.console[(_this_console.conY*_this_console.conWidth)+_this_console.conX] = c;
- if (++_this_console.conX == _this_console.conWidth)
- _win_newline();
- }
-}
-
-size_t _win_printf(const char *fmt,...) {
- int fX = _this_console.conX;
- va_list va;
- char *t;
-
- va_start(va,fmt);
- vsnprintf(temprintf,sizeof(temprintf)-1,fmt,va);
- va_end(va);
-
- t = temprintf;
- if (*t != 0) {
- while (*t != 0) {
- if (*t == 13 || *t == 10) fX = 0;
- _win_putc(*t++);
- }
- if (fX <= _this_console.conX) _win_redraw_line_row_partial(fX,_this_console.conX);
- _win_update_cursor();
- }
-
- _win_pump();
- return 0;
-}
-
-/* HACK: I don't know if real systems do this or QEMU is doing something wrong, but apparently if a program
- * rapidly prints a lot of text under Windows 3.1 (like the RDTSC test program) it can cause the GDI
- * to become 100% focused on TextOut() to the point not even the cursor updates when you move it, and
- * keyboard events to become severely stalled. Our solution to this problem is to see if we're running
- * under Windows 3.1 or earlier, and if so, purposely slow down our output with a software delay */
-void _gdi_pause() {
-#if defined(TARGET_WINDOWS)
-# if TARGET_MSDOS == 32 && defined(WIN386)
-# else
- const DWORD ConDelay = 16UL; /* 16ms */
-# endif
-#endif
-
-#if defined(TARGET_WINDOWS)
- if (windows_mode != WINDOWS_NT) {
-# if TARGET_MSDOS == 32 && defined(WIN386)
- /* nothing */
-# else
-# if TARGET_MSDOS == 16
- if (ToolHelpInit()) {
- DWORD base,m;
- TIMERINFO ti;
- ti.dwSize = sizeof(ti);
- if (__TimerCount(&ti)) {
- base = ti.dwmsSinceStart;
-
- do {
- Yield();
- _win_pump();
- if (!__TimerCount(&ti)) break;
- m = ti.dwmsSinceStart;
- } while ((m - base) < ConDelay);
- }
- }
- else {
-# else
- {
-# endif
- DWORD base,m;
-
- base = GetTickCount();
- do {
- Yield();
- _win_pump();
- m = GetTickCount();
- } while ((m - base) < ConDelay);
- }
-# endif
- }
-#endif
-}
-
-/* NOTES:
- * For Win16, programmers generally use WINAPI WinMain(...) but WINAPI is defined in such a way
- * that it always makes the function prolog return FAR. Unfortunately, when Watcom C's runtime
- * calls this function in a memory model that's compact or small, the call is made as if NEAR,
- * not FAR. To avoid a GPF or crash on return, we must simply declare it PASCAL instead. */
-int PASCAL _win_main_con_entry(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow,int (_cdecl *_main_f)(int argc,char**,char**)) {
- WNDCLASS wnd;
- MSG msg;
-
- _win_hInstance = hInstance;
- snprintf(_win_WindowProcClass,sizeof(_win_WindowProcClass),"_HW_DOS_WINFCON_%lX",(DWORD)hInstance);
-#if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
- _win_WindowProc_MPI = MakeProcInstance((FARPROC)_win_WindowProc,hInstance);
-#endif
-
- /* clear the console */
- memset(&_this_console,0,sizeof(_this_console));
- memset(_this_console.console,' ',sizeof(_this_console.console));
- _this_console._win_kb_i = _this_console._win_kb_o = 0;
- _this_console.conHeight = 25;
- _this_console.conWidth = 80;
- _this_console.conX = 0;
- _this_console.conY = 0;
-#if TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && defined(WIN386))
- {
- WORD s=0;
-
- __asm {
- mov ax,ds
- mov s,ax
- }
- _this_console.my_ds = s;
- }
-#endif
-
- /* we need to know at this point what DOS/Windows combination we're running under */
- probe_dos();
- detect_windows();
-
- /* we want each instance to have it's own WNDCLASS, even though Windows (Win16) considers them all instances
- * coming from the same HMODULE. In Win32, there is no such thing as a "previous instance" anyway */
- wnd.style = CS_HREDRAW|CS_VREDRAW;
-#if ((TARGET_MSDOS == 16 && TARGET_WINDOWS < 31) || (TARGET_MSDOS == 32 && defined(WIN386)))
- wnd.lpfnWndProc = (WNDPROC)_win_WindowProc_MPI;
-#else
- wnd.lpfnWndProc = _win_WindowProc;
-#endif
- wnd.cbClsExtra = USER_GCW_MAX;
- wnd.cbWndExtra = USER_GWW_MAX;
- wnd.hInstance = hInstance;
- wnd.hIcon = NULL;
- wnd.hCursor = NULL;
- wnd.hbrBackground = NULL;
- wnd.lpszMenuName = NULL;
- wnd.lpszClassName = _win_WindowProcClass;
-
- if (!RegisterClass(&wnd)) {
- MessageBox(NULL,"Unable to register Window class","Oops!",MB_OK);
- return 1;
- }
-
-/* Use the full path of our EXE image by default */
- {
- char title[256];
-
- if (!GetModuleFileName(hInstance,title,sizeof(title)-1))
- strcpy(title,"<unknown>");
-
- _this_console.hwndMain = CreateWindow(_win_WindowProcClass,title,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,CW_USEDEFAULT,
- 100,40,
- NULL,NULL,
- hInstance,NULL);
- }
-
- if (!_this_console.hwndMain) {
- MessageBox(NULL,"Unable to create window","Oops!",MB_OK);
- return 1;
- }
-
-#if TARGET_MSDOS == 32 && defined(WIN386)
- /* our Win386 hack needs the address of our console context */
- SetWindowWord(_this_console.hwndMain,USER_GWW_CTX,(WORD)FP_SEG(&_this_console));
- SetWindowLong(_this_console.hwndMain,USER_GWW_CTX+2,(DWORD)FP_OFF(&_this_console));
-#elif TARGET_MSDOS == 16
- /* our Win16 hack needs the address of our console context */
- SetWindowLong(_this_console.hwndMain,USER_GWW_CTX,(DWORD)(&_this_console));
-#endif
-
- /* Create the monospace font we use for terminal display */
- {
- _this_console.monoSpaceFont = CreateFont(-12,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH | FF_DONTCARE,"Terminal");
- if (!_this_console.monoSpaceFont) {
- MessageBox(NULL,"Unable to create Font","Oops!",MB_OK);
- return 1;
- }
-
- {
- HWND hwnd = GetDesktopWindow();
- HDC hdc = GetDC(hwnd);
- _this_console.monoSpaceFontHeight = 12;
- if (!GetCharWidth(hdc,'A','A',&_this_console.monoSpaceFontWidth)) _this_console.monoSpaceFontWidth = 9;
- ReleaseDC(hwnd,hdc);
- }
- }
-
- ShowWindow(_this_console.hwndMain,nCmdShow);
- UpdateWindow(_this_console.hwndMain);
- SetWindowPos(_this_console.hwndMain,HWND_TOP,0,0,
- (_this_console.monoSpaceFontWidth * _this_console.conWidth) +
- (2 * GetSystemMetrics(SM_CXFRAME)),
- (_this_console.monoSpaceFontHeight * _this_console.conHeight) +
- (2 * GetSystemMetrics(SM_CYFRAME)) + GetSystemMetrics(SM_CYCAPTION),
- SWP_NOMOVE);
-
- if (setjmp(_this_console.exit_jmp) == 0)
- _main_f(0,NULL,NULL); /* <- FIXME: We need to take the command line and generate argv[]. Also generate envp[] */
-
- if (!_this_console.userReqClose) {
- _win_printf("\n<program terminated>");
- _this_console.allowClose = 1;
- while (GetMessage(&msg,NULL,0,0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- else {
- if (IsWindow(_this_console.hwndMain)) {
- DestroyWindow(_this_console.hwndMain);
- while (GetMessage(&msg,NULL,0,0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- }
-
- DeleteObject(_this_console.monoSpaceFont);
- _this_console.monoSpaceFont = NULL;
- return 0;
-}
-#endif
-
+++ /dev/null
-/* winfcon.h
- *
- * Fake console for Windows applications where a console is not available.
- * (C) 2011-2012 Jonathan Campbell.
- * Hackipedia DOS library.
- *
- * This code is licensed under the LGPL.
- * <insert LGPL legal text here>
- */
-
-/* Windows 3.1 and earlier, even for Win32s: there is no system given console.
- * We either have to draw and maintain our own window, or find some other way to printf() and display it. */
-#if defined(TARGET_WINDOWS) && (TARGET_MSDOS == 16 || (TARGET_MSDOS == 32 && TARGET_WINDOWS == 31) || (defined(WIN386) && TARGET_MSDOS == 32))
-# define WIN_STDOUT_CONSOLE
-# define getch _win_getch
-# define kbhit _win_kbhit
-# define fprintf __XXX_TODO_fprintf
-# define printf _win_printf
-# define isatty _win_isatty
-# define write _win_write
-# define read _win_read
-
-void _win_pump();
-int _win_kbhit();
-int _win_getch();
-HWND _win_hwnd();
-void _gdi_pause();
-void _win_pump_wait();
-void _win_putc(char c);
-int _win_isatty(int fd);
-int _win_read(int fd,void *buf,int sz);
-size_t _win_printf(const char *fmt,...);
-int _win_write(int fd,const void *buf,int sz);
-int _cdecl main(int argc,char **argv,char **envp);
-int PASCAL _win_main_con_entry(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow,int (_cdecl *_main_f)(int argc,char**,char**));
-
-extern HINSTANCE _win_hInstance;
-
-# ifdef WINFCON_STOCK_WIN_MAIN
-int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) {
- return _win_main_con_entry(hInstance,hPrevInstance,lpCmdLine,nCmdShow,main);
-}
-# endif
-
-#endif
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (FLATREAL) or / (Linux)
-NOW_BUILDING = HW_FLATREAL_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = flatreal.c
-OBJS = $(SUBDIR)$(HPS)flatreal.obj $(SUBDIR)$(HPS)flatmode.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_FLATREAL_LIB): $(OBJS)
- wlib -q -b -c $(HW_FLATREAL_LIB) -+$(SUBDIR)$(HPS)flatreal.obj -+$(SUBDIR)$(HPS)flatmode.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-FLATREAL
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-lib: $(HW_FLATREAL_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_FLATREAL_LIB) $(SUBDIR)$(HPS)test.obj $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_FLATREAL_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HPS_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_FLATREAL_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-; NTS: We use NASM to achieve our goals here because WASM sucks donkey balls
-; Maybe when they bother to implement a proper conditional macro system, I'll consider it...
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-; NTS: Associate our data with Watcom's data segment
-segment .data public align=4 class=data
-
-; NTS: Help NASM put the code segment in the right place for Watcom to link it in properly
-segment text public align=1 class=code
-
-%if TARGET_MSDOS == 16
-
-; int flatrealmode_test()
-global flatrealmode_test_
-flatrealmode_test_:
- pushf
- push ds
- push si
- push cx
-
- ; clear interrupts, to ensure IRQ 5 is not mistaken for a GP fault
- cli
-
- ; set DS=0 to carry out the test, and zero AX
- xor ax,ax
- mov ds,ax
-
- ; hook interrupt 0x0D (general protection fault and IRQ 5)
- mov si,0x0D * 4
- mov cx,[si] ; offset
- mov word [si],_flatrealmode_test_fail
- push cx
- mov cx,[si+2]
- mov word [si+2],cs
- push cx
-
- ; now try it. either we'll make it through unscathed or it will cause a GP fault and branch to our handler
- mov esi,0xFFFFFFF8
- mov esi,[esi]
-
- ; either nothing happened, or control jmp'd here from the exception handler (who also set AX=1)
- ; restore interrupt routine and clean up
-_flatrealmode_test_conclude:
- mov si,0x0D * 4
- pop cx
- mov word [si+2],cx
- pop cx
- mov word [si],cx
-
- pop cx
- pop si
- pop ds
- popf
- retnative
-_flatrealmode_test_fail:
- add sp,6 ; throw away IRETF address (IP+CS+FLAGS)
- inc ax ; make AX nonzero
- jmp short _flatrealmode_test_conclude
-
-; void __cdecl flatrealmode_force_datasel(void *ptr);
-global _flatrealmode_force_datasel
-_flatrealmode_force_datasel:
- push bp
- mov bp,sp
- pushf
- pusha
-
- mov ax,cs
- mov word [cs:_flatrealmode_force_datasel_j2_hackme+3],ax ; overwrite segment portion of JMP FAR instruction
-
-; LARGE and COMPACT memory models: a far pointer is passed onto the stack
-%ifidni MMODE,l
-%define FARPTR_
-%else
- %ifidni MMODE,c
- %define FARPTR_
- %endif
-%endif
-
-%ifdef FARPTR_
- %undef FARPTR_
- ; LARGE memory model version (we're given a FAR pointer)
- ; caller passes us the address of the constructed GDT (near ptr)
- xor esi,esi
- mov si,[bp+cdecl_param_offset]
-
- ; now convert to physical addr
- xor eax,eax
- mov ax,[bp+cdecl_param_offset+2]
- shl eax,4
- add eax,esi
-%else ; SMALL memory model version (we're given a NEAR pointer)
- ; caller passes us the address of the constructed GDT (near ptr)
- xor esi,esi
- mov si,[bp+cdecl_param_offset]
-
- ; now convert to physical addr
- xor eax,eax
- mov ax,ds
- shl eax,4
- add eax,esi
-%endif
-
- ; disable interrupts, we're going to fuck with the CPU mode and thunk into protected mode
- cli
-
- ; allocate room on the stack for the GDT and store the original GDTR
- sub sp,8
- mov bx,sp
- sgdt [bx]
-
- ; and another for the new GDT
- sub sp,8
- mov di,sp
- mov word [di],0xFF
- mov dword [di+2],eax
-
- ; load the new GDT
- lgdt [di]
-
- ; save previous segment regs
- mov bx,ds
- mov cx,es
-
- ; enable protected mode
- mov eax,cr0
- or al,1
- mov cr0,eax
-
- ; now load the segment registers
- mov ax,8 ; GDT selector value
- mov ds,ax
- mov es,ax
-
- ; force CPU to go into protected mode, clear cache
- jmp 16:word _flatrealmode_force_datasel_j1
-_flatrealmode_force_datasel_j1:
-
- ; disable protected mode
- mov eax,cr0
- and al,~1
- mov cr0,eax
-
- ; jump to force it
- ; opcode format: 0xEA <ofs> <seg>
-_flatrealmode_force_datasel_j2_hackme:
- jmp 0:word _flatrealmode_force_datasel_j2
-_flatrealmode_force_datasel_j2:
-
- ; reload sane realmode selectors
- mov ds,bx
- mov es,cx
-
- ; discard the new GDT
- add sp,8
-
- ; restore old GDT
- mov bx,sp
- lgdt [bx]
-
- ; discard old GDT
- add sp,8
-
- popa
- popf
- pop bp
- retnative
-%endif
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/emm.h>
-#include <hw/dos/doswin.h>
-#include <hw/flatreal/flatreal.h>
-
-#if TARGET_MSDOS == 16
-
-#ifndef MMODE
-#error I need to know what memory model
-#endif
-
-void __cdecl flatrealmode_force_datasel(void *ptr);
-
-int flatrealmode_setup(uint32_t limit) {
- const unsigned long segds = 0;
- uint32_t *ap;
- void *buf;
-
- /* Requires a 386 or higher. As usual, if the programmer doesn't bother to check the CPU
- * we go ahead and do it anyway */
- if (cpu_basic_level < 3)
- return 0;
-
- if (!flatrealmode_allowed())
- return 0;
-
- if (limit < 0xFFFFUL) limit = 0xFFFFUL;
- limit >>= 12UL;
-
- buf = malloc(16 + (8*3));
- if (buf == NULL) return 0;
-
-#if defined(__LARGE__) || defined(__COMPACT__) /* 16-bit large memory model */
- {
- unsigned int seg = FP_SEG(buf);
- unsigned int ofs = FP_OFF(buf);
- ofs = (ofs + 15) & (~15);
- seg += ofs >> 4;
- ofs &= 0xF;
- ap = MK_FP(seg,ofs);
- }
-#else
- ap = (uint32_t*)(((size_t)buf + 15) & (~15));
-#endif
-
- /* GDT[0] = null */
- ap[0] = ap[1] = 0;
- /* GDT[1] = 32-bit data segment */
- ap[2] = (segds << 16UL) | (limit & 0xFFFFUL);
- ap[3] = (limit & 0xF0000UL) | (0x80UL << 16UL) | (0x93UL << 8UL) | (segds >> 16UL);
- /* GDT[2] = 16-bit code segment */
- {
- void far *ptr = (void far*)flatrealmode_force_datasel;
- unsigned int seg = FP_SEG(ptr);
- unsigned long sego = (unsigned long)seg << 4UL;
-/* printf("%04x:%04x %05lx\n",seg,FP_OFF(ptr),sego); */
- ap[4] = (sego << 16UL) | 0xFFFFUL;
- ap[5] = 0xF0000UL | (0x80UL << 16UL) | (0x9BUL << 8UL) | (sego >> 16UL);
- }
-
- flatrealmode_force_datasel(ap);
-
- free(buf);
- return 1;
-}
-#endif
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/emm.h>
-#include <stdint.h>
-
-#if TARGET_MSDOS == 16
-
-unsigned char flatrealmode_readb(uint32_t addr);
-#pragma aux flatrealmode_readb = \
- ".386p" \
- "push es" \
- "xor cx,cx" \
- "mov es,cx" \
- "shl edx,16" \
- "and eax,0xFFFF" \
- "mov al,es:[eax+edx]" \
- "pop es" \
- modify [cx dx] \
- parm [dx ax] \
- value [al]
-
-uint16_t flatrealmode_readw(uint32_t addr);
-#pragma aux flatrealmode_readw = \
- ".386p" \
- "push es" \
- "xor cx,cx" \
- "mov es,cx" \
- "shl edx,16" \
- "and eax,0xFFFF" \
- "mov ax,es:[eax+edx]" \
- "pop es" \
- modify [cx dx] \
- parm [dx ax] \
- value [ax]
-
-uint32_t flatrealmode_readd(uint32_t addr);
-#pragma aux flatrealmode_readd = \
- ".386p" \
- "push es" \
- "xor cx,cx" \
- "mov es,cx" \
- "shl edx,16" \
- "and eax,0xFFFF" \
- "mov eax,es:[eax+edx]" \
- "mov edx,eax" \
- "shr edx,16" \
- "pop es" \
- modify [cx] \
- parm [dx ax] \
- value [dx ax]
-
-void flatrealmode_writeb(uint32_t addr,uint8_t c);
-#pragma aux flatrealmode_writeb = \
- ".386p" \
- "push es" \
- "xor cx,cx" \
- "mov es,cx" \
- "shl edx,16" \
- "and eax,0xFFFF" \
- "mov es:[eax+edx],bl" \
- "pop es" \
- modify [cx dx] \
- parm [dx ax] [bl]
-
-void flatrealmode_writew(uint32_t addr,uint16_t c);
-#pragma aux flatrealmode_writew = \
- ".386p" \
- "push es" \
- "xor cx,cx" \
- "mov es,cx" \
- "shl edx,16" \
- "and eax,0xFFFF" \
- "mov es:[eax+edx],bx" \
- "pop es" \
- modify [cx dx] \
- parm [dx ax] [bx]
-
-void flatrealmode_writed(uint32_t addr,uint32_t c);
-#pragma aux flatrealmode_writed = \
- ".386p" \
- "push es" \
- "push cx" \
- "xor cx,cx" \
- "mov es,cx" \
- "pop cx" \
- "shl edx,16" \
- "and eax,0xFFFF" \
- "shl ecx,16" \
- "and ebx,0xFFFF" \
- "add ebx,ecx" \
- "mov es:[eax+edx],ebx" \
- "pop es" \
- modify [bx cx dx] \
- parm [dx ax] [cx bx]
-
-int flatrealmode_setup(uint32_t limit);
-int flatrealmode_test(); /* ASM */ /* 1=flat real mode not active 0=flat real mode active */ /* FIXME: Give this a more descriptive name. It's confusing in it's current form */
-
-/* you can't do flat real mode when Windows is running. Nor can you use it when running in virtual 8086 mode (such as when EMM386.EXE is resident) */
-#define flatrealmode_allowed() (cpu_v86_active == 0 && windows_mode == WINDOWS_NONE)
-#define flatrealmode_ok() (flatrealmode_test() == 0)
-
-/* feed this constant into the setup function to enable the full 4GB range */
-#define FLATREALMODE_4GB 0xFFFFFFFFUL
-/* feed this constant into the setup function to re-impose the 64KB real-mode limit */
-#define FLATREALMODE_64KB 0x0000FFFFUL
-
-#endif /* TARGET_MSDOS == 16 */
-
-#if TARGET_MSDOS == 32
-# define flatrealmode_allowed() (0)
-# define flatrealmode_ok() (0)
-#endif
-
+++ /dev/null
-Program notes:\r
-\r
-- Flat real mode and virtual 8086 mode\r
- This code will only function correctly in pure 16-bit real mode.\r
- If virtual 8086 mode is involved, the code will disable it's functions\r
- to prevent exceptions and possible crashes from occuring.\r
-\r
-- Flat real mode and EMM386.EXE\r
- EMM386.EXE accomplishes it's trickery on 386 or higher systems by running\r
- the 16-bit DOS system under virtual 8086 mode. Programs that try to use\r
- flat real mode will crash the system and initiate a hard reset\r
- (Windows 95 and earlier) or will cause EMM386.EXE to hang the machine with\r
- a textual error message (Windows 98). To avoid this crash, the library\r
- will disable itself if EMM386.EXE is present (virtual 8086 mode detected).\r
-\r
- On Microsoft systems, if EMM386.EXE is resident, you can disable EMM\r
- functions (and v8086 mode) at runtime by typing "EMM386 OFF". You should\r
- then be able to use flat real mode without problems. Later you can type\r
- "EMM386 ON" to reenable EMM functions and v8086 mode.\r
-\r
-- Flat real mode and Microsoft Windows\r
- If the library detects that it is running in a "DOS Box" under Windows,\r
- it will disable it's functions. For the same reasons as EMM386.EXE,\r
- attempts to use Flat Real Mode will only cause an exception, which under\r
- Windows, immediately terminates the DOS Box and causes the desktop to\r
- display an error message. This applies to all versions of Windows that\r
- run in "386 enhanced mode", including "Windows 3.1 enhanced mode",\r
- Windows 95, Windows 98, Windows ME, and all NT based versions.\r
-\r
- If you are running Windows in Real or Standard Mode, where the kernel\r
- does not use v8086 mode, you might be able to use flat real mode without\r
- problems. But if you're running hardware THAT OLD you might as well just\r
- stay with pure DOS mode.\r
-\r
-- Flat real mode and certain clone CPU & Emulator situations\r
- On real Intel or AMD CPUs, attempting to do "flat real mode" style memory\r
- access will cause a real-mode exception, because you are violating the\r
- segment limits. This is why, when using the library, you must first\r
- "enable" flat real mode. On clone CPUs and certain emulators however,\r
- the CPU does not enforce segment limits. Such systems can give the\r
- programmer the false impression that his code, using the library, will\r
- run correctly. Therefore, if you want to ensure your code runs correctly\r
- in all cases, I recommend testing your program and the flat real mode\r
- library on as many systems as possible, ideally some Intel and some clone\r
- hardware.\r
-\r
+++ /dev/null
-/* Test program to demonstrate using the Flat Real Mode library.
- *
- * Interesting results:
- * - Most modern CPUs do not seem to enforce segment limits in real mode.
- * But anything prior to (about) a Pentium II will, especially if made by Intel.
- * - Most emulators seem to not enforce real mode segment limits either.
- * DOSBox and Virtual Box completely ignore limits. Bochs and Microsoft Virtual
- * PC 2007 enforce segment limits.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <conio.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/flatreal/flatreal.h>
-
-int main() {
-#if TARGET_MSDOS == 16
- cpu_probe();
- probe_dos();
- printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
- printf("I am running under Windows.\n");
- printf(" Mode: %s\n",windows_mode_str(windows_mode));
- printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
- }
- else {
- printf("Not running under Windows or OS/2\n");
- }
-
- if (flatrealmode_setup(FLATREALMODE_4GB)) {
- unsigned int i;
- unsigned char c;
- unsigned long d;
- unsigned short w;
-
- for (i=0;i < 0x40;i++) {
- c = flatrealmode_readb(0xB8000UL + (uint32_t)i);
- printf("%02X ",c);
- }
- printf("\n");
- for (i=0;i < 0x40;i++) {
- flatrealmode_writeb(0xB8000UL + (uint32_t)i,i);
- }
- while (getch() != 13);
- printf("\n");
-
- for (i=0;i < 0x40;i++) {
- w = flatrealmode_readw(0xB8000UL + (uint32_t)(i*2));
- printf("%04X ",w);
- }
- printf("\n");
- for (i=0;i < 0x40;i++) {
- flatrealmode_writew(0xB8000UL + (uint32_t)(i*2),i*0x101);
- }
- while (getch() != 13);
- printf("\n");
-
- for (i=0;i < 0x40;i++) {
- d = flatrealmode_readd(0xB8000UL + (uint32_t)(i*4));
- printf("%08lX ",(unsigned long)d);
- }
- printf("\n");
- for (i=0;i < 0x40;i++) {
- flatrealmode_writed(0xB8000UL + (uint32_t)(i*4),i*0x1010101UL);
- }
- while (getch() != 13);
-
- printf("Flat real mode testing: will your CPU GP# fault if I access beyond 64KB?\n");
-
- flatrealmode_setup(FLATREALMODE_4GB); i = flatrealmode_test();
- printf("Processor with segment limits @ 4GB, result: %d (%s)\n",i,i?"yes":"no");
-
- flatrealmode_setup(FLATREALMODE_64KB); i = flatrealmode_test();
- printf("Processor with segment limits reset to 64KB, result: %d (%s)\n",i,i?"yes":"no");
-
- flatrealmode_setup(FLATREALMODE_4GB); i = flatrealmode_test();
- printf("Processor with segment limits @ 4GB, result: %d (%s)\n",i,i?"yes":"no");
-
- flatrealmode_setup(FLATREALMODE_64KB); i = flatrealmode_test();
- printf("Processor with segment limits reset to 64KB, result: %d (%s)\n",i,i?"yes":"no");
- }
- else {
- printf("Unable to set up Flat Real Mode\n");
- }
- return 0;
-#else
- printf("Flat real mode is specific to the 16-bit real-mode builds of this suite\n");
- printf("and does not apply to 32-bit protected mode.\n");
- return 1;
-#endif
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_FLOPPY_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = floppy.c
-OBJS = $(SUBDIR)$(HPS)floppy.obj $(SUBDIR)$(HPS)floppy.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_FLOPPY_LIB): $(OBJS)
- wlib -q -b -c $(HW_FLOPPY_LIB) -+$(SUBDIR)$(HPS)floppy.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_FLOPPY_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-!ifdef TEST_EXE
-$(TEST_EXE): $(HW_FLOPPY_LIB) $(HW_FLOPPY_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(HW_8237_LIB) $(HW_8237_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_VGAGUI_LIB) $(HW_VGAGUI_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_PCI_LIB) $(HW_PCI_LIB_DEPENDENCIES) $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_FLOPPY_LIB_WLINK_LIBRARIES) $(HW_8237_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_VGAGUI_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_PCI_LIB_WLINK_LIBRARIES) $(HW_ISAPNP_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_FLOPPY_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#ifndef __DOSLIB_HW_IDE_FLOPPYLIB_H
-#define __DOSLIB_HW_IDE_FLOPPYLIB_H
-
-#endif /* __DOSLIB_HW_IDE_FLOPPYLIB_H */
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/8237/8237.h> /* DMA controller */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/dos/doswin.h>
-
-#define MAX_FLOPPY_CONTROLLER 4
-
-struct floppy_controller {
- uint16_t base_io;
- int8_t irq;
- int8_t dma;
-
- /* known state */
- uint8_t ps2_status[2]; /* 0x3F0-0x3F1 */
- uint8_t st[4]; /* ST0...ST3 */
- /* Status Register ST0 */
- /* [7:6] IC (Interrupt code) */
- /* 00 = normal termination, no errors */
- /* 01 = abnormal termination */
- /* 10 = invalid command */
- /* 11 = abnormal termination by polling */
- /* [5:5] Seek end */
- /* [4:4] Unit check */
- /* [3:3] Drive not ready */
- /* [2:2] Head currently active */
- /* [1:0] Currently selected drive */
- /* Status Register ST1 */
- /* [7:7] End of Cylinder */
- /* [6:6] always 0 */
- /* [5:5] Data error */
- /* [4:4] Time out (data overrun) */
- /* [3:3] always 0 */
- /* [2:2] No data */
- /* [1:1] Not writeable */
- /* [0:0] No address mark */
- /* Status Register ST2 */
- /* [7:7] always 0 */
- /* [6:6] Deleted Address Mark */
- /* [5:5] CRC error in data field */
- /* [4:4] Wrong Cylinder */
- /* [3:3] Seek equal */
- /* [2:2] Seek error */
- /* [1:1] Bad cylinder */
- /* [0:0] Not data address mark DAM */
- /* Status Register ST3 */
- /* [7:7] Error, drive error signal is active */
- /* [6:6] Write protection */
- /* [5:5] Ready, drive ready signal is active */
- /* [4:4] Track 0 */
- /* [3:3] Double sided drive */
- /* [2:2] HDSEL (head select) signal from drive */
- /* [1:0] Drive select */
- uint8_t digital_out; /* last value written to 0x3F2 */
- /* [7:7] MOTD (Motor control, drive D) */
- /* [6:6] MOTC (Motor control, drive C) */
- /* [5:5] MOTB (Motor control, drive B) */
- /* [4:4] MOTA (Motor control, drive A) */
- /* [3:3] DMA (DMA+IRQ enable) */
- /* [2:2] !REST (Controller reset) 1=enable 0=reset */
- /* [1:0] Drive select (0=A 1=B 2=C 3=D) */
- uint8_t main_status; /* last value read from 0x3F4 */
- /* [7:7] MRQ (Main request) 1=data register ready */
- /* [6:6] DIO (Data input/output) 1=expecting CPU read 0=expecting CPU write */
- /* [5:5] NDMA (non-DMA mode) 1=not in DMA mode */
- /* [4:4] BUSY (instruction, device busy) 1=active */
- /* [3:3] ACTD Drive D in positioning mode */
- /* [2:2] ACTC Drive C in positioning mode */
- /* [1:1] ACTB Drive B in positioning mode */
- /* [0:0] ACTA Drive A in positioning mode */
- uint8_t digital_in; /* last value read from 0x3F7 */
- /* [7:7] CHAN (Disk Change) 1=disk changed since last command (PS/2 model 30 bit is inverted) */
- /* * PS/2 except Model 30 */
- /* [6:3] all 1's */
- /* * PS/2 Model 30 */
- /* [6:4] all 0's */
- uint8_t control_cfg; /* last value written to 0x3F7 */
- /* [1:0] Data transfer rate */
- /* 11 = 1 mbit/sec */
- /* 10 = 250 kbit/sec */
- /* 01 = 300 kbit/sec */
- /* 00 = 500 kbit/sec */
- uint8_t cylinder; /* last known cylinder position */
- uint16_t irq_fired;
-
- /* desired state */
- uint8_t use_irq:1; /* if set, use IRQ. else. ??? */
- uint8_t use_dma:1; /* if set, use DMA. else, use PIO data transfer */
- uint8_t use_implied_seek:1; /* if set, act like controller has Implied Seek enabled */
-
- /* what we know about the controller */
- uint8_t version; /* result of command 0x10 (determine controller version) or 0x00 if not yet queried */
- uint8_t ps2_mode:1; /* controller is in PS/2 mode (has status registers A and B I/O ports) */
- uint8_t at_mode:1; /* controller is in AT mode (has Digital Input Register and Control Config Reg) */
- uint8_t digital_out_rw:1; /* digital out (0x3F2) is readable */
- uint8_t non_dma_mode:1; /* "ND" bit in Dump Regs */
- uint8_t implied_seek:1; /* "EIS" bit in Dump Regs */
- uint8_t current_srt:4;
- uint8_t current_hut:4;
- uint8_t current_hlt;
-};
-
-/* standard I/O ports for floppy controllers */
-struct floppy_controller floppy_standard_isa[2] = {
- /*base, IRQ, DMA*/
- {0x3F0, 6, 2},
- {0x370, 6, 2}
-};
-
-struct floppy_controller *floppy_get_standard_isa_port(int x) {
- if (x < 0 || x >= (sizeof(floppy_standard_isa)/sizeof(floppy_standard_isa[0]))) return NULL;
- return &floppy_standard_isa[x];
-}
-
-struct dma_8237_allocation* floppy_dma = NULL; /* DMA buffer */
-
-struct floppy_controller floppy_controllers[MAX_FLOPPY_CONTROLLER];
-int8_t floppy_controllers_init = -1;
-
-struct floppy_controller *floppy_get_controller(int x) {
- if (x < 0 || x >= MAX_FLOPPY_CONTROLLER) return NULL;
- if (floppy_controllers[x].base_io == 0) return NULL;
- return &floppy_controllers[x];
-}
-
-int wait_for_enter_or_escape() {
- int c;
-
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
-
- return c;
-}
-
-struct floppy_controller *alloc_floppy_controller() {
- unsigned int i=0;
-
- while (i < MAX_FLOPPY_CONTROLLER) {
- if (floppy_controllers[i].base_io == 0)
- return &floppy_controllers[i];
- }
-
- return NULL;
-}
-
-void floppy_controller_read_ps2_status(struct floppy_controller *i) {
- if (i->ps2_mode) {
- i->ps2_status[0] = inp(i->base_io+0);
- i->ps2_status[1] = inp(i->base_io+1);
- }
- else {
- i->ps2_status[0] = i->ps2_status[1] = 0xFF;
- }
-}
-
-static inline uint8_t floppy_controller_read_status(struct floppy_controller *i) {
- i->main_status = inp(i->base_io+4); /* 0x3F4 main status */
- return i->main_status;
-}
-
-static inline uint8_t floppy_controller_read_DIR(struct floppy_controller *i) {
- if (i->at_mode || i->ps2_mode)
- i->digital_in = inp(i->base_io+7); /* 0x3F7 */
- else
- i->digital_in = 0xFF;
-
- return i->digital_in;
-}
-
-static inline void floppy_controller_write_DOR(struct floppy_controller *i,unsigned char c) {
- i->digital_out = c;
- outp(i->base_io+2,c); /* 0x3F2 Digital Output Register */
-}
-
-static inline void floppy_controller_write_CCR(struct floppy_controller *i,unsigned char c) {
- i->control_cfg = c;
- outp(i->base_io+7,c); /* 0x3F7 Control Configuration Register */
-}
-
-void floppy_controller_set_data_transfer_rate(struct floppy_controller *i,unsigned char rsel) {
- if (rsel > 3) return;
- floppy_controller_write_CCR(i,(i->control_cfg & ~3) + rsel); /* change bits [1:0] */
-}
-
-void floppy_controller_drive_select(struct floppy_controller *i,unsigned char drv) {
- if (drv > 3) return;
-
- i->digital_out &= ~0x03;
- i->digital_out |= drv;
- outp(i->base_io+2,i->digital_out); /* 0x3F2 Digital Output Register */
-}
-
-void floppy_controller_set_motor_state(struct floppy_controller *i,unsigned char drv,unsigned char set) {
- if (drv > 3) return;
-
- i->digital_out &= ~(0x10 << drv);
- i->digital_out |= (set?(0x10 << drv):0x00);
- outp(i->base_io+2,i->digital_out); /* 0x3F2 Digital Output Register */
-}
-
-void floppy_controller_enable_dma(struct floppy_controller *i,unsigned char set) {
- if (i->dma < 0) set = 0;
- i->use_dma = !!set;
-
- /* 82077AA refers to this bit as "!DMAGATE", and only in AT mode.
- * Setting it gates both the IRQ and DMA. It says it has no effect
- * in PS/2 mode. Doh! */
- i->digital_out &= ~0x08;
- i->digital_out |= ((i->use_irq || i->use_dma)?0x08:0x00);
- outp(i->base_io+2,i->digital_out); /* 0x3F2 Digital Output Register */
-}
-
-void floppy_controller_enable_irq(struct floppy_controller *i,unsigned char set) {
- if (i->irq < 0) set = 0;
- i->use_irq = !!set;
-
- /* 82077AA refers to this bit as "!DMAGATE", and only in AT mode.
- * Setting it gates both the IRQ and DMA. It says it has no effect
- * in PS/2 mode. Doh! */
- i->digital_out &= ~0x08;
- i->digital_out |= ((i->use_irq || i->use_dma)?0x08:0x00);
- outp(i->base_io+2,i->digital_out); /* 0x3F2 Digital Output Register */
-}
-
-void floppy_controller_enable_irqdma_gate_otr(struct floppy_controller *i,unsigned char set) {
- unsigned char c;
-
- c = i->digital_out;
- c &= ~0x08;
- c |= (set?0x08:0x00);
- outp(i->base_io+2,c); /* 0x3F2 Digital Output Register */
-}
-
-void floppy_controller_set_reset(struct floppy_controller *i,unsigned char set) {
- i->digital_out &= ~0x04;
- i->digital_out |= (set?0x00:0x04); /* bit is INVERTED (0=reset 1=normal) */
- outp(i->base_io+2,i->digital_out); /* 0x3F2 Digital Output Register */
-}
-
-struct floppy_controller *floppy_controller_probe(struct floppy_controller *i) {
- struct floppy_controller *ret = NULL;
- uint8_t t1;
-
- if (i == NULL) return NULL;
- if (i->base_io == 0) return NULL;
-
- /* is anything there? the best we can hope for is to probe the I/O port range and see if SOMETHING responds */
- t1 = inp(i->base_io+4); /* main status register (we can't assume the ability to read the digital output register, the data reg might be 0xFF) */
- if (t1 == 0xFF) return NULL;
-
- ret = alloc_floppy_controller();
- if (ret == NULL) return NULL;
- memset(ret,0,sizeof(*ret));
-
- ret->base_io = i->base_io;
- if (i->irq >= 2 && i->irq <= 15)
- ret->irq = i->irq;
- else
- ret->irq = -1;
-
- if (i->dma >= 0 && i->dma <= 7)
- ret->dma = i->dma;
- else
- ret->dma = -1;
-
- ret->use_dma = (ret->dma >= 0);
- ret->use_irq = (ret->irq >= 0);
-
- /* assume middle-of-the-road defaults */
- ret->current_srt = 8; /* 4/8/14/16ms for 1M/500K/300K/250K */
- ret->current_hut = 8; /* 64/128/213/256 for 1M/500K/300K/250K */
- ret->current_hlt = 0x40; /* 64/128/213/256 for 1M/500K/300K/250K */
-
- /* assume controller has ND (Non-DMA) and EIS (implied seek) turned off.
- * most BIOSes do that. */
-
- /* if something appears at 0x3F0-0x3F1, assume "PS/2 mode".
- * there are finer intricate details where the meaning of some bits
- * completely change or invert their meaning between PS/2 and Model 30,
- * so we don't concern ourself with them, we only care that there's
- * something there and we can let the program using this lib figure it out. */
- t1 = inp(ret->base_io+0);
- t1 &= inp(ret->base_io+1);
- if (t1 != 0xFF) ret->ps2_mode = 1;
-
- /* what about the AT & PS/2 style CCR & DIR */
- t1 = inp(ret->base_io+7);
- if (t1 != 0xFF) ret->at_mode = 1;
-
- /* and ... guess */
- floppy_controller_write_DOR(ret,0x04+(ret->use_irq?0x08:0x00)); /* most BIOSes: DMA/IRQ enable, !reset, motor off, drive A select */
- floppy_controller_read_status(ret);
-
- /* is the Digital Out port readable? */
- t1 = inp(ret->base_io+2);
- if (t1 == ret->digital_out) ret->digital_out_rw = 1;
-
- floppy_controller_read_DIR(ret);
-
- return ret;
-}
-
-int init_floppy_controller_lib() {
- if (floppy_controllers_init < 0) {
- memset(floppy_controllers,0,sizeof(floppy_controllers));
- floppy_controllers_init = 0;
-
- cpu_probe();
- probe_dos();
- detect_windows();
-
- /* do NOT under any circumstances talk directly to the floppy from under Windows! */
- if (windows_mode != WINDOWS_NONE) return (floppy_controllers_init=0);
-
- /* init OK */
- floppy_controllers_init = 1;
- }
-
- return floppy_controllers_init;
-}
-
-void free_floppy_controller_lib() {
-}
-
-/*------------------------------------------------------------------------*/
-
-char tmp[1024];
-
-/* "current position" */
-static int current_log_sect = 1;
-static int current_log_head = 0;
-static int current_phys_head = 0;
-static int current_log_track = 0;
-static int current_phys_rw_gap = 0x1B; /* gap size for read/write commands */
-static int current_phys_fmt_gap = 0x54; /* gap size when formatting */
-static int current_sectsize_p2 = 2; /* NTS: 128 << N, 128 << 2 = 512 */
-static int current_sectsize_smaller = 0xFF; /* if sectsize_p2 == 0 */
-static int current_sectcount = 2; /* two sectors */
-static unsigned char allow_multitrack = 1; /* set MT bit */
-static unsigned char mfm_mode = 1; /* set bit to indicate MFM (not FM) */
-
-static void (interrupt *my_floppy_old_irq)() = NULL;
-static struct floppy_controller *my_floppy_irq_floppy = NULL;
-static unsigned long floppy_irq_counter = 0;
-static int my_floppy_irq_number = -1;
-
-void do_floppy_controller_unhook_irq(struct floppy_controller *fdc);
-
-static void interrupt my_floppy_irq() {
- int i;
-
- i = vga_width*(vga_height-1);
-
- _cli();
- if (my_floppy_irq_floppy != NULL) {
- my_floppy_irq_floppy->irq_fired++;
-
- /* ack PIC */
- if (my_floppy_irq_floppy->irq >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
-
- /* If too many IRQs fired, then unhook the IRQ and use polling from now on. */
- if (my_floppy_irq_floppy->irq_fired >= 0xFFFEU) {
- do_floppy_controller_unhook_irq(my_floppy_irq_floppy);
- vga_alpha_ram[i+12] = 0x1C00 | '!';
- my_floppy_irq_floppy->irq_fired = ~0; /* make sure the IRQ counter is as large as possible */
- }
- }
-
- /* we CANNOT use sprintf() here. sprintf() doesn't work to well from within an interrupt handler,
- * and can cause crashes in 16-bit realmode builds. */
- vga_alpha_ram[i++] = 0x1F00 | 'I';
- vga_alpha_ram[i++] = 0x1F00 | 'R';
- vga_alpha_ram[i++] = 0x1F00 | 'Q';
- vga_alpha_ram[i++] = 0x1F00 | ':';
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter / 100000UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter / 10000UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter / 1000UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter / 100UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter / 10UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((floppy_irq_counter / 1L) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ' ';
-
- floppy_irq_counter++;
-}
-
-void do_floppy_controller_hook_irq(struct floppy_controller *fdc) {
- if (my_floppy_irq_number >= 0 || my_floppy_old_irq != NULL || fdc->irq < 0)
- return;
-
- /* let the IRQ know what floppy controller */
- my_floppy_irq_floppy = fdc;
-
- /* enable on floppy controller */
- p8259_mask(fdc->irq);
- floppy_controller_enable_irq(fdc,1);
-
- /* hook IRQ */
- my_floppy_old_irq = _dos_getvect(irq2int(fdc->irq));
- _dos_setvect(irq2int(fdc->irq),my_floppy_irq);
- my_floppy_irq_number = fdc->irq;
-
- /* enable at PIC */
- p8259_unmask(fdc->irq);
-}
-
-void do_floppy_controller_unhook_irq(struct floppy_controller *fdc) {
- if (my_floppy_irq_number < 0 || my_floppy_old_irq == NULL || fdc->irq < 0)
- return;
-
- /* disable on floppy controller, then mask at PIC */
- p8259_mask(fdc->irq);
- floppy_controller_enable_irq(fdc,0);
-
- /* restore the original vector */
- _dos_setvect(irq2int(fdc->irq),my_floppy_old_irq);
- my_floppy_irq_number = -1;
- my_floppy_old_irq = NULL;
-}
-
-void do_floppy_controller_enable_irq(struct floppy_controller *fdc,unsigned char en) {
- if (!en || fdc->irq < 0 || fdc->irq != my_floppy_irq_number)
- do_floppy_controller_unhook_irq(fdc);
- if (en && fdc->irq >= 0)
- do_floppy_controller_hook_irq(fdc);
-}
-
-static inline uint8_t floppy_controller_busy_in_instruction(struct floppy_controller *fdc) {
- return ((fdc->main_status & 0x10) == 0x10)?1:0; /* busy == 1 */
-}
-
-static inline uint8_t floppy_controller_data_io_ready(struct floppy_controller *fdc) {
- return ((fdc->main_status & 0x80) == 0x80)?1:0; /* data ready == 1 */
-}
-
-static inline uint8_t floppy_controller_can_read_data(struct floppy_controller *fdc) {
- return ((fdc->main_status & 0xC0) == 0xC0)?1:0; /* data ready == 1 and data i/o == 1 */
-}
-
-static inline uint8_t floppy_controller_can_read_data_non_dma(struct floppy_controller *fdc) {
- return ((fdc->main_status & 0xE0) == 0xE0)?1:0; /* data ready == 1 and data i/o == 1 and NDMA == 1 */
-}
-
-static inline uint8_t floppy_controller_can_write_data(struct floppy_controller *fdc) {
- return ((fdc->main_status & 0xC0) == 0x80)?1:0; /* data ready == 1 and data i/o == 0 */
-}
-
-static inline uint8_t floppy_controller_can_write_data_non_dma(struct floppy_controller *fdc) {
- return ((fdc->main_status & 0xE0) == 0xA0)?1:0; /* data ready == 1 and data i/o == 0 AND NDMA == 1 */
-}
-
-static inline uint8_t floppy_controller_read_data_byte(struct floppy_controller *fdc) {
- return inp(fdc->base_io+5);
-}
-
-static inline void floppy_controller_write_data_byte(struct floppy_controller *fdc,uint8_t b) {
- outp(fdc->base_io+5,b);
-}
-
-static inline int floppy_controller_wait_data_ready(struct floppy_controller *fdc,unsigned int timeout) {
- do {
- floppy_controller_read_status(fdc);
- if (floppy_controller_data_io_ready(fdc)) return 1;
- } while (--timeout != 0);
-
- return 0;
-}
-
-static inline int floppy_controller_wait_data_read_non_dma_ready(struct floppy_controller *fdc,unsigned int timeout) {
- do {
- floppy_controller_read_status(fdc);
- if (floppy_controller_can_read_data_non_dma(fdc)) return 1;
- t8254_wait(t8254_us2ticks(1000));
- } while (--timeout != 0);
-
- return 0;
-}
-
-static inline int floppy_controller_wait_data_write_non_dma_ready(struct floppy_controller *fdc,unsigned int timeout) {
- do {
- floppy_controller_read_status(fdc);
- if (floppy_controller_can_write_data_non_dma(fdc)) return 1;
- t8254_wait(t8254_us2ticks(1000));
- } while (--timeout != 0);
-
- return 0;
-}
-
-static inline void floppy_controller_reset_irq_counter(struct floppy_controller *fdc) {
- fdc->irq_fired = 0;
-}
-
-int floppy_controller_wait_busy_in_instruction(struct floppy_controller *fdc,unsigned int timeout) {
- do {
- floppy_controller_read_status(fdc);
- if (!floppy_controller_busy_in_instruction(fdc)) return 1;
- t8254_wait(t8254_us2ticks(1000));
- } while (--timeout != 0);
-
- return 0;
-}
-
-int floppy_controller_wait_data_ready_ms(struct floppy_controller *fdc,unsigned int timeout) {
- do {
- floppy_controller_read_status(fdc);
- if (floppy_controller_data_io_ready(fdc)) return 1;
- t8254_wait(t8254_us2ticks(1000));
- } while (--timeout != 0);
-
- return 0;
-}
-
-int floppy_controller_wait_irq(struct floppy_controller *fdc,unsigned int timeout,unsigned int counter) {
- do {
- if (fdc->irq_fired >= counter) break;
- t8254_wait(t8254_us2ticks(1000));
- } while (--timeout != 0);
-
- return 0;
-}
-
-int floppy_controller_write_data(struct floppy_controller *fdc,const unsigned char *data,int len) {
- unsigned int oflags = get_cpu_flags();
- int ret = 0;
-
- _cli(); /* clear interrupts so we can focus on talking to the FDC */
- while (len > 0) {
- if (!floppy_controller_wait_data_ready(fdc,1000)) {
- if (ret == 0) ret = -1;
- break;
- }
- if (!floppy_controller_can_write_data(fdc)) {
- if (ret == 0) ret = -2;
- break;
- }
-
- floppy_controller_write_data_byte(fdc,*data++);
- len--; ret++;
- }
-
- if (oflags&0x200/*IF interrupt enable was on*/) _sti();
- return ret;
-}
-
-#if TARGET_MSDOS == 32
-int floppy_controller_write_data_ndma(struct floppy_controller *fdc,const unsigned char *data,int len) {
-#else
-int floppy_controller_write_data_ndma(struct floppy_controller *fdc,const unsigned char far *data,int len) {
-#endif
- unsigned int oflags = get_cpu_flags();
- int ret = 0;
-
- _cli();
- while (len > 0) {
- if (!floppy_controller_wait_data_ready(fdc,1000)) {
- if (ret == 0) ret = -1;
- break;
- }
- if (!floppy_controller_wait_data_write_non_dma_ready(fdc,1000)) {
- if (ret == 0) ret = -2;
- break;
- }
-
- floppy_controller_write_data_byte(fdc,*data++);
- len--; ret++;
- }
-
- if (oflags&0x200/*IF interrupt enable was on*/) _sti();
- return ret;
-}
-
-int floppy_controller_read_data(struct floppy_controller *fdc,unsigned char *data,int len) {
- unsigned int oflags = get_cpu_flags();
- int ret = 0;
-
- _cli();
- while (len > 0) {
- if (!floppy_controller_wait_data_ready(fdc,1000)) {
- if (ret == 0) ret = -1;
- break;
- }
- if (!floppy_controller_can_read_data(fdc)) {
- if (ret == 0) ret = -2;
- break;
- }
-
- *data++ = floppy_controller_read_data_byte(fdc);
- len--; ret++;
- }
-
- if (oflags&0x200/*IF interrupt enable was on*/) _sti();
- return ret;
-}
-
-#if TARGET_MSDOS == 32
-int floppy_controller_read_data_ndma(struct floppy_controller *fdc,unsigned char *data,int len) {
-#else
-int floppy_controller_read_data_ndma(struct floppy_controller *fdc,unsigned char far *data,int len) {
-#endif
- unsigned int oflags = get_cpu_flags();
- int ret = 0;
-
- _cli();
- while (len > 0) {
- if (!floppy_controller_wait_data_ready(fdc,1000)) {
- if (ret == 0) ret = -1;
- break;
- }
- if (!floppy_controller_wait_data_read_non_dma_ready(fdc,1000)) {
- if (ret == 0) ret = -2;
- break;
- }
-
- *data++ = floppy_controller_read_data_byte(fdc);
- len--; ret++;
- }
-
- if (oflags&0x200/*IF interrupt enable was on*/) _sti();
- return ret;
-}
-
-void do_floppy_controller_reset(struct floppy_controller *fdc) {
- struct vga_msg_box vgabox;
-
- vga_msg_box_create(&vgabox,"FDC reset in progress",0,0);
-
- floppy_controller_set_reset(fdc,1);
- t8254_wait(t8254_us2ticks(1000000));
- floppy_controller_set_reset(fdc,0);
- floppy_controller_wait_data_ready_ms(fdc,1000);
- floppy_controller_read_status(fdc);
-
- vga_msg_box_destroy(&vgabox);
-}
-
-void do_check_interrupt_status(struct floppy_controller *fdc) {
- struct vga_msg_box vgabox;
- char cmd[10],resp[10];
- int rd,wd,rdo,wdo;
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- /* Check Interrupt Status (x8h)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 0 0 0 1 0 0 0
- *
- */
-
- wdo = 1;
- cmd[0] = 0x08; /* Check interrupt status */
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 1) {
- sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* wait for data ready. does not fire an IRQ (because you use this to clear IRQ status!) */
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- /* NTS: It's not specified whether this returns 2 bytes if success and 1 if no IRQ pending.. or...? */
- rdo = 2;
- resp[1] = 0;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- sprintf(tmp,"Failed to read data from the FDC, %u/%u",rd,rdo);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* Check Interrupt Status (x8h) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | ST0
- * 1 | Current Cylinder
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* return value is ST0 and the current cylinder */
- fdc->st[0] = resp[0];
- fdc->cylinder = resp[1];
-}
-
-void do_spin_up_motor(struct floppy_controller *fdc,unsigned char drv) {
- if (drv > 3) return;
-
- if (!(fdc->digital_out & (0x10 << drv))) {
- struct vga_msg_box vgabox;
-
- vga_msg_box_create(&vgabox,"Spinning up motor",0,0);
-
- /* if the motor isn't on, then turn it on, and then wait for motor to stabilize */
- floppy_controller_set_motor_state(fdc,drv,1);
- t8254_wait(t8254_us2ticks(500000)); /* 500ms */
-
- vga_msg_box_destroy(&vgabox);
- }
- else {
- /* some controllers auto-timeout the motor against our will.
- * perhaps this is what the Linux kernel means by "twaddling" the motor bit */
- floppy_controller_set_motor_state(fdc,drv,0);
- floppy_controller_set_motor_state(fdc,drv,1);
- }
-}
-
-void do_seek_drive_rel(struct floppy_controller *fdc,int track) {
- struct vga_msg_box vgabox;
- char cmd[10];
- int wd,wdo;
-
- do_spin_up_motor(fdc,fdc->digital_out&3);
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- floppy_controller_reset_irq_counter(fdc);
-
- /* Seek Relative (1xFh)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 1 DIR 0 0 1 1 1 1
- * 1 | x x x x x HD DR1 DR0
- * 2 | Cylinder Step
- *
- * HD = Head select (on PC platform, doesn't matter)
- * DR1,DR0 = Drive select
- * DIR = Step direction (1=inward increasing, 0=outward decreasing)
- * Cyl. step = How many tracks to step */
-
- wdo = 3;
- cmd[0] = 0x8F + (track < 0 ? 0x40 : 0x00); /* Seek rel [6:6] = DIR */
- cmd[1] = (fdc->digital_out&3)+(current_phys_head?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] HD (doesn't matter) */;
- cmd[2] = abs(track);
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 3) {
- sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* fires an IRQ. doesn't return state */
- if (fdc->use_irq) floppy_controller_wait_irq(fdc,1000,1);
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- /* Seek Relative (1xFh) response
- *
- * (none)
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* use Check Interrupt Status */
- do_check_interrupt_status(fdc);
-}
-
-unsigned long prompt_track_number();
-void do_seek_drive(struct floppy_controller *fdc,uint8_t track);
-void do_calibrate_drive(struct floppy_controller *fdc);
-int do_read_sector_id(unsigned char resp[7],struct floppy_controller *fdc,unsigned char head);
-
-void do_step_tracks(struct floppy_controller *fdc) {
- unsigned long start,end,track;
- struct vga_msg_box vgabox;
- unsigned char resp[7];
- char tmp[64];
- int del,c;
-
- start = prompt_track_number();
- if (start == (~0UL)) return;
-
- end = prompt_track_number();
- if (start == (~0UL)) return;
- if (start > end) return;
-
- do_spin_up_motor(fdc,fdc->digital_out&3);
-
- vga_msg_box_create(&vgabox,"Seeking to track 0",0,0);
- do_calibrate_drive(fdc);
- do_calibrate_drive(fdc);
- do_calibrate_drive(fdc);
- vga_msg_box_destroy(&vgabox);
-
- /* step! */
- for (track=start;track <= end;track++) {
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
- if (c == 27) break;
- }
-
- sprintf(tmp,"Seeking track %lu",track);
- vga_msg_box_create(&vgabox,tmp,0,0);
-
- /* move head */
- do_seek_drive(fdc,(uint8_t)track);
-
- /* read sector ID to try and force head select if FDC doesn't do it from seek command */
- do_read_sector_id(resp,fdc,current_phys_head);
-
- /* delay 1 second */
- for (del=0;del < 1000;del++)
- t8254_wait(t8254_us2ticks(1000));
-
- /* un-draw the box */
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-void do_seek_drive(struct floppy_controller *fdc,uint8_t track) {
- struct vga_msg_box vgabox;
- char cmd[10];
- int wd,wdo;
-
- do_spin_up_motor(fdc,fdc->digital_out&3);
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- floppy_controller_reset_irq_counter(fdc);
-
- /* Seek (xFh)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 0 0 0 1 1 1 1
- * 1 | x x x x x HD DR1 DR0
- * 2 | Cylinder
- *
- * HD = Head select (on PC platform, doesn't matter)
- * DR1,DR0 = Drive select
- * Cylinder = Track to move to */
-
- wdo = 3;
- cmd[0] = 0x0F; /* Seek */
- cmd[1] = (fdc->digital_out&3)+(current_phys_head?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] HD (doesn't matter) */;
- cmd[2] = track;
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 3) {
- sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* fires an IRQ. doesn't return state */
- if (fdc->use_irq) floppy_controller_wait_irq(fdc,1000,1);
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- /* Seek (xFh) response
- *
- * (none)
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* use Check Interrupt Status */
- do_check_interrupt_status(fdc);
-}
-
-void do_check_drive_status(struct floppy_controller *fdc) {
- struct vga_msg_box vgabox;
- char cmd[10],resp[10];
- int rd,wd,rdo,wdo;
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- /* Check Drive Status (x4h)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 0 0 0 0 1 0 0
- * 1 | x x x x x HD DR1 DR0
- *
- * HD = Head select (on PC platform, doesn't matter)
- * DR1,DR0 = Drive select */
-
- wdo = 2;
- cmd[0] = 0x04; /* Check drive status */
- cmd[1] = (fdc->digital_out&3)+(current_phys_head?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD = 0 */;
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 2) {
- sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* wait for data ready. does not fire an IRQ */
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- /* Check Drive Status (x4h) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | ST3
- */
-
- rdo = 1;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- sprintf(tmp,"Failed to read data from the FDC, %u/%u",rd,rdo);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* return value is ST3 */
- fdc->st[3] = resp[0];
-}
-
-void do_calibrate_drive(struct floppy_controller *fdc) {
- struct vga_msg_box vgabox;
- char cmd[10];
- int wd,wdo;
-
- do_spin_up_motor(fdc,fdc->digital_out&3);
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- floppy_controller_reset_irq_counter(fdc);
-
- /* Calibrate Drive (x7h)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 0 0 0 0 1 1 1
- * 1 | x x x x x 0 DR1 DR0
- *
- * DR1,DR0 = Drive select */
-
- wdo = 2;
- cmd[0] = 0x07; /* Calibrate */
- cmd[1] = (fdc->digital_out&3)/* [1:0] = DR1,DR0 */;
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 2) {
- sprintf(tmp,"Failed to write data to FDC, %u/%u",wd,wdo);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* fires an IRQ. doesn't return state */
- if (fdc->use_irq) floppy_controller_wait_irq(fdc,1000,1);
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- /* Calibrate Drive (x7h) response
- *
- * (none)
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* use Check Interrupt Status */
- do_check_interrupt_status(fdc);
-}
-
-int do_floppy_get_version(struct floppy_controller *fdc) {
- int rd,wd,rdo,wdo;
- char cmd[10],resp[10];
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- /* Version (1x0h)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 0 0 1 0 0 0 0
- */
-
- wdo = 1;
- cmd[0] = 0x10;
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 1) {
- do_floppy_controller_reset(fdc);
- return 0;
- }
-
- /* wait for data ready. does not fire an IRQ */
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- rdo = 1;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- do_floppy_controller_reset(fdc);
- return 0;
- }
-
- /* Version (1x0h) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+--------------------------------------
- * 0 | Version or error
- *
- * Version/Error values:
- * 0x80: Not an enhanced controller (we got an invalid opcode)
- * 0x90: Enhanced controller
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- fdc->version = resp[0];
- return 1;
-
-}
-
-int do_floppy_controller_specify(struct floppy_controller *fdc) {
- int retry_count=0;
- char cmd[10];
- int wd,wdo;
- int drv;
-
-retry: drv = fdc->digital_out & 3;
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- /* Specify (x3h)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 0 0 0 0 0 1 1
- * 1 | <--- SRT ---> <----HUT---->
- * 2 | <-----------HLT---------> ND
- */
-
- wdo = 3;
- cmd[0] = 0x03;
- cmd[1] = (fdc->current_srt << 4) | (fdc->current_hut & 0xF);
- cmd[2] = (fdc->current_hlt << 1) | (fdc->non_dma_mode & 1);
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 3) {
- do_floppy_controller_reset(fdc);
- return 0;
- }
-
- /* wait for data ready. does not fire an IRQ */
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- /* Specify (x3h) response
- *
- * (none)
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* use Check Interrupt Status */
- do_check_interrupt_status(fdc);
-
- /* if it failed, try again */
- if ((fdc->st[0]&0xC0) == 0xC0 || (fdc->st[0]&0xC0) == 0x40) {
- if ((++retry_count) < 8) { /* what the hell VirtualBox? */
- floppy_controller_drive_select(fdc,drv);
- goto retry;
- }
-
- return 0;
- }
-
- return 1;
-}
-
-int do_floppy_dumpreg(struct floppy_controller *fdc) {
- int rd,wd,rdo,wdo;
- char cmd[10],resp[10];
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- /* Dump Registers (xEh)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 0 0 0 1 1 1 0
- */
-
- wdo = 1;
- cmd[0] = 0x0E;
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 1) {
- do_floppy_controller_reset(fdc);
- return 0;
- }
-
- /* wait for data ready. does not fire an IRQ */
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- rdo = 10;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- do_floppy_controller_reset(fdc);
- return 0;
- }
-
- /* Dump Registers (xEh) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+--------------------------------------
- * 0 | Current Cylinder (drive 0) <- Also known as PCN0
- * 1 | Current Cylinder (drive 1) <- Also known as PCN1
- * 2 | Current Cylinder (drive 2) <- Also known as PCN2
- * 3 | Current Cylinder (drive 3) <- Also known as PCN3
- * 4 | <------SRT-----> <------HUT----->
- * 5 | <------------HLT--------------> ND
- * 6 | <--------------SC/EOT-------------->
- * 7 |LOCK 0 D3 D2 D1 D0 GAP WGATE
- * 8 | 0 EIS EFIFO POLL <---FIFOTHR---->
- * 9 | <--------------PRETRK-------------->
- *
- * SRT = Step rate interval (0.5 to 8ms in 0.5 steps at 1mbit/sec, affected by data rate)
- * HUT = Head unload time (affected by data rate)
- * HLT = Head load time (affected by data rate)
- * ND = Non-DMA mode flag. If set, the controller should operate in the non-DMA mode.
- * SC/EOT = Sector count/End of track
- * D3...D0 = Drive Select 3..0, which ones are in Perpendicular Mode
- * GAP = Alter Gap 2 length in Perpendicular Mode
- * WGATE = Write gate alters timing of WE, to allow for pre-erase loads in perpendicular drives.
- * EIS = Enable Implied Seek
- * EFIFO = Enable FIFO. When 0, FIFO is enabled. When 1, FIFO is disabled.
- * POLL = Polling disable. When set, internal polling routine is disabled.
- * FIFOTHR = FIFO threshold - 1 in the execution phase of read/write commands. 0h to Fh maps to 1...16 bytes.
- * PRETRK = Precompensation start track number.
- *
- *
- * 82077AA Drive Control Delays (ms) Table 5-10
- *
- * | HUT | SRT |
- * | 1M 500K 300K 250K | 1M 500K 300K 250K |
- * ---+------------------------------------+------------------------------------+
- * 0 | 128 256 426 512 | 8.0 16 26.7 32 |
- * 1 | 8 16 26.7 32 | 7.5 15 25 30 |
- * ...............................................................................
- * Eh | 112 224 373 448 | 1.0 2 3.33 4 |
- * Fh | 120 240 400 480 | 0.5 1 1.67 2 |
- * +------------------------------------+------------------------------------+
- *
- * | HLT |
- * | 1M 500K 300K 250K |
- * ---+------------------------------------+
- * 0 | 128 256 426 512 |
- * 1 | 1 2 3.3 4 |
- * ..........................................
- * 7Eh | 126 252 420 504 |
- * 7Fh | 127 254 423 508 |
- * +------------------------------------+
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* copy down info we want to keep track of */
- fdc->current_srt = resp[4] >> 4;
- fdc->current_hut = resp[4] & 0x0F;
- fdc->current_hlt = resp[5] >> 1;
- fdc->non_dma_mode = resp[5] & 0x01;
- fdc->implied_seek = (resp[8] >> 6) & 1;
-
- {
- struct vga_msg_box vgabox;
- char *w=tmp;
- int i;
-
- for (i=0;i < rd;i++) w += sprintf(w,"%02x ",resp[i]);
- *w++ = '\n';
- *w++ = '\n';
- *w = 0;
-
- w += sprintf(w,"PCN[0-3](physical track) = %u,%u,%u,%u\n",
- resp[0],resp[1],resp[2],resp[3]);
- w += sprintf(w,"SRT=%u HUT=%u HLT=%u ND=%u\n",
- resp[4]>>4,resp[4]&0xF,
- resp[5]>>1,resp[5]&1);
- w += sprintf(w,"SC/EOT=%u LOCK=%u D[0-3](perpendicular)=%u,%u,%u,%u\n",
- resp[6],
- (resp[7]>>7)&1,
- (resp[7]>>5)&1,
- (resp[7]>>4)&1,
- (resp[7]>>3)&1,
- (resp[7]>>2)&1);
- w += sprintf(w,"GAP=%u WGATE=%u EIS=%u EFIFO=%u POLL=%u\n",
- (resp[7]>>1)&1,
- (resp[7]>>0)&1,
- (resp[8]>>6)&1,
- (resp[8]>>5)&1,
- (resp[8]>>4)&1);
- w += sprintf(w,"FIFOTHR=%u PRETRK=%u",
- (resp[8]>>0)&0xF,
- resp[9]);
-
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-
- return 1;
-}
-
-int do_read_sector_id(unsigned char resp[7],struct floppy_controller *fdc,unsigned char head) {
- int rd,wd,rdo,wdo;
- char cmd[10];
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- /* Read ID (xAh)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 MF 0 0 1 0 1 0
- * 1 | x x x x x HD DR1 DR0
- *
- * MF = MFM/FM
- * HD = Head select (on PC platform, doesn't matter)
- * DR1,DR0 = Drive select */
-
- wdo = 2;
- cmd[0] = 0x0A + (mfm_mode?0x40:0x00); /* Read sector ID [6:6] MFM */
- cmd[1] = (fdc->digital_out&3)+(head<<2)/* [1:0] = DR1,DR0 [2:2] = HD */;
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 2) {
- do_floppy_controller_reset(fdc);
- return 0;
- }
-
- /* wait for data ready. does not fire an IRQ */
- floppy_controller_wait_data_ready_ms(fdc,1000);
-
- rdo = 7;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- do_floppy_controller_reset(fdc);
- return 0;
- }
-
- /* Read ID (xAh) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | ST0
- * 1 | ST1
- * 2 | ST2
- * 3 | Cylinder
- * 4 | Head
- * 5 | Sector Number
- * 6 | Sector Size
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* accept ST0..ST2 from response and update */
- if (rd >= 3) {
- fdc->st[0] = resp[0];
- fdc->st[1] = resp[1];
- fdc->st[2] = resp[2];
- }
- if (rd >= 4) {
- fdc->cylinder = resp[3];
- }
-
- return rd;
-}
-
-void do_read_sector_id_demo(struct floppy_controller *fdc) {
- unsigned char headsel = current_phys_head;
- char resp[10];
- int c;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_clear();
-
- vga_write("Read Sector ID demo. Space to switch heads.\n\n");
-
- do {
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27)
- break;
- else if (c == ' ')
- headsel ^= 1;
- }
-
- if ((c=do_read_sector_id(resp,fdc,headsel)) == 7) {
- vga_moveto(0,2);
- vga_write_color(0x0F);
-
- sprintf(tmp,"ST: %02xh %02xh %02xh %02xh\n",fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3]);
- vga_write(tmp);
-
- sprintf(tmp,"C/H/S/sz: %-3u/%-3u/%-3u/%-3u \n",resp[3],resp[4],resp[5],resp[6]);
- vga_write(tmp);
- }
- else {
- vga_moveto(0,2);
- vga_write_color(0x0F);
-
- sprintf(tmp,"ST: --h --h --h --h (ret=%d)\n",c);
- vga_write(tmp);
-
- sprintf(tmp,"C/H/S/sz: ---/---/---/--- \n");
- vga_write(tmp);
- }
- } while (1);
-}
-
-signed long prompt_signed_track_number() {
- signed long track = 0;
- struct vga_msg_box box;
- VGA_ALPHA_PTR sco;
- char temp_str[16];
- int c,i=0;
-
- vga_msg_box_create(&box,"Enter relative track number:",2,0);
- sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
- while (1) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- track = 0;
- break;
- }
- else if (c == 13) {
- if (i == 0) break;
- temp_str[i] = 0;
- if (isdigit(temp_str[0]))
- track = strtol(temp_str,NULL,0);
- else
- track = 0;
-
- break;
- }
- else if (isdigit(c) || c == '-') {
- if (i < 15) {
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- }
- }
- else if (c == 8) {
- if (i > 0) i--;
- sco[i] = ' ' | 0x1E00;
- }
- }
- vga_msg_box_destroy(&box);
-
- return track;
-}
-
-unsigned long prompt_track_number() {
- unsigned long track = 0;
- struct vga_msg_box box;
- VGA_ALPHA_PTR sco;
- char temp_str[16];
- int c,i=0;
-
- vga_msg_box_create(&box,"Enter track number:",2,0);
- sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
- while (1) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- track = (int)(~0UL);
- break;
- }
- else if (c == 13) {
- if (i == 0) break;
- temp_str[i] = 0;
- if (isdigit(temp_str[0]))
- track = strtol(temp_str,NULL,0);
- else
- track = 0;
-
- break;
- }
- else if (isdigit(c)) {
- if (i < 15) {
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- }
- }
- else if (c == 8) {
- if (i > 0) i--;
- sco[i] = ' ' | 0x1E00;
- }
- }
- vga_msg_box_destroy(&box);
-
- return track;
-}
-
-void do_floppy_format_track(struct floppy_controller *fdc) {
- unsigned int data_length,unit_length;
- unsigned int returned_length = 0;
- char cmd[10],resp[10];
- int rd,rdo,wd,wdo,p;
- uint8_t nsect;
-
- nsect = current_sectcount;
-
- unit_length = 4;
- data_length = nsect * unit_length;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_clear();
-
- {
- struct vga_msg_box vgabox;
- char *w=tmp;
- int i;
-
- w += sprintf(w,"I will format the track as having %u sectors/track,\n",
- nsect);
- w += sprintf(w,"first sector %u, logical track %u, %u bytes/sector.\n",
- current_log_sect,current_log_track,128 << current_sectsize_p2);
- w += sprintf(w,"I am using the sector number count for sectors/track.\n");
- w += sprintf(w,"Since (last I checked) the head is currently located at\n");
- w += sprintf(w,"track %u, physical track %u will be formatted logical\n",
- fdc->cylinder,fdc->cylinder);
- w += sprintf(w,"track %u. The track will be marked as having logical head %u\n",
- current_log_track,
- current_log_head);
- w += sprintf(w,"and formatted on physical head %u\n",
- current_phys_head);
- w += sprintf(w,"\n");
- w += sprintf(w,"Hit ENTER to continue if this is what you want,\nor ESC to stop now.");
-
- vga_msg_box_create(&vgabox,tmp,0,0);
- i = wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- if (i == 27) return;
- }
-
- sprintf(tmp,"Formatting C/H/S/sz/num %u/%u/%u/%u/%u\n",current_log_track,current_log_head,current_log_sect,128 << current_sectsize_p2,nsect);
- vga_write(tmp);
-
- do_spin_up_motor(fdc,fdc->digital_out&3);
-
- if (floppy_dma == NULL) return;
- if (data_length > floppy_dma->length) {
- nsect = floppy_dma->length / unit_length;
- data_length = nsect * unit_length;
- }
- if (data_length > floppy_dma->length) return;
-
- /* sector pattern. 4 bytes for each sector to write */
- for (rd=0;rd < nsect;rd++) {
- wd = rd * unit_length;
-
- /* |
- * --+---------------------------
- * 0 | Cylinder
- * 1 | Head
- * 2 | Sector address
- * 3 | Sector size code
- */
- floppy_dma->lin[wd++] = current_log_track;
- floppy_dma->lin[wd++] = current_log_head;
- floppy_dma->lin[wd++] = current_log_sect + rd;
- floppy_dma->lin[wd++] = current_sectsize_p2;
- }
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- if (fdc->dma >= 0 && fdc->use_dma) {
- outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma) | D8237_MASK_SET); /* mask */
-
- outp(d8237_ioport(fdc->dma,D8237_REG_W_WRITE_MODE),
- D8237_MODER_CHANNEL(fdc->dma) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
-
- d8237_write_count(fdc->dma,data_length);
- d8237_write_base(fdc->dma,floppy_dma->phys);
-
- outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
-
- inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
- }
-
- /* Format Track (xDh)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | 0 MF 0 0 1 1 0 1
- * 1 | 0 0 0 0 0 HD DR1 DR0
- * 2 | <------ bytes/sector ------->
- * 3 | <----- sectors/track ------->
- * 4 | <--------- GAP3 ------------>
- * 5 | <------ Fill byte ---------->
- *
- * MF = MFM/FM
- * HD = Head select (on PC platform, doesn't matter)
- * DR1,DR0 = Drive select */
-
- wdo = 6;
- cmd[0] = (mfm_mode?0x40:0x00)/* MFM */ + 0x0D/* FORMAT TRACK */;
- cmd[1] = (fdc->digital_out&3)+(current_phys_head&1?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD */;
- cmd[2] = current_sectsize_p2;
- cmd[3] = nsect;
- cmd[4] = current_phys_fmt_gap;
- cmd[5] = 0xAA; /* fill byte */
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 2) {
- vga_write("Write data port failed\n");
- do_floppy_controller_reset(fdc);
- return;
- }
-
- vga_write("Format in progress\n");
-
- /* fires an IRQ */
- if (fdc->use_dma) {
- if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
- floppy_controller_wait_data_ready_ms(fdc,1000);
- }
- else {
- /* NOTES:
- *
- * Sun/Oracle VirtualBox floppy emulation bug: PIO mode doesn't seem to be supported properly on write
- * for more than one sector. It will SEEM like it works, but when you read the data back only the first
- * sector was ever written. On the same configuration, READ works fine using the same PIO mode. */
- while (returned_length < data_length) {
- if ((returned_length+unit_length) > data_length) break;
- floppy_controller_wait_data_ready_ms(fdc,10000);
-
- p = floppy_controller_write_data_ndma(fdc,floppy_dma->lin + returned_length,unit_length);
- if (p < 0 || p > unit_length) {
- sprintf(tmp,"NDMA write failed %d (%02xh)\n",p,fdc->main_status);
- vga_write(tmp);
- p = 0;
- }
-
- returned_length += p;
- /* stop on incomplete transfer */
- if (p != unit_length) break;
- }
- }
-
- rdo = 7;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- vga_write("Write data port failed\n");
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* Format Track (xDh) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | ST0
- * 1 | ST1
- * 2 | ST2
- * 3 | ?
- * 4 | ?
- * 5 | ?
- * 6 | ?
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* accept ST0..ST2 from response and update */
- if (rd >= 3) {
- fdc->st[0] = resp[0];
- fdc->st[1] = resp[1];
- fdc->st[2] = resp[2];
- }
- if (rd >= 4) {
- fdc->cylinder = resp[3];
- }
-
- /* (if DMA) did we get any data? */
- if (fdc->dma >= 0 && fdc->use_dma) {
- uint32_t dma_len = d8237_read_count(fdc->dma);
- uint8_t status = inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS));
-
- /* some DMA controllers reset the count back to the original value on terminal count.
- * so if the DMA controller says terminal count, the true count is zero */
- if (status&D8237_STATUS_TC(fdc->dma)) dma_len = 0;
-
- if (dma_len > (uint32_t)data_length) dma_len = (uint32_t)data_length;
- returned_length = (unsigned int)((uint32_t)data_length - dma_len);
- }
-
- sprintf(tmp,"%lu bytes written\n",(unsigned long)returned_length);
- vga_write(tmp);
- vga_write("\n");
-
- wait_for_enter_or_escape();
-}
-
-void do_floppy_write_test(struct floppy_controller *fdc) {
- unsigned int data_length,unit_length;
- unsigned int returned_length = 0;
- char cmd[10],resp[10];
- uint8_t cyl,head,sect,ssz,nsect;
- int rd,rdo,wd,wdo,x,p;
-
- cyl = current_log_track;
- head = current_log_head;
- sect = current_log_sect;
- nsect = current_sectcount;
- ssz = current_sectsize_p2;
-
- if (current_sectsize_p2 > 0)
- unit_length = (128 << ssz);
- else
- unit_length = current_sectsize_smaller;
-
- data_length = nsect * unit_length;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_clear();
-
- sprintf(tmp,"Writing C/H/S/sz/num %u/%u/%u/%u/%u\n",cyl,head,sect,unit_length,nsect);
- vga_write(tmp);
-
- do_spin_up_motor(fdc,fdc->digital_out&3);
-
- if (floppy_dma == NULL) return;
- if (data_length > floppy_dma->length) {
- nsect = floppy_dma->length / unit_length;
- data_length = nsect * unit_length;
- }
- if (data_length > floppy_dma->length) return;
-
- for (x=0;(unsigned int)x < data_length;x++) floppy_dma->lin[x] = x;
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- if (fdc->dma >= 0 && fdc->use_dma) {
- outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma) | D8237_MASK_SET); /* mask */
-
- outp(d8237_ioport(fdc->dma,D8237_REG_W_WRITE_MODE),
- D8237_MODER_CHANNEL(fdc->dma) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
-
- d8237_write_count(fdc->dma,data_length);
- d8237_write_base(fdc->dma,floppy_dma->phys);
-
- outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
-
- inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
- }
-
- /* Write Sector (x5h)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | MT MF 0 0 0 1 0 1
- * 1 | x x x x x HD DR1 DR0
- * 2 | Cylinder
- * 3 | Head
- * 4 | Sector Number
- * 5 | Sector Size
- * 6 | Track length/last sector
- * 7 | Length of GAP3
- * 8 | Data Length
- *
- * MT = Multi-track
- * MF = MFM/FM
- * HD = Head select (on PC platform, doesn't matter)
- * DR1,DR0 = Drive select */
-
- /* NTS: To ensure we read only one sector, Track length/last sector must equal
- * Sector Number field. The floppy controller stops reading on error or when
- * sector number matches. This is very important for the PIO mode of this code,
- * else we'll never complete reading properly and never get to reading back
- * the status bytes. */
-
- wdo = 9;
- cmd[0] = (allow_multitrack?0x80:0x00)/*Multitrack*/ + (mfm_mode?0x40:0x00)/* MFM */ + 0x05/* WRITE DATA */;
- cmd[1] = (fdc->digital_out&3)+(current_phys_head&1?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD */;
- cmd[2] = cyl; /* cyl=0 */
- cmd[3] = head; /* head=0 */
- cmd[4] = sect; /* sector=1 */
- cmd[5] = ssz; /* sector size=2 (512 bytes) */
- cmd[6] = sect+nsect-1; /* last sector of the track (what sector to stop at). */
- cmd[7] = current_phys_rw_gap;
- cmd[8] = current_sectsize_smaller; /* DTL (not used if 256 or larger) */
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 2) {
- vga_write("Write data port failed\n");
- do_floppy_controller_reset(fdc);
- return;
- }
-
- vga_write("Write in progress\n");
-
- /* fires an IRQ */
- if (fdc->use_dma) {
- if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
- floppy_controller_wait_data_ready_ms(fdc,1000);
- }
- else {
- /* NOTES:
- *
- * Sun/Oracle VirtualBox floppy emulation bug: PIO mode doesn't seem to be supported properly on write
- * for more than one sector. It will SEEM like it works, but when you read the data back only the first
- * sector was ever written. On the same configuration, READ works fine using the same PIO mode. */
- while (returned_length < data_length) {
- if ((returned_length+unit_length) > data_length) break;
- floppy_controller_wait_data_ready_ms(fdc,10000);
-
- p = floppy_controller_write_data_ndma(fdc,floppy_dma->lin + returned_length,unit_length);
- if (p < 0 || p > unit_length) {
- sprintf(tmp,"NDMA write failed %d (%02xh)\n",p,fdc->main_status);
- vga_write(tmp);
- p = 0;
- }
-
- returned_length += p;
- /* stop on incomplete transfer */
- if (p != unit_length) break;
- }
- }
-
- rdo = 7;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- vga_write("Write data port failed\n");
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* Write Sector (x5h) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | ST0
- * 1 | ST1
- * 2 | ST2
- * 3 | Cylinder
- * 4 | Head
- * 5 | Sector Number
- * 6 | Sector Size
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* accept ST0..ST2 from response and update */
- if (rd >= 3) {
- fdc->st[0] = resp[0];
- fdc->st[1] = resp[1];
- fdc->st[2] = resp[2];
- }
- if (rd >= 4) {
- fdc->cylinder = resp[3];
- }
-
- /* (if DMA) did we get any data? */
- if (fdc->dma >= 0 && fdc->use_dma) {
- uint32_t dma_len = d8237_read_count(fdc->dma);
- uint8_t status = inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS));
-
- /* some DMA controllers reset the count back to the original value on terminal count.
- * so if the DMA controller says terminal count, the true count is zero */
- if (status&D8237_STATUS_TC(fdc->dma)) dma_len = 0;
-
- if (dma_len > (uint32_t)data_length) dma_len = (uint32_t)data_length;
- returned_length = (unsigned int)((uint32_t)data_length - dma_len);
- }
-
- sprintf(tmp,"%lu bytes written\n",(unsigned long)returned_length);
- vga_write(tmp);
- vga_write("\n");
-
- wait_for_enter_or_escape();
-}
-
-void do_floppy_read_test(struct floppy_controller *fdc) {
- unsigned int data_length,unit_length;
- unsigned int returned_length = 0;
- char cmd[10],resp[10];
- uint8_t cyl,head,sect,ssz,nsect;
- int rd,rdo,wd,wdo,x,y,p;
-
- cyl = current_log_track;
- head = current_log_head;
- sect = current_log_sect;
- nsect = current_sectcount;
- ssz = current_sectsize_p2;
-
- if (current_sectsize_p2 > 0)
- unit_length = (128 << ssz);
- else
- unit_length = current_sectsize_smaller;
-
- data_length = nsect * unit_length;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_clear();
-
- sprintf(tmp,"Reading C/H/S/sz/num %u/%u/%u/%u/%u\n",cyl,head,sect,unit_length,nsect);
- vga_write(tmp);
-
- do_spin_up_motor(fdc,fdc->digital_out&3);
-
- if (floppy_dma == NULL) return;
- if (data_length > floppy_dma->length) {
- nsect = floppy_dma->length / unit_length;
- data_length = nsect * unit_length;
- }
- if (data_length > floppy_dma->length) return;
-
-#if TARGET_MSDOS == 32
- memset(floppy_dma->lin,0,data_length);
-#else
- _fmemset(floppy_dma->lin,0,data_length);
-#endif
-
- floppy_controller_read_status(fdc);
- if (!floppy_controller_can_write_data(fdc) || floppy_controller_busy_in_instruction(fdc))
- do_floppy_controller_reset(fdc);
-
- if (fdc->dma >= 0 && fdc->use_dma) {
- outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma) | D8237_MASK_SET); /* mask */
-
- outp(d8237_ioport(fdc->dma,D8237_REG_W_WRITE_MODE),
- D8237_MODER_CHANNEL(fdc->dma) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_WRITE) |
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
-
- d8237_write_count(fdc->dma,data_length);
- d8237_write_base(fdc->dma,floppy_dma->phys);
-
- outp(d8237_ioport(fdc->dma,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(fdc->dma)); /* unmask */
-
- inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS)); /* read status port to clear TC bits */
- }
-
- /* Read Sector (x6h)
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | MT MF SK 0 0 1 1 0
- * 1 | x x x x x HD DR1 DR0
- * 2 | Cylinder
- * 3 | Head
- * 4 | Sector Number
- * 5 | Sector Size
- * 6 | Track length/last sector
- * 7 | Length of GAP3
- * 8 | Data Length
- *
- * MT = Multi-track
- * MF = MFM/FM
- * SK = Skip deleted address mark
- * HD = Head select (on PC platform, doesn't matter)
- * DR1,DR0 = Drive select */
-
- /* NTS: To ensure we read only one sector, Track length/last sector must equal
- * Sector Number field. The floppy controller stops reading on error or when
- * sector number matches. This is very important for the PIO mode of this code,
- * else we'll never complete reading properly and never get to reading back
- * the status bytes. */
-
- wdo = 9;
- cmd[0] = (allow_multitrack?0x80:0x00)/*Multitrack*/ + (mfm_mode?0x40:0x00)/* MFM */ + 0x06/* READ DATA */;
- cmd[1] = (fdc->digital_out&3)+(current_phys_head&1?0x04:0x00)/* [1:0] = DR1,DR0 [2:2] = HD */;
- cmd[2] = cyl; /* cyl=0 */
- cmd[3] = head; /* head=0 */
- cmd[4] = sect; /* sector=1 */
- cmd[5] = ssz; /* sector size=2 (512 bytes) */
- cmd[6] = sect+nsect-1; /* last sector of the track (what sector to stop at). */
- cmd[7] = current_phys_rw_gap;
- cmd[8] = current_sectsize_smaller; /* DTL (not used if 256 or larger) */
- wd = floppy_controller_write_data(fdc,cmd,wdo);
- if (wd < 2) {
- vga_write("Write data port failed\n");
- do_floppy_controller_reset(fdc);
- return;
- }
-
- vga_write("Read in progress\n");
-
- /* fires an IRQ */
- if (fdc->use_dma) {
- if (fdc->use_irq) floppy_controller_wait_irq(fdc,10000,1); /* 10 seconds */
- floppy_controller_wait_data_ready_ms(fdc,1000);
- }
- else {
- while (returned_length < data_length) {
- if ((returned_length+unit_length) > data_length) break;
- floppy_controller_wait_data_ready_ms(fdc,10000);
-
- p = floppy_controller_read_data_ndma(fdc,floppy_dma->lin + returned_length,unit_length);
- if (p < 0 || p > unit_length) {
- sprintf(tmp,"NDMA read failed %d (%02xh)\n",p,fdc->main_status);
- vga_write(tmp);
- p = 0;
- }
-
- returned_length += p;
- /* stop on incomplete transfer */
- if (p != unit_length) break;
- }
- }
-
- rdo = 7;
- rd = floppy_controller_read_data(fdc,resp,rdo);
- if (rd < 1) {
- vga_write("Read data port failed\n");
- do_floppy_controller_reset(fdc);
- return;
- }
-
- /* Read Sector (x6h) response
- *
- * Byte | 7 6 5 4 3 2 1 0
- * -----+---------------------------------
- * 0 | ST0
- * 1 | ST1
- * 2 | ST2
- * 3 | Cylinder
- * 4 | Head
- * 5 | Sector Number
- * 6 | Sector Size
- */
-
- /* the command SHOULD terminate */
- floppy_controller_wait_data_ready(fdc,20);
- if (!floppy_controller_wait_busy_in_instruction(fdc,1000))
- do_floppy_controller_reset(fdc);
-
- /* accept ST0..ST2 from response and update */
- if (rd >= 3) {
- fdc->st[0] = resp[0];
- fdc->st[1] = resp[1];
- fdc->st[2] = resp[2];
- }
- if (rd >= 4) {
- fdc->cylinder = resp[3];
- }
-
- /* (if DMA) did we get any data? */
- if (fdc->dma >= 0 && fdc->use_dma) {
- uint32_t dma_len = d8237_read_count(fdc->dma);
- uint8_t status = inp(d8237_ioport(fdc->dma,D8237_REG_R_STATUS));
-
- /* some DMA controllers reset the count back to the original value on terminal count.
- * so if the DMA controller says terminal count, the true count is zero */
- if (status&D8237_STATUS_TC(fdc->dma)) dma_len = 0;
-
- if (dma_len > (uint32_t)data_length) dma_len = (uint32_t)data_length;
- returned_length = (unsigned int)((uint32_t)data_length - dma_len);
- }
-
- sprintf(tmp,"%lu bytes received\n",(unsigned long)returned_length);
- vga_write(tmp);
- vga_write("\n");
-
- vga_write_color(0x0F);
- for (p=0;p == 0 || p < ((returned_length+255)/256);p++) {
- for (y=0;y < 16;y++) {
- vga_moveto(0,6+y);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"%02x ",floppy_dma->lin[((y+(p*16))*16)+x]);
- vga_write(tmp);
- }
-
- vga_moveto(50,6+y);
- for (x=0;x < 16;x++) {
- tmp[0] = floppy_dma->lin[((y+(p*16))*16)+x];
- if (tmp[0] < 32) tmp[0] = '.';
- tmp[1] = 0;
- vga_write(tmp);
- }
- }
-
- if (wait_for_enter_or_escape() == 27)
- break;
- }
-}
-
-void do_floppy_controller_read_tests(struct floppy_controller *fdc) {
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- char redraw=1;
- int select=-1;
- int c;
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" Read tests ");
- sprintf(tmp,"@%X",fdc->base_io);
- vga_write(tmp);
- if (fdc->irq >= 0) {
- sprintf(tmp," IRQ %d",fdc->irq);
- vga_write(tmp);
- }
- if (fdc->dma >= 0) {
- sprintf(tmp," DMA %d",fdc->dma);
- vga_write(tmp);
- }
- if (floppy_dma != NULL) {
- sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
- vga_write(tmp);
- }
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- floppy_controller_read_status(fdc);
- floppy_controller_read_DIR(fdc);
- floppy_controller_read_ps2_status(fdc);
-
- y = 2;
- vga_moveto(8,y++);
- vga_write_color(0x0F);
- sprintf(tmp,"DOR %02xh DIR %02xh Stat %02xh CCR %02xh cyl=%-3u",
- fdc->digital_out,fdc->digital_in,
- fdc->main_status,fdc->control_cfg,
- fdc->cylinder);
- vga_write(tmp);
-
- vga_moveto(8,y++);
- vga_write_color(0x0F);
- sprintf(tmp,"ST0..3: %02x %02x %02x %02x PS/2 %02x %02x",
- fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3],
- fdc->ps2_status[0],fdc->ps2_status[1]);
- vga_write(tmp);
-
- y = 5;
- vga_moveto(8,y++);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("FDC menu");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- y++;
-
- vga_moveto(8,y++);
- vga_write_color((select == 0) ? 0x70 : 0x0F);
- vga_write("Read sector");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1) {
- break;
- }
- else if (select == 0) { /* Read Sector */
- do_floppy_read_test(fdc);
- backredraw = 1;
- }
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = 0;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > 0)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-void do_floppy_controller_write_tests(struct floppy_controller *fdc) {
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- char redraw=1;
- int select=-1;
- int c;
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" Write tests ");
- sprintf(tmp,"@%X",fdc->base_io);
- vga_write(tmp);
- if (fdc->irq >= 0) {
- sprintf(tmp," IRQ %d",fdc->irq);
- vga_write(tmp);
- }
- if (fdc->dma >= 0) {
- sprintf(tmp," DMA %d",fdc->dma);
- vga_write(tmp);
- }
- if (floppy_dma != NULL) {
- sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
- vga_write(tmp);
- }
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- floppy_controller_read_status(fdc);
- floppy_controller_read_DIR(fdc);
- floppy_controller_read_ps2_status(fdc);
-
- y = 2;
- vga_moveto(8,y++);
- vga_write_color(0x0F);
- sprintf(tmp,"DOR %02xh DIR %02xh Stat %02xh CCR %02xh cyl=%-3u",
- fdc->digital_out,fdc->digital_in,
- fdc->main_status,fdc->control_cfg,
- fdc->cylinder);
- vga_write(tmp);
-
- vga_moveto(8,y++);
- vga_write_color(0x0F);
- sprintf(tmp,"ST0..3: %02x %02x %02x %02x PS/2 %02x %02x",
- fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3],
- fdc->ps2_status[0],fdc->ps2_status[1]);
- vga_write(tmp);
-
- y = 5;
- vga_moveto(8,y++);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("FDC menu");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- y++;
-
- vga_moveto(8,y++);
- vga_write_color((select == 0) ? 0x70 : 0x0F);
- vga_write("Write sector");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1) {
- break;
- }
- else if (select == 0) { /* Write Sector */
- do_floppy_write_test(fdc);
- backredraw = 1;
- }
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = 0;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > 0)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-void prompt_position() {
- uint64_t tmp;
- int en_mfm,en_mt;
- int cyl,head,phead,sect,ssz,sszm,scount,gaprw,gapfmt;
- struct vga_msg_box box;
- unsigned char redraw=1;
- unsigned char ok=1;
- char temp_str[64];
- int select=0;
- int c,i=0;
-
- en_mfm = mfm_mode;
- en_mt = allow_multitrack;
- sszm = current_sectsize_smaller;
- gapfmt = current_phys_fmt_gap;
- gaprw = current_phys_rw_gap;
- scount = current_sectcount;
- phead = current_phys_head;
- ssz = current_sectsize_p2;
- cyl = current_log_track;
- sect = current_log_sect;
- head = current_log_head;
-
- vga_msg_box_create(&box,
- "Edit position: ",
- 2+10,0);
- while (1) {
- char recalc = 0;
- char rekey = 0;
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(box.x+2,box.y+2+1 + 0);
- vga_write_color(0x1E);
- vga_write("Cylinder: ");
- vga_write_color(select == 0 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",cyl);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 1);
- vga_write_color(0x1E);
- vga_write("Head: ");
- vga_write_color(select == 1 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",head);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 2);
- vga_write_color(0x1E);
- vga_write("Sector: ");
- vga_write_color(select == 2 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",sect);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 3);
- vga_write_color(0x1E);
- vga_write("Sect. size:");
- vga_write_color(select == 3 ? 0x70 : 0x1E);
- if (ssz > 0)
- i=sprintf(temp_str,"%u",128 << ssz);
- else
- i=sprintf(temp_str,"%u",sszm);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 4);
- vga_write_color(0x1E);
- vga_write("Phys. Head:");
- vga_write_color(select == 4 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",phead);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 5);
- vga_write_color(0x1E);
- vga_write("Sect count:");
- vga_write_color(select == 5 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",scount);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 6);
- vga_write_color(0x1E);
- vga_write("Multitrack:");
- vga_write_color(select == 6 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%s",en_mt?"On":"Off");
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 7);
- vga_write_color(0x1E);
- vga_write("FM/MFM: ");
- vga_write_color(select == 7 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%s",en_mfm?"MFM":"FM");
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 8);
- vga_write_color(0x1E);
- vga_write("R/W gap: ");
- vga_write_color(select == 8 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",gaprw);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 9);
- vga_write_color(0x1E);
- vga_write("Fmt gap: ");
- vga_write_color(select == 9 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",gapfmt);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
-nextkey: if (c == 27) {
- ok = 0;
- break;
- }
- else if (c == 13) {
- ok = 1;
- break;
- }
- else if (c == 0x4800) {
- if (--select < 0) select = 9;
- redraw = 1;
- }
- else if (c == 0x5000 || c == 9/*tab*/) {
- if (++select > 9) select = 0;
- redraw = 1;
- }
-
- else if (c == 0x4B00) { /* left */
- switch (select) {
- case 0:
- if (cyl == 0) cyl = 255;
- else cyl--;
- break;
- case 1:
- if (head == 0) head = 255;
- else head--;
- break;
- case 2:
- if (sect == 0) sect = 255;
- else sect--;
- break;
- case 3:
- if (ssz == 0) {
- if (sszm <= 1) {
- sszm = 0xFF;
- ssz = 7;
- }
- else {
- sszm--;
- }
- }
- else {
- ssz--;
- }
- break;
- case 4:
- if (phead == 0) phead = 1;
- else phead--;
- break;
- case 5:
- if (scount <= 1) scount = 256;
- else scount--;
- break;
- case 6:
- en_mt = !en_mt;
- break;
- case 7:
- en_mfm = !en_mfm;
- break;
- case 8:
- if (gaprw == 0) gaprw = 255;
- else gaprw--;
- break;
- case 9:
- if (gapfmt == 0) gapfmt = 255;
- else gapfmt--;
- break;
- };
-
- recalc = 1;
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- switch (select) {
- case 0:
- if ((++cyl) >= 256) cyl = 0;
- break;
- case 1:
- if ((++head) >= 256) head = 0;
- break;
- case 2:
- if ((++sect) >= 256) sect = 0;
- break;
- case 3:
- if (ssz == 0) {
- if ((++sszm) > 255) {
- sszm = 0xFF;
- ssz = 1;
- }
- }
- else {
- if ((++ssz) > 7) {
- ssz = 0;
- sszm = 1;
- }
- }
- break;
- case 4:
- if ((++phead) >= 2) phead = 0;
- break;
- case 5:
- if ((++scount) >= 257) scount = 1;
- break;
- case 6:
- en_mt = !en_mt;
- break;
- case 7:
- en_mfm = !en_mfm;
- break;
- case 8:
- if (gaprw == 255) gaprw = 0;
- else gaprw++;
- break;
- case 9:
- if (gapfmt == 255) gapfmt = 0;
- else gapfmt++;
- break;
- };
-
- recalc = 1;
- redraw = 1;
- }
-
- else if ((c == 8 || isdigit(c)) && (select != 6 && select != 7)) {
- unsigned int sy = box.y+2+1 + select;
- unsigned int sx = box.x+2+11;
-
- switch (select) {
- case 0: sprintf(temp_str,"%u",cyl); break;
- case 1: sprintf(temp_str,"%u",head); break;
- case 2: sprintf(temp_str,"%u",sect); break;
- case 3: sprintf(temp_str,"%u",ssz != 0 ? (128 << ssz) : sszm); break;
- case 4: sprintf(temp_str,"%u",phead); break;
- case 5: sprintf(temp_str,"%u",scount); break;
- case 8: sprintf(temp_str,"%u",gaprw); break;
- case 9: sprintf(temp_str,"%u",gapfmt); break;
- }
-
- if (c == 8) {
- i = strlen(temp_str) - 1;
- if (i < 0) i = 0;
- temp_str[i] = 0;
- }
- else {
- i = strlen(temp_str);
- if (i == 1 && temp_str[0] == '0') i--;
- if ((i+2) < sizeof(temp_str)) {
- temp_str[i++] = (char)c;
- temp_str[i] = 0;
- }
- }
-
- redraw = 1;
- while (1) {
- if (redraw) {
- redraw = 0;
- vga_moveto(sx,sy);
- vga_write_color(0x70);
- vga_write(temp_str);
- while (vga_pos_x < (box.x+box.w-4) && vga_pos_x != 0) vga_writec(' ');
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 8) {
- if (i > 0) {
- temp_str[--i] = 0;
- redraw = 1;
- }
- }
- else if (isdigit(c)) {
- if ((i+2) < sizeof(temp_str)) {
- temp_str[i++] = (char)c;
- temp_str[i] = 0;
- redraw = 1;
- }
- }
- else {
- break;
- }
- }
-
- switch (select) {
- case 0: tmp=strtoull(temp_str,NULL,0); cyl=(tmp > 255ULL ? 255ULL : tmp); break;
- case 1: tmp=strtoull(temp_str,NULL,0); head=(tmp > 255ULL ? 255ULL : tmp); break;
- case 2: tmp=strtoull(temp_str,NULL,0); sect=(tmp > 255ULL ? 255ULL : tmp); break;
- case 3:
- tmp=strtoull(temp_str,NULL,0);
- if (tmp > 16384ULL) tmp = 16384ULL;
- if (tmp >= 256UL) {
- ssz=1; /* 256 */
- while ((128<<ssz) < (unsigned int)tmp) ssz++;
- }
- else {
- ssz=0;
- sszm=(unsigned int)tmp;
- }
- break;
- case 4: tmp=strtoull(temp_str,NULL,0); phead=(tmp > 1ULL ? 1ULL : tmp); break;
- case 5: tmp=strtoull(temp_str,NULL,0); scount=(tmp > 256ULL ? 256ULL : tmp);
- if (scount == 0) scount = 1;
- break;
- case 8: tmp=strtoull(temp_str,NULL,0); gaprw=(tmp > 255ULL ? 255ULL : tmp); break;
- case 9: tmp=strtoull(temp_str,NULL,0); gapfmt=(tmp > 255ULL ? 255ULL : tmp); break;
- }
-
- rekey = 1;
- recalc = 1;
- }
-
- if (rekey) {
- rekey = 0;
- goto nextkey;
- }
- }
- vga_msg_box_destroy(&box);
-
- if (ok) {
- mfm_mode = en_mfm;
- allow_multitrack = en_mt;
- current_sectsize_smaller = sszm;
- current_phys_fmt_gap = gapfmt;
- current_phys_rw_gap = gaprw;
- current_sectcount = scount;
- current_phys_head = phead;
- current_sectsize_p2 = ssz;
- current_log_track = cyl;
- current_log_sect = sect;
- current_log_head = head;
- }
-}
-
-void do_floppy_controller(struct floppy_controller *fdc) {
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- char redraw=1;
- int select=-1;
- int c;
-
- /* and allocate DMA too */
- if (fdc->dma >= 0 && floppy_dma == NULL) {
-#if TARGET_MSDOS == 32
- uint32_t choice = 65536;
-#else
- uint32_t choice = 32768;
-#endif
-
- do {
- floppy_dma = dma_8237_alloc_buffer(choice);
- if (floppy_dma == NULL) choice -= 4096UL;
- } while (floppy_dma == NULL && choice > 4096UL);
-
- if (floppy_dma == NULL) return;
- }
-
- /* if the floppy struct says to use interrupts, then do it */
- do_floppy_controller_enable_irq(fdc,fdc->use_irq);
- floppy_controller_enable_dma(fdc,fdc->use_dma);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" Floppy controller ");
- sprintf(tmp,"@%X",fdc->base_io);
- vga_write(tmp);
- if (fdc->irq >= 0) {
- sprintf(tmp," IRQ %d",fdc->irq);
- vga_write(tmp);
- }
- if (fdc->dma >= 0) {
- sprintf(tmp," DMA %d",fdc->dma);
- vga_write(tmp);
- }
- if (floppy_dma != NULL) {
- sprintf(tmp," phys=%08lxh len=%04lxh",(unsigned long)floppy_dma->phys,(unsigned long)floppy_dma->length);
- vga_write(tmp);
- }
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- int cx = vga_width / 2;
-
- redraw = 0;
-
- floppy_controller_read_status(fdc);
- floppy_controller_read_DIR(fdc);
- floppy_controller_read_ps2_status(fdc);
-
- y = 2;
- vga_moveto(8,y++);
- vga_write_color(0x0F);
- sprintf(tmp,"DOR %02xh DIR %02xh Stat %02xh CCR %02xh cyl=%-3u ver=%02xh",
- fdc->digital_out,fdc->digital_in,
- fdc->main_status,fdc->control_cfg,
- fdc->cylinder, fdc->version);
- vga_write(tmp);
-
- vga_moveto(8,y++);
- vga_write_color(0x0F);
- sprintf(tmp,"ST0..3: %02x %02x %02x %02x PS/2 %02x %02x",
- fdc->st[0],fdc->st[1],fdc->st[2],fdc->st[3],
- fdc->ps2_status[0],fdc->ps2_status[1]);
- vga_write(tmp);
-
- y = 5;
- vga_moveto(8,y++);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Main menu");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- y++;
-
- vga_moveto(8,y++);
- vga_write_color((select == 0) ? 0x70 : 0x0F);
- vga_write("DMA: ");
- vga_write(fdc->use_dma ? "Enabled" : "Disabled");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 1) ? 0x70 : 0x0F);
- vga_write("IRQ: ");
- vga_write(fdc->use_irq ? "Enabled" : "Disabled");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 2) ? 0x70 : 0x0F);
- vga_write("Drive A motor: ");
- vga_write((fdc->digital_out&0x10) ? "On" : "Off");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 3) ? 0x70 : 0x0F);
- vga_write("Drive B motor: ");
- vga_write((fdc->digital_out&0x20) ? "On" : "Off");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 4) ? 0x70 : 0x0F);
- vga_write("Drive C motor: ");
- vga_write((fdc->digital_out&0x40) ? "On" : "Off");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 5) ? 0x70 : 0x0F);
- vga_write("Drive D motor: ");
- vga_write((fdc->digital_out&0x80) ? "On" : "Off");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 6) ? 0x70 : 0x0F);
- vga_write("Drive select: ");
- sprintf(tmp,"%c(%u)",(fdc->digital_out&3)+'A',fdc->digital_out&3);
- vga_write(tmp);
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 7) ? 0x70 : 0x0F);
- vga_write("Data rate: ");
- switch (fdc->control_cfg&3) {
- case 0: vga_write("500kbit/sec"); break;
- case 1: vga_write("300kbit/sec"); break;
- case 2: vga_write("250kbit/sec"); break;
- case 3: vga_write("1mbit/sec"); break;
- };
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 8) ? 0x70 : 0x0F);
- vga_write("Reset signal: ");
- vga_write((fdc->digital_out&0x04) ? "Off" : "On");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 9) ? 0x70 : 0x0F);
- vga_write("Pos log C/H/S/sz/cnt: ");
- sprintf(tmp,"%u/%u/%u/%u/%u phyH=%u MT=%u %s",
- current_log_track,
- current_log_head,
- current_log_sect,
- current_sectsize_p2 > 0 ? (128 << current_sectsize_p2) : current_sectsize_smaller,
- current_sectcount,
- current_phys_head,
- allow_multitrack,
- mfm_mode?"MFM":"FM");
-
- vga_write(tmp);
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- y++;
-
- vga_moveto(8,y++);
- vga_write_color((select == 10) ? 0x70 : 0x0F);
- vga_write("Check drive status (x4h)");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 11) ? 0x70 : 0x0F);
- vga_write("Calibrate (x7h)");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 12) ? 0x70 : 0x0F);
- vga_write("Seek (xFh)");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 13) ? 0x70 : 0x0F);
- vga_write("Seek relative (1xFh)");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 14) ? 0x70 : 0x0F);
- vga_write("Read sector ID (xAh)");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 15) ? 0x70 : 0x0F);
- vga_write("Read testing >>");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 16) ? 0x70 : 0x0F);
- vga_write("Write testing >>");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 17) ? 0x70 : 0x0F);
- vga_write("Dump Registers (xEh)");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 18) ? 0x70 : 0x0F);
- vga_write("Get Version (1x0h)");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color((select == 19) ? 0x70 : 0x0F);
- vga_write("Format Track (xDh)");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 20) ? 0x70 : 0x0F);
- vga_write("Step through tracks");
- while (vga_pos_x < cx && vga_pos_x != 0) vga_writec(' ');
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1) {
- break;
- }
- else if (select == 0) { /* DMA enable */
- fdc->non_dma_mode = !fdc->non_dma_mode;
- if (do_floppy_controller_specify(fdc)) /* if specify fails, don't change DMA flag */
- floppy_controller_enable_dma(fdc,!fdc->non_dma_mode); /* enable DMA = !(non-dma-mode) */
- else
- fdc->non_dma_mode = !fdc->non_dma_mode;
-
- redraw = 1;
- }
- else if (select == 1) { /* IRQ enable */
- do_floppy_controller_enable_irq(fdc,!fdc->use_irq);
- redraw = 1;
- }
- else if (select == 2) { /* Drive A motor */
- floppy_controller_set_motor_state(fdc,0/*A*/,!(fdc->digital_out&0x10));
- redraw = 1;
- }
- else if (select == 3) { /* Drive B motor */
- floppy_controller_set_motor_state(fdc,1/*B*/,!(fdc->digital_out&0x20));
- redraw = 1;
- }
- else if (select == 4) { /* Drive C motor */
- floppy_controller_set_motor_state(fdc,2/*C*/,!(fdc->digital_out&0x40));
- redraw = 1;
- }
- else if (select == 5) { /* Drive D motor */
- floppy_controller_set_motor_state(fdc,3/*D*/,!(fdc->digital_out&0x80));
- redraw = 1;
- }
- else if (select == 6) { /* Drive select */
- floppy_controller_drive_select(fdc,((fdc->digital_out&3)+1)&3);
- redraw = 1;
- }
- else if (select == 7) { /* Transfer rate */
- floppy_controller_set_data_transfer_rate(fdc,((fdc->control_cfg&3)+1)&3);
- redraw = 1;
- }
- else if (select == 8) { /* reset */
- floppy_controller_set_reset(fdc,!!(fdc->digital_out&0x04)); /* bit is INVERTED 1=normal 0=reset */
- redraw = 1;
- }
- else if (select == 9) { /* Position */
- prompt_position();
- redraw = 1;
- }
- else if (select == 10) { /* check drive status */
- do_check_drive_status(fdc);
- redraw = 1;
- }
- else if (select == 11) { /* calibrate drive */
- do_calibrate_drive(fdc);
- redraw = 1;
- }
- else if (select == 12) { /* seek */
- unsigned long track = prompt_track_number();
- if (track != (~0UL) && track < 256) {
- do_seek_drive(fdc,(uint8_t)track);
- redraw = 1;
- }
- }
- else if (select == 13) { /* seek relative */
- signed long track = prompt_signed_track_number();
- if (track >= -255L && track <= 255L) {
- do_seek_drive_rel(fdc,(int)track);
- redraw = 1;
- }
- }
- else if (select == 14) { /* read sector ID */
- do_read_sector_id_demo(fdc);
- backredraw = 1;
- }
- else if (select == 15) { /* read testing */
- do_floppy_controller_read_tests(fdc);
- backredraw = 1;
- }
- else if (select == 16) { /* write testing */
- do_floppy_controller_write_tests(fdc);
- backredraw = 1;
- }
- else if (select == 17) { /* dump registers */
- do_floppy_dumpreg(fdc);
- }
- else if (select == 18) { /* get version */
- do_floppy_get_version(fdc);
- redraw = 1;
- }
- else if (select == 19) { /* format track */
- do_floppy_format_track(fdc);
- backredraw = 1;
- }
- else if (select == 20) { /* step through tracks */
- do_step_tracks(fdc);
- backredraw = 1;
- }
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = 20;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > 20)
- select = -1;
-
- redraw = 1;
- }
- }
-
- if (floppy_dma != NULL) {
- dma_8237_free_buffer(floppy_dma);
- floppy_dma = NULL;
- }
-
- do_floppy_controller_enable_irq(fdc,0);
- floppy_controller_enable_irqdma_gate_otr(fdc,1); /* because BIOSes probably won't */
- p8259_unmask(fdc->irq);
-}
-
-void do_main_menu() {
- char redraw=1;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- struct floppy_controller *floppy;
- unsigned int x,y,i;
- int select=-1;
- int c;
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" Floppy controller test program");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- y = 5;
- vga_moveto(8,y++);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Exit program");
- y++;
-
- for (i=0;i < MAX_FLOPPY_CONTROLLER;i++) {
- floppy = floppy_get_controller(i);
- if (floppy != NULL) {
- vga_moveto(8,y++);
- vga_write_color((select == (int)i) ? 0x70 : 0x0F);
-
- sprintf(tmp,"Controller @ %04X",floppy->base_io);
- vga_write(tmp);
-
- if (floppy->irq >= 0) {
- sprintf(tmp," IRQ %2d",floppy->irq);
- vga_write(tmp);
- }
-
- if (floppy->dma >= 0) {
- sprintf(tmp," DMA %2d",floppy->dma);
- vga_write(tmp);
- }
- }
- }
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1) {
- break;
- }
- else if (select >= 0 && select < MAX_FLOPPY_CONTROLLER) {
- floppy = floppy_get_controller(select);
- if (floppy != NULL) do_floppy_controller(floppy);
- backredraw = redraw = 1;
- }
- }
- else if (c == 0x4800) {
- if (select <= -1)
- select = MAX_FLOPPY_CONTROLLER - 1;
- else
- select--;
-
- while (select >= 0 && floppy_get_controller(select) == NULL)
- select--;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- select++;
- while (select >= 0 && select < MAX_FLOPPY_CONTROLLER && floppy_get_controller(select) == NULL)
- select++;
- if (select >= MAX_FLOPPY_CONTROLLER)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-int main(int argc,char **argv) {
- struct floppy_controller *reffdc;
- struct floppy_controller *newfdc;
- int i;
-
- /* we take a GUI-based approach (kind of) */
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
- if (!probe_8237())
- printf("WARNING: Cannot init 8237 DMA\n");
- /* the floppy code has some timing requirements and we'll use the 8254 to do it */
- /* newer motherboards don't even have a floppy controller and it's probable they'll stop implementing the 8254 at some point too */
- if (!probe_8254()) {
- printf("8254 chip not detected\n");
- return 1;
- }
- if (!probe_8259()) {
- printf("8259 chip not detected\n");
- return 1;
- }
- if (!init_floppy_controller_lib()) {
- printf("Failed to init floppy controller\n");
- return 1;
- }
-
- printf("Probing standard FDC ports...\n");
- for (i=0;(reffdc = (struct floppy_controller*)floppy_get_standard_isa_port(i)) != NULL;i++) {
- printf(" %3X IRQ %d DMA %d: ",reffdc->base_io,reffdc->irq,reffdc->dma); fflush(stdout);
-
- if ((newfdc = floppy_controller_probe(reffdc)) != NULL) {
- printf("FOUND. PS/2=%u AT=%u dma=%u DOR/RW=%u DOR=%02xh DIR=%02xh mst=%02xh\n",
- newfdc->ps2_mode,
- newfdc->at_mode,
- newfdc->use_dma,
- newfdc->digital_out_rw,
- newfdc->digital_out,
- newfdc->digital_in,
- newfdc->main_status);
- }
- else {
- printf("\x0D \x0D"); fflush(stdout);
- }
- }
-
- printf("Hit ENTER to continue, ESC to cancel\n");
- i = wait_for_enter_or_escape();
- if (i == 27) {
- free_floppy_controller_lib();
- return 0;
- }
-
- do_main_menu();
- free_floppy_controller_lib();
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_IDE_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = idelib.c
-OBJS = $(SUBDIR)$(HPS)idelib.obj $(SUBDIR)$(HPS)idelib.obj
-
-!ifeq TARGET_MSDOS 16
-! ifeq MMODE c
-# this test program isn't going to fit in the compact memory model. sorry.
-NO_TEST_EXE=1
-! endif
-!endif
-
-!ifndef NO_TEST_EXE
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-!endif
-
-$(HW_IDE_LIB): $(OBJS)
- wlib -q -b -c $(HW_IDE_LIB) -+$(SUBDIR)$(HPS)idelib.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_IDE_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-!ifdef TEST_EXE
-$(TEST_EXE): $(HW_IDE_LIB) $(HW_IDE_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(SUBDIR)$(HPS)testutil.obj $(SUBDIR)$(HPS)testmbox.obj $(SUBDIR)$(HPS)testcmui.obj $(SUBDIR)$(HPS)testbusy.obj $(SUBDIR)$(HPS)testnop.obj $(SUBDIR)$(HPS)testpwr.obj $(SUBDIR)$(HPS)testpiom.obj $(SUBDIR)$(HPS)testpiot.obj $(SUBDIR)$(HPS)testrvfy.obj $(SUBDIR)$(HPS)testrdwr.obj $(SUBDIR)$(HPS)testidnt.obj $(SUBDIR)$(HPS)testcdej.obj $(SUBDIR)$(HPS)testtadj.obj $(SUBDIR)$(HPS)testcdrm.obj $(SUBDIR)$(HPS)testmumo.obj $(SUBDIR)$(HPS)testrdts.obj $(SUBDIR)$(HPS)testrdtv.obj $(SUBDIR)$(HPS)testrdws.obj $(SUBDIR)$(HPS)testmisc.obj $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_VGAGUI_LIB) $(HW_VGAGUI_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_PCI_LIB) $(HW_PCI_LIB_DEPENDENCIES) $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj file $(SUBDIR)$(HPS)testutil.obj file $(SUBDIR)$(HPS)testmbox.obj file $(SUBDIR)$(HPS)testcmui.obj file $(SUBDIR)$(HPS)testbusy.obj file $(SUBDIR)$(HPS)testnop.obj file $(SUBDIR)$(HPS)testpwr.obj file $(SUBDIR)$(HPS)testpiom.obj file $(SUBDIR)$(HPS)testpiot.obj file $(SUBDIR)$(HPS)testrvfy.obj file $(SUBDIR)$(HPS)testrdwr.obj file $(SUBDIR)$(HPS)testidnt.obj file $(SUBDIR)$(HPS)testcdej.obj file $(SUBDIR)$(HPS)testtadj.obj file $(SUBDIR)$(HPS)testcdrm.obj file $(SUBDIR)$(HPS)testmumo.obj file $(SUBDIR)$(HPS)testrdts.obj file $(SUBDIR)$(HPS)testrdtv.obj file $(SUBDIR)$(HPS)testrdws.obj file $(SUBDIR)$(HPS)testmisc.obj $(HW_IDE_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_VGAGUI_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_PCI_LIB_WLINK_LIBRARIES) $(HW_ISAPNP_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
-! ifeq TARGET_MSDOS 16
- %write tmp.cmd option stack=12k
-! endif
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_IDE_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/ide/idelib.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-
-struct ide_controller ide_controller[MAX_IDE_CONTROLLER];
-int8_t idelib_init = -1;
-
-const struct ide_controller ide_isa_standard[2] = {
- /*base alt fired irq flags*/
- {0x1F0,0x3F6,0,14,{0}},
- {0x170,0x376,0,15,{0}}
-};
-
-const struct ide_controller *idelib_get_standard_isa_port(int i) {
- if (i < 0 || i >= 4) return NULL;
- return &ide_isa_standard[i];
-}
-
-int init_idelib() {
- if (idelib_init < 0) {
- memset(ide_controller,0,sizeof(ide_controller));
- idelib_init = 0;
-
- cpu_probe();
- probe_dos();
- detect_windows();
-
- /* do NOT under any circumstances talk directly to IDE from under Windows! */
- if (windows_mode != WINDOWS_NONE) return (idelib_init=0);
-
- /* init OK */
- idelib_init = 1;
- }
-
- return (int)idelib_init;
-}
-
-void free_idelib() {
-}
-
-void idelib_controller_update_status(struct ide_controller *ide) {
- if (ide == NULL) return;
- ide->last_status = inp(ide->alt_io != 0 ? /*0x3F6-ish status*/ide->alt_io : /*status register*/(ide->base_io+7));
- if (ide->alt_io != 0) ide->drive_address = inp(ide->alt_io+1);
-
- /* if the IDE controller is NOT busy, then also note the status according to the selected drive's taskfile */
- if (!(ide->last_status&0x80)) ide->taskfile[ide->selected_drive].status = ide->last_status;
-}
-
-int idelib_controller_is_busy(struct ide_controller *ide) {
- if (ide == NULL) return 0;
- return !!(ide->last_status&0x80);
-}
-
-int idelib_controller_is_error(struct ide_controller *ide) {
- if (ide == NULL) return 0;
- return !!(ide->last_status&0x01) && !(ide->last_status&0x80)/*and not busy*/;
-}
-
-int idelib_controller_is_drq_ready(struct ide_controller *ide) {
- if (ide == NULL) return 0;
- return !!(ide->last_status&0x08) && !(ide->last_status&0x80)/*and not busy*/;
-}
-
-int idelib_controller_is_drive_ready(struct ide_controller *ide) {
- if (ide == NULL) return 0;
- return !!(ide->last_status&0x40) && !(ide->last_status&0x80)/*and not busy*/;
-}
-
-int idelib_controller_allocated(struct ide_controller *ide) {
- if (ide == NULL) return 0;
- return (ide->base_io != 0);
-}
-
-struct ide_controller *idelib_get_controller(int i) {
- if (i < 0 || i >= MAX_IDE_CONTROLLER) return NULL;
- if (!idelib_controller_allocated(&ide_controller[i])) return NULL;
- return &ide_controller[i];
-}
-
-/* NTS: The controller is "allocated" if the base I/O port is nonzero.
- * Therefore, if the caller never fills in base_io, it remains
- * unallocated, and next call the same struct is returned. */
-struct ide_controller *idelib_new_controller() {
- int i;
-
- for (i=0;i < MAX_IDE_CONTROLLER;i++) {
- if (!idelib_controller_allocated(&ide_controller[i]))
- return &ide_controller[i];
- }
-
- return NULL;
-}
-
-struct ide_controller *idelib_by_base_io(uint16_t io) {
- int i;
-
- if (io == 0)
- return NULL;
-
- for (i=0;i < MAX_IDE_CONTROLLER;i++) {
- if (ide_controller[i].base_io == io)
- return &ide_controller[i];
- }
-
- return NULL;
-}
-
-struct ide_controller *idelib_by_alt_io(uint16_t io) {
- int i;
-
- if (io == 0)
- return NULL;
-
- for (i=0;i < MAX_IDE_CONTROLLER;i++) {
- if (ide_controller[i].alt_io == io)
- return &ide_controller[i];
- }
-
- return NULL;
-}
-
-struct ide_controller *idelib_by_irq(int8_t irq) {
- int i;
-
- if (irq < 0)
- return NULL;
-
- for (i=0;i < MAX_IDE_CONTROLLER;i++) {
- if (ide_controller[i].irq == irq)
- return &ide_controller[i];
- }
-
- return NULL;
-}
-
-/* To explain: an IDE controller struct is passed in by the caller
- * only to describe what resources to use. A completely new IDE
- * controller struct is allocated and initialized based on what
- * we were given. The caller can then dispose of the original
- * struct. This gives the caller freedom to declare a struct on
- * the stack and use it without consequences. */
-struct ide_controller *idelib_probe(struct ide_controller *ide) {
- struct ide_controller *newide = NULL;
- uint16_t alt_io = 0;
- int8_t irq = -1;
-
- /* allocate a new empty slot. bail if all are full */
- newide = idelib_new_controller();
- if (newide == NULL)
- return NULL;
-
- /* we can work with the controller if alt_io is zero or irq < 0, but we
- * require the base_io to be valid */
- if (ide->base_io == 0)
- return NULL;
-
- /* IDE I/O is always 8-port aligned */
- if ((ide->base_io & 7) != 0)
- return NULL;
-
- /* alt I/O if present is always 8-port aligned and at the 6th port */
- if (ide->alt_io != 0 && (ide->alt_io & 1) != 0)
- return NULL;
-
- /* don't probe if base io already taken */
- if (idelib_by_base_io(ide->base_io) != NULL)
- return NULL;
-
- irq = ide->irq;
-
- /* if the alt io conflicts, then don't use it */
- alt_io = ide->alt_io;
- if (alt_io != 0 && idelib_by_alt_io(alt_io) != NULL)
- alt_io = 0;
-
- /* the alt I/O port is supposed to be readable, and it usually exists as a
- * mirror of what you read from the status port (+7). and there's no
- * conceivable reason I know of that the controller would happen to be busy
- * at this point in execution.
- *
- * NTS: we could reset the hard drives here as part of the test, but that might
- * not be wise in case the BIOS is cheap and sets up the controller only
- * once the way it expects.u */
- if (alt_io != 0 && inp(alt_io) == 0xFF)
- alt_io = 0;
-
- /* TODO: come up with a more comprehensive IDE I/O port test routine.
- * but one that reliably detects without changing hard disk state. */
- if (inp(ide->base_io+7) == 0xFF)
- return NULL;
-
- newide->drive_address = 0;
- newide->pio32_atapi_command = 0; /* always assume ATAPI packet commands are to be written with 16-bit PIO */
- newide->pio_width = IDELIB_PIO_WIDTH_16; /* always default to 16-bit PIO */
- newide->irq_fired = 0;
- newide->irq = irq;
- newide->flags.io_irq_enable = (newide->irq >= 0) ? 1 : 0; /* unless otherwise known, use the IRQ */
- newide->base_io = ide->base_io;
- newide->alt_io = alt_io;
-
- idelib_controller_update_taskfile(newide,0xFF/*all registers*/,IDELIB_TASKFILE_SELECTED_UPDATE);
-
- newide->device_control = 0x08+(newide->flags.io_irq_enable?0x00:0x02); /* can't read device control but we can guess */
- if (ide->alt_io != 0) outp(ide->alt_io,newide->device_control);
-
- /* construct IDE taskfile from register contents */
- memset(&newide->taskfile,0,sizeof(newide->taskfile));
- newide->taskfile[newide->selected_drive].head_select = newide->head_select;
-
- return newide;
-}
-
-void ide_vlb_sync32_pio(struct ide_controller *ide) {
- inp(ide->base_io+2);
- inp(ide->base_io+2);
- inp(ide->base_io+2);
-}
-
-void idelib_controller_drive_select(struct ide_controller *ide,unsigned char which/*1=slave 0=master*/,unsigned char head/*CHS mode head value*/,unsigned char mode/*upper 3 bits*/) {
- if (ide == NULL) return;
- ide->head_select = ((which&1)<<4) + (head&0xF) + ((mode&7)<<5);
- outp(ide->base_io+6/*0x1F6*/,ide->head_select);
-
- /* and let it apply to whatever drive it selects */
- ide->selected_drive = (ide->head_select >> 4) & 1;
- ide->taskfile[ide->selected_drive].head_select = ide->head_select;
-}
-
-void idelib_otr_enable_interrupt(struct ide_controller *ide,unsigned char en) { /* "off the record" interrupt control */
- if (en) {
- if (!(ide->device_control&0x02)) /* if nIEN=0 already do nothing */
- return;
-
- /* force clear IRQ */
- inp(ide->base_io+7);
-
- /* enable at IDE controller */
- if (ide->alt_io != 0) idelib_write_device_control(ide,0x08); /* nIEN=0 (enable) and not reset */
- else ide->device_control = 0x00; /* fake it */
- }
- else {
- if (ide->device_control&0x02) /* if nIEN=1 already do nothing */
- return;
-
- /* disable at IDE controller */
- if (ide->alt_io != 0) idelib_write_device_control(ide,0x08+0x02); /* nIEN=1 (disable) and not reset */
- else ide->device_control = 0x02; /* fake it */
- }
-}
-
-void idelib_enable_interrupt(struct ide_controller *ide,unsigned char en) {
- if (en) {
- if (!(ide->device_control&0x02)) /* if nIEN=0 already do nothing */
- return;
-
- ide->flags.io_irq_enable = 1;
- ide->irq_fired = 0;
-
- /* force clear IRQ */
- inp(ide->base_io+7);
-
- /* enable at IDE controller */
- if (ide->alt_io != 0) idelib_write_device_control(ide,0x08); /* nIEN=0 (enable) and not reset */
- else ide->device_control = 0x00; /* fake it */
- }
- else {
- if (ide->device_control&0x02) /* if nIEN=1 already do nothing */
- return;
-
- /* disable at IDE controller */
- if (ide->alt_io != 0) idelib_write_device_control(ide,0x08+0x02); /* nIEN=1 (disable) and not reset */
- else ide->device_control = 0x02; /* fake it */
-
- ide->flags.io_irq_enable = 0;
- ide->irq_fired = 0;
- }
-}
-
-int idelib_controller_apply_taskfile(struct ide_controller *ide,unsigned char portmask,unsigned char flags) {
- if (portmask & 0x80/*base+7*/) {
- /* if the IDE controller is busy we cannot apply the taskfile */
- ide->last_status = inp(ide->alt_io != 0 ? /*0x3F6-ish status*/ide->alt_io : /*status register*/(ide->base_io+7));
- if (ide->last_status&0x80) return -1; /* if the controller is busy, then the other registers have no meaning */
- }
- if (portmask & 0x40/*base+6*/) {
- /* we do not write the head/drive select/mode here but we do note what was written */
- /* if writing the taskfile would select a different drive or head, then error out */
- ide->head_select = inp(ide->base_io+6);
- if (ide->selected_drive != ((ide->head_select >> 4) & 1)) return -1;
- if ((ide->head_select&0x10) != (ide->taskfile[ide->selected_drive].head_select&0x10)) return -1;
- outp(ide->base_io+6,ide->taskfile[ide->selected_drive].head_select);
- }
-
- if (flags&IDELIB_TASKFILE_LBA48_UPDATE)
- ide->taskfile[ide->selected_drive].assume_lba48 = (flags&IDELIB_TASKFILE_LBA48)?1:0;
-
- /* and read back the upper 3 bits for the current mode, to detect LBA48 commands.
- * NTS: Unfortunately some implementations, even though you wrote 0x4x, will return 0xEx regardless,
- * so it's not really that easy. In that case, the only way to know is if the flags are set
- * in the taskfile indicating that an LBA48 command was issued. */
- if (ide->taskfile[ide->selected_drive].assume_lba48/*we KNOW we issued an LBA48 command*/ ||
- (ide->head_select&0xE0) == 0x40/*LBA48 command was issued (NTS: but most IDE controllers replace with 0xE0, so...)*/) {
- /* write 16 bits to 0x1F2-0x1F5 */
- if (portmask & 0x04) {
- outp(ide->base_io+2,ide->taskfile[ide->selected_drive].sector_count>>8);
- outp(ide->base_io+2,ide->taskfile[ide->selected_drive].sector_count);
- }
- if (portmask & 0x08) {
- outp(ide->base_io+3,ide->taskfile[ide->selected_drive].lba0_3>>8);
- outp(ide->base_io+3,ide->taskfile[ide->selected_drive].lba0_3);
- }
- if (portmask & 0x10) {
- outp(ide->base_io+4,ide->taskfile[ide->selected_drive].lba1_4>>8);
- outp(ide->base_io+4,ide->taskfile[ide->selected_drive].lba1_4);
- }
- if (portmask & 0x20) {
- outp(ide->base_io+5,ide->taskfile[ide->selected_drive].lba2_5>>8);
- outp(ide->base_io+5,ide->taskfile[ide->selected_drive].lba2_5);
- }
- }
- else {
- if (portmask & 0x04)
- outp(ide->base_io+2,ide->taskfile[ide->selected_drive].sector_count);
- if (portmask & 0x08)
- outp(ide->base_io+3,ide->taskfile[ide->selected_drive].lba0_3);
- if (portmask & 0x10)
- outp(ide->base_io+4,ide->taskfile[ide->selected_drive].lba1_4);
- if (portmask & 0x20)
- outp(ide->base_io+5,ide->taskfile[ide->selected_drive].lba2_5);
- }
-
- if (portmask & 0x02)
- outp(ide->base_io+1,ide->taskfile[ide->selected_drive].features);
-
- /* and finally, the command */
- if (portmask & 0x80/*base+7*/) {
- outp(ide->base_io+7,ide->taskfile[ide->selected_drive].command);
- ide->last_status = inp(ide->alt_io != 0 ? /*0x3F6-ish status*/ide->alt_io : /*status register*/(ide->base_io+7));
- }
-
- return 0;
-}
-
-int idelib_controller_update_taskfile(struct ide_controller *ide,unsigned char portmask,unsigned char flags) {
- if (portmask & 0x80/*base+7*/) {
- ide->last_status = inp(ide->alt_io != 0 ? /*0x3F6-ish status*/ide->alt_io : /*status register*/(ide->base_io+7));
- if (ide->last_status&0x80) return -1; /* if the controller is busy, then the other registers have no meaning */
- }
-
- if (portmask & 0x40/*base+6*/) {
- /* NTS: we do not pay attention to the drive select bit, because some IDE implementations
- * will read back the wrong value especially if only a slave is connected to the chain, no master */
- ide->head_select = inp(ide->base_io+6);
- if (ide->alt_io != 0) ide->drive_address = inp(ide->alt_io+1);
- ide->taskfile[ide->selected_drive].head_select = ide->head_select;
- }
-
- if (flags&IDELIB_TASKFILE_LBA48_UPDATE)
- ide->taskfile[ide->selected_drive].assume_lba48 = (flags&IDELIB_TASKFILE_LBA48)?1:0;
-
- /* and read back the upper 3 bits for the current mode, to detect LBA48 commands.
- * NTS: Unfortunately some implementations, even though you wrote 0x4x, will return 0xEx regardless,
- * so it's not really that easy. In that case, the only way to know is if the flags are set
- * in the taskfile indicating that an LBA48 command was issued. the program using this function
- * will presumably let us know if it is by sending:
- * flags = IDELIB_TASKFILE_LBA48 | IDELIB_TASKFILE_LBA48_UPDATE */
- if (ide->taskfile[ide->selected_drive].assume_lba48/*we KNOW we issued an LBA48 command*/ ||
- (ide->head_select&0xE0) == 0x40/*LBA48 command was issued*/) {
- /* read back 16 bits from 0x1F2-0x1F5 */
- if (portmask & 0x04) {
- ide->taskfile[ide->selected_drive].sector_count = (uint16_t)inp(ide->base_io+2) << 8;
- ide->taskfile[ide->selected_drive].sector_count |= (uint16_t)inp(ide->base_io+2);
- }
- if (portmask & 0x08) {
- ide->taskfile[ide->selected_drive].lba0_3 = (uint16_t)inp(ide->base_io+3) << 8;
- ide->taskfile[ide->selected_drive].lba0_3 |= (uint16_t)inp(ide->base_io+3);
- }
- if (portmask & 0x10) {
- ide->taskfile[ide->selected_drive].lba1_4 = (uint16_t)inp(ide->base_io+4) << 8;
- ide->taskfile[ide->selected_drive].lba1_4 |= (uint16_t)inp(ide->base_io+4);
- }
- if (portmask & 0x20) {
- ide->taskfile[ide->selected_drive].lba2_5 = (uint16_t)inp(ide->base_io+5) << 8;
- ide->taskfile[ide->selected_drive].lba2_5 |= (uint16_t)inp(ide->base_io+5);
- }
- }
- else {
- if (portmask & 0x04)
- ide->taskfile[ide->selected_drive].sector_count = (uint16_t)inp(ide->base_io+2);
- if (portmask & 0x08)
- ide->taskfile[ide->selected_drive].lba0_3 = (uint16_t)inp(ide->base_io+3);
- if (portmask & 0x10)
- ide->taskfile[ide->selected_drive].lba1_4 = (uint16_t)inp(ide->base_io+4);
- if (portmask & 0x20)
- ide->taskfile[ide->selected_drive].lba2_5 = (uint16_t)inp(ide->base_io+5);
- }
-
- if (portmask & 0x02)
- ide->taskfile[ide->selected_drive].error = (uint16_t)inp(ide->base_io+1);
-
- return 0;
-}
-
-struct ide_taskfile *idelib_controller_get_taskfile(struct ide_controller *ide,int which) {
- if (which < 0) which = ide->selected_drive;
- else if (which >= 2) return NULL;
- return &ide->taskfile[which];
-}
-
-void idelib_read_pio16(unsigned char *buf,unsigned int len,struct ide_controller *ide) {
- unsigned int lws = len >> 1;
-
- len &= 1;
- while (lws != 0) {
- *((uint16_t*)buf) = inpw(ide->base_io); /* from data port */
- buf += 2;
- lws--;
- }
- if (len != 0) *buf = inp(ide->base_io);
-}
-
-void idelib_write_pio16(unsigned char *buf,unsigned int len,struct ide_controller *ide) {
- unsigned int lws = len >> 1;
-
- len &= 1;
- while (lws != 0) {
- outpw(ide->base_io,*((uint16_t*)buf)); /* to data port */
- buf += 2;
- lws--;
- }
- if (len != 0) outp(ide->base_io,*buf);
-}
-
-void idelib_discard_pio16(unsigned int len,struct ide_controller *ide) {
- unsigned int lws = len >> 1;
-
- len &= 1;
- while (lws != 0) {
- inpw(ide->base_io); /* from data port */
- lws--;
- }
- if (len != 0) inp(ide->base_io);
-}
-
-void idelib_read_pio32(unsigned char *buf,unsigned int len,struct ide_controller *ide) {
- unsigned int lws = len >> 2;
-
- len &= 3;
- while (lws != 0) {
- *((uint32_t*)buf) = inpd(ide->base_io); /* from data port */
- buf += 4;
- lws--;
- }
- if (len & 2) {
- *((uint16_t*)buf) = inpw(ide->base_io);
- buf += 2;
- }
- if (len & 1) *buf = inp(ide->base_io);
-}
-
-void idelib_write_pio32(unsigned char *buf,unsigned int len,struct ide_controller *ide) {
- unsigned int lws = len >> 2;
-
- len &= 3;
- while (lws != 0) {
- outpd(ide->base_io,*((uint32_t*)buf)); /* to data port */
- buf += 4;
- lws--;
- }
- if (len & 2) {
- outpw(ide->base_io,*((uint16_t*)buf));
- buf += 2;
- }
- if (len & 1) outp(ide->base_io,*buf);
-}
-
-void idelib_discard_pio32(unsigned int len,struct ide_controller *ide) {
- unsigned int lws = len >> 2;
-
- len &= 3;
- while (lws != 0) {
- inpd(ide->base_io); /* from data port */
- lws--;
- }
- if (len & 2) inpw(ide->base_io);
- if (len & 1) inp(ide->base_io);
-}
-
-void idelib_discard_pio_general(unsigned int lw,struct ide_controller *ide,unsigned char pio_width) {
- if (pio_width == 0)
- pio_width = ide->pio_width;
-
- if (pio_width >= 32) {
- if (pio_width == 33) ide_vlb_sync32_pio(ide);
- idelib_discard_pio32(lw,ide);
- }
- else {
- idelib_discard_pio16(lw,ide);
- }
-}
-
-void idelib_read_pio_general(unsigned char *buf,unsigned int lw,struct ide_controller *ide,unsigned char pio_width) {
- if (pio_width == 0)
- pio_width = ide->pio_width;
-
- if (pio_width >= 32) {
- if (pio_width == 33) ide_vlb_sync32_pio(ide);
- idelib_read_pio32(buf,lw,ide);
- }
- else {
- idelib_read_pio16(buf,lw,ide);
- }
-}
-
-void idelib_write_pio_general(unsigned char *buf,unsigned int lw,struct ide_controller *ide,unsigned char pio_width) {
- if (pio_width == 0)
- pio_width = ide->pio_width;
-
- if (pio_width >= 32) {
- if (pio_width == 33) ide_vlb_sync32_pio(ide);
- idelib_write_pio32(buf,lw,ide);
- }
- else {
- idelib_write_pio16(buf,lw,ide);
- }
-}
-
-int idelib_controller_atapi_prepare_packet_command(struct ide_controller *ide,unsigned char features,unsigned int bytecount) {
- struct ide_taskfile *tsk;
-
- if (ide == NULL) return -1;
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- tsk->features = features; /* 0x1F1 */
- tsk->sector_count = 0; /* unused? */ /* 0x1F2 */
- tsk->lba0_3 = 0; /* unused */ /* 0x1F3 */
- tsk->lba1_4 = bytecount & 0xFF; /* 0x1F4 */
- tsk->lba2_5 = bytecount >> 8; /* 0x1F5 */
- tsk->command = 0xA0; /* ATAPI packet command */ /* 0x1F7 */
- return 0;
-}
-
-void idelib_controller_atapi_write_command(struct ide_controller *ide,unsigned char *buf,unsigned int len/*Only "12" is supported!*/) {
- unsigned int i;
-
- if (len > 12) len = 12; /* max 12 bytes (6 words) */
-
- if (ide->pio_width >= IDELIB_PIO_WIDTH_32 && ide->pio32_atapi_command) {
- if (ide->pio_width == IDELIB_PIO_WIDTH_32_VLB) ide_vlb_sync32_pio(ide);
-
- len = (len + 3) / 4; /* command bytes transmitted in DWORDs */
- for (i=0;i < 3 && i < len;i++) /* 3x4 = 12 */
- outpd(ide->base_io+0,((uint32_t*)buf)[i]);
- for (;i < 3;i++)
- outpd(ide->base_io+0,0/*pad*/);
- }
- else {
- len = (len + 1) / 2; /* command bytes transmitted in WORDs */
- for (i=0;i < 6 && i < len;i++) /* 6x2 = 12 */
- outpw(ide->base_io+0,((uint16_t*)buf)[i]);
- for (;i < 6;i++)
- outpw(ide->base_io+0,0/*pad*/);
- }
-}
-
-int idelib_controller_update_atapi_state(struct ide_controller *ide) {
- struct ide_taskfile *tsk;
-
- if (ide == NULL) return -1;
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- tsk->sector_count = inp(ide->base_io+2);
- return 0;
-}
-
-int idelib_controller_read_atapi_state(struct ide_controller *ide) {
- struct ide_taskfile *tsk;
-
- if (ide == NULL) return -1;
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- return (tsk->sector_count&3);
-}
-
-int idelib_controller_update_atapi_drq(struct ide_controller *ide) {
- return idelib_controller_update_taskfile(ide,0x30/*base_io+4-5*/,0);
-}
-
-unsigned int idelib_controller_read_atapi_drq(struct ide_controller *ide) {
- struct ide_taskfile *tsk;
-
- if (ide == NULL) return 0;
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- return ((tsk->lba1_4&0xFF) + ((tsk->lba2_5&0xFF) << 8));
-}
-
+++ /dev/null
-
-#ifndef __DOSLIB_HW_IDE_IDELIB_H
-#define __DOSLIB_HW_IDE_IDELIB_H
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#define MAX_IDE_CONTROLLER 16
-
-struct ide_controller_flags {
- uint8_t io_irq_enable:1; /* if set, disk I/O should use IRQ to signal completion */
- uint8_t _reserved_:1;
-};
-
-struct ide_taskfile {
- union { /* 0x1F1. error/feature */
- uint8_t error;
- uint8_t features;
- };
- uint16_t sector_count; /* 0x1F2. double wide for LBA48 */
- union {
- uint16_t lba0_3; /* 0x1F3. if LBA48, contains [15:8 = byte 3] and [7:0 = byte 0] of LBA,
- or contains only byte 0 of LBA, or sector number of CHS */
- uint16_t chs_sector;
- };
- union {
- uint16_t lba1_4; /* 0x1F4. if LBA48, contains [15:8 = byte 4] and [7:0 = byte 1] of LBA,
- or contains only byte 1 of LBA, or [7:0] of cylinder in CHS */
- uint16_t chs_cylinder_low;
- };
- union {
- uint16_t lba2_5; /* 0x1F5. if LBA48, contains [15:8 = byte 5] and [7:0 = byte 2] of LBA,
- or contains only byte 2 of LBA, or [15:8] of cylinder in CHS */
- uint16_t chs_cylinder_high;
- };
- uint8_t head_select; /* 0x1F6. mode [bits 7:5] select [bit 4] head [bits 3:0] */
- uint8_t command; /* 0x1F7. command(W) and status(R) */
- uint8_t status; /* also port 0x3F6 status */
- uint8_t assume_lba48:1; /* assume LBA48 response (i.e. 0x1F2-0x1F5 are 16-bit wide) */
- uint8_t _reserved_:7;
-};
-
-struct ide_controller {
- uint16_t base_io; /* 0x1F0, 0x170, etc */
- uint16_t alt_io; /* 0x3F6, 0x3F7, etc */
- volatile uint16_t irq_fired; /* IRQ counter */
- int8_t irq;
- struct ide_controller_flags flags;
- struct ide_taskfile taskfile[2]; /* one per drive */
- uint8_t head_select;
- uint8_t device_control; /* 0x3F6. control bits last written */
- uint8_t drive_address; /* 0x3F7. drive select and head */
- uint8_t last_status;
- uint8_t pio_width; /* PIO width (16=16-bit 32=32-bit 33=32-bit VLB key) */
- uint8_t selected_drive:1; /* which drive is selected */
- uint8_t pio32_atapi_command:1; /* if set, allow 32-bit PIO when sending ATAPI command */
- uint8_t _reserved_:6;
-};
-
-enum {
- IDELIB_PIO_WIDTH_DEFAULT=0,
- IDELIB_PIO_WIDTH_16=16,
- IDELIB_PIO_WIDTH_32=32,
- IDELIB_PIO_WIDTH_32_VLB=33
-};
-
-extern const struct ide_controller ide_isa_standard[2];
-extern struct ide_controller ide_controller[MAX_IDE_CONTROLLER];
-extern int8_t idelib_init;
-
-void idelib_controller_update_status(struct ide_controller *ide);
-const struct ide_controller *idelib_get_standard_isa_port(int i);
-
-int idelib_controller_is_busy(struct ide_controller *ide);
-int idelib_controller_is_error(struct ide_controller *ide);
-int idelib_controller_is_drq_ready(struct ide_controller *ide);
-int idelib_controller_is_drive_ready(struct ide_controller *ide);
-
-enum {
- IDELIB_DRIVE_SELECT_MASTER=0,
- IDELIB_DRIVE_SELECT_SLAVE=1
-};
-
-enum {
- IDELIB_DRIVE_SELECT_MODE_LBA48=0x02, /* LBA48 (2 << 5) = 0x40 */
- IDELIB_DRIVE_SELECT_MODE_CHS=0x05, /* LBA (5 << 5) = 0xA0 */
- IDELIB_DRIVE_SELECT_MODE_LBA=0x07 /* CHS (7 << 5) = 0xE0 */
-};
-
-enum {
- IDELIB_TASKFILE_LBA48=0x01,
- IDELIB_TASKFILE_LBA48_UPDATE=0x02,
- IDELIB_TASKFILE_SELECTED_UPDATE=0x04 /* allow update function to change "selected drive" pointer */
-};
-
-void idelib_controller_drive_select(struct ide_controller *ide,unsigned char which/*1=slave 0=master*/,unsigned char head/*CHS mode head value*/,unsigned char mode/*upper 3 bits*/);
-int idelib_controller_apply_taskfile(struct ide_controller *ide,unsigned char portmask,unsigned char flags);
-int idelib_controller_update_taskfile(struct ide_controller *ide,unsigned char portmask,unsigned char flags);
-struct ide_taskfile *idelib_controller_get_taskfile(struct ide_controller *ide,int which);
-void idelib_read_pio16(unsigned char *buf,unsigned int len,struct ide_controller *ide);
-void idelib_read_pio32(unsigned char *buf,unsigned int len,struct ide_controller *ide);
-void idelib_read_pio_general(unsigned char *buf,unsigned int lw,struct ide_controller *ide,unsigned char pio_width);
-void idelib_write_pio16(unsigned char *buf,unsigned int len,struct ide_controller *ide);
-void idelib_write_pio32(unsigned char *buf,unsigned int len,struct ide_controller *ide);
-void idelib_write_pio_general(unsigned char *buf,unsigned int lw,struct ide_controller *ide,unsigned char pio_width);
-void idelib_discard_pio16(unsigned int len,struct ide_controller *ide);
-void idelib_discard_pio32(unsigned int len,struct ide_controller *ide);
-void idelib_discard_pio_general(unsigned int lw,struct ide_controller *ide,unsigned char pio_width);
-
-void idelib_otr_enable_interrupt(struct ide_controller *ide,unsigned char en);
-void idelib_enable_interrupt(struct ide_controller *ide,unsigned char en);
-int idelib_controller_allocated(struct ide_controller *ide);
-struct ide_controller *idelib_probe(struct ide_controller *ide);
-struct ide_controller *idelib_get_controller(int i);
-struct ide_controller *idelib_new_controller();
-struct ide_controller *idelib_by_base_io(uint16_t io);
-struct ide_controller *idelib_by_alt_io(uint16_t io);
-struct ide_controller *idelib_by_irq(int8_t irq);
-void ide_vlb_sync32_pio(struct ide_controller *ide);
-int idelib_controller_atapi_prepare_packet_command(struct ide_controller *ide,unsigned char features,unsigned int bytecount);
-void idelib_controller_atapi_write_command(struct ide_controller *ide,unsigned char *buf,unsigned int len/*Only "12" is supported!*/);
-int idelib_controller_update_atapi_state(struct ide_controller *ide);
-int idelib_controller_read_atapi_state(struct ide_controller *ide);
-int idelib_controller_update_atapi_drq(struct ide_controller *ide);
-unsigned int idelib_controller_read_atapi_drq(struct ide_controller *ide);
-
-static inline void idelib_controller_ack_irq(struct ide_controller *ide) {
- /* reading port 0x3F6 (normal method of status update) does not clear IRQ.
- * reading port 0x1F7 reads status AND clears IRQ */
- ide->last_status = inp(ide->base_io+7);
- if (!(ide->last_status&0x80)) ide->taskfile[ide->selected_drive].status = ide->last_status;
-}
-
-static inline void idelib_controller_write_command(struct ide_controller *ide,unsigned char cmd) { /* WARNING: does not check controller or drive readiness */
- outp(ide->base_io+7,cmd);
-}
-
-static inline void idelib_controller_reset_irq_counter(struct ide_controller *ide) {
- ide->irq_fired = 0;
-}
-
-static inline unsigned char idelib_read_device_control(struct ide_controller *ide) {
- return ide->device_control;
-}
-
-static inline void idelib_write_device_control(struct ide_controller *ide,unsigned char byte) {
- ide->device_control = byte;
- outp(ide->alt_io,byte);
-}
-
-static inline void idelib_device_control_set_reset(struct ide_controller *ide,unsigned char reset) {
- idelib_write_device_control(ide,(ide->device_control & (~0x06)) | (reset ? 0x04/*SRST*/ : (ide->flags.io_irq_enable?0x00:0x02/*nIEN*/)));
-}
-
-static inline int idelib_controller_atapi_data_input_state(struct ide_controller *ide) {
- return (idelib_controller_read_atapi_state(ide) == 2); /* [bit 1] input/output == 1 [bit 0] command/data == 0 */
-}
-
-static inline int idelib_controller_atapi_command_state(struct ide_controller *ide) {
- return (idelib_controller_read_atapi_state(ide) == 1); /* [bit 1] input/output == 0 [bit 0] command/data == 1 */
-}
-
-static inline int idelib_controller_atapi_complete_state(struct ide_controller *ide) {
- return (idelib_controller_read_atapi_state(ide) == 3); /* [bit 1] input/output == 1 [bit 0] command/data == 1 */
-}
-
-void free_idelib();
-int init_idelib();
-
-#endif /* __DOSLIB_HW_IDE_IDELIB_H */
-
+++ /dev/null
-IDE/ATA and IDE/ATAPI test program.
-
-This demonstrates how to talk directly to the IDE controller
-on most PCs that is connected to a hard drive and (in some cases)
-a CD-ROM drive as well.
-
+++ /dev/null
-/* THINGS TO DO:
- *
- * - Modularize copy-pasta'd code such as:
- * * The "if you value your data" warning
- * * ATAPI packet commands
- * * EVERYTHING---This code basically works on test hardware, now it's time to clean it up
- * modularize and refactor.
- * - Add menu item where the user can ask this code to test whether or not the IDE controller
- * supports 32-bit PIO properly.
- * - Start using this code for reference and implementation of IDE emulation within DOSBox-X
- * - Add menu items to allow the user to play with SET FEATURES command
- * - Add submenu where the user can play with the S.M.A.R.T. ATA commands
- * - **TEST THIS CODE ON AS MANY MACHINES AS POSSIBLE** The IDE interface is one of those
- * hardware standards that is conceptually simple yet so manu manufacturers managed to fuck
- * up their implementation in some way or another.
- * - Cleanup this code, move library into idelib.c+idelib.h
- * - Fix corner cases where we're IDE busy waiting and user commands to break free (ESC or spacebar
- * do not break out of read/write loop, forcing the user to CTRL+ALT+DEL or press reset.
- *
- * Also don't forget:
- * - Test programs for specific IDE chipsets (like Intel PIIX3) to demonstrate IDE DMA READ/WRITE commands
- *
- * Interesting notes:
- * - Toshiba Satellite Pro 465CDX/2.1
- * - Putting the hard drive to sleep seems to put the IDE controller to sleep too. IDE controller
- * "busy" bit is stuck on when hard drive asleep. Only way out seems to be doing a "host reset"
- * on that IDE controller. Note that NORMAL behavior is that the IDE controller remains not-busy
- * but the device is not ready.
- *
- * - The CD-ROM drive (or secondary IDE?) appears to ignore 32-bit I/O to port 0x170 (base_io+0).
- * If you attempt to read a sector or identify command results using 32-bit PIO, you get only
- * 0xFFFFFFFF. Reading data only works when PIO is done as 16-bit. NORMAL behavior suggests
- * either 32-bit PIO gets 32 bits at a time (PCI based IDE) or 32-bit PIO gets 16 bits of IDE
- * data and 16 bits of the adjacent 16-bit I/O register due to 386/486-era ISA subdivision of
- * 32-bit I/O into two 16-bit I/O reads. Supposedly, on pre-PCI controllers, 32-bit PIO could
- * be made to work if you tell the card in advance using the "VLB keying sequence", but I have
- * yet to find such a card.
- *
- * Known hardware this code has trouble with (so far):
- *
- * - Ancient (1999-2002-ish) DVD-ROM drives. They generally work with this code but there seem to be a lot
- * of edge cases. One DVD-ROM drive I own will not raise "drive ready" after receipt of a command it doesn't
- * recognize. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "testmumo.h"
-#include "testmisc.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef ISAPNP
-#include <hw/isapnp/isapnp.h>
-#include <hw/sndsb/sndsbpnp.h>
-#endif
-
-unsigned char opt_ignore_smartdrv = 0;
-unsigned char opt_no_irq = 0;
-unsigned char opt_no_pci = 0;
-unsigned char opt_no_isapnp = 0;
-unsigned char opt_no_isa_probe = 0;
-unsigned char opt_irq_chain = 1;
-
-unsigned char cdrom_read_mode = 12;
-unsigned char pio_width_warning = 1;
-unsigned char big_scary_write_test_warning = 1;
-
-char tmp[1024];
-uint16_t ide_info[256];
-#ifdef ISAPNP
-static unsigned char far devnode_raw[4096];
-#endif
-
-#if TARGET_MSDOS == 32
-unsigned char cdrom_sector[512U*256U];/* ~128KB, enough for 64 CD-ROM sector or 256 512-byte sectors */
-#else
-# if defined(__LARGE__) || defined(__COMPACT__)
-unsigned char cdrom_sector[512U*16U]; /* ~8KB, enough for 4 CD-ROM sector or 16 512-byte sectors */
-# else
-unsigned char cdrom_sector[512U*8U]; /* ~4KB, enough for 2 CD-ROM sector or 8 512-byte sectors */
-# endif
-#endif
-
-/*-----------------------------------------------------------------*/
-
-static const char *drive_main_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "Identify (ATA)",
- "Identify packet (ATAPI)",
- "Power states >>",
- "PIO mode >>", /* 4 */ /* rewritten */
- "No-op", /* 5 */
- "Tweaks and adjustments >>",
- "CD-ROM eject/load >>",
- "CD-ROM reading >>",
- "Multiple mode >>",
- "Read/Write tests >>", /* 10 */
- "Miscellaneous >>"
-};
-
-void do_ide_controller_drive(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_main_menustrings);
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* select the drive we want */
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
-
- /* in case the IDE controller is busy for that time */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
-
- /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
- do_ide_controller_atapi_device_check_post_host_reset(ide);
-
- /* wait for the drive to indicate readiness */
- /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
- * possibility that the device doesn't exist. This can happen for example if there
- * is a master attached but no slave. */
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
-
- /* for completeness, clear pending IRQ */
- idelib_controller_ack_irq(ide);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- /* update a string or two: PIO mode */
- if (ide->pio_width == 33)
- drive_main_menustrings[4] = "PIO mode (currently: 32-bit VLB) >>";
- else if (ide->pio_width == 32)
- drive_main_menustrings[4] = "PIO mode (currently: 32-bit) >>";
- else
- drive_main_menustrings[4] = "PIO mode (currently: 16-bit) >>";
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE controller main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /*Identify*/
- case 2: /*Identify packet*/
- do_drive_identify_device_test(ide,which,select == 2 ? 0xA1/*Identify packet*/ : 0xEC/*Identify*/);
- redraw = backredraw = 1;
- break;
- case 3: /* power states */
-#ifdef POWER_MENU
- do_drive_power_states_test(ide,which);
- redraw = backredraw = 1;
-#endif
- break;
- case 4: /* PIO mode */
-#ifdef PIO_MODE_MENU
- do_drive_pio_mode(ide,which);
- redraw = backredraw = 1;
-#endif
- break;
- case 5: /* NOP */
-#ifdef NOP_TEST
- do_ide_controller_drive_nop_test(ide,which);
-#endif
- break;
- case 6: /* Tweaks and adjustments */
-#ifdef TWEAK_MENU
- do_drive_tweaks_and_adjustments(ide,which);
- redraw = backredraw = 1;
-#endif
- break;
- case 7: /* CD-ROM start/stop/eject/load */
- do_drive_cdrom_startstop_test(ide,which);
- redraw = backredraw = 1;
- break;
- case 8: /* CD-ROM reading */
- do_drive_cdrom_reading(ide,which);
- redraw = backredraw = 1;
- break;
- case 9: /* multiple mode */
-#ifdef MULTIPLE_MODE_MENU
- do_drive_multiple_mode(ide,which);
- redraw = backredraw = 1;
-#endif
- break;
- case 10: /* read/write tests */
- do_drive_readwrite_tests(ide,which);
- redraw = backredraw = 1;
- break;
- case 11: /* misc */
-#ifdef MISC_TEST
- do_drive_misc_tests(ide,which);
- redraw = backredraw = 1;
-#endif
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-static void (interrupt *my_ide_old_irq)() = NULL;
-static struct ide_controller *my_ide_irq_ide = NULL;
-static unsigned long ide_irq_counter = 0;
-static int my_ide_irq_number = -1;
-
-static void interrupt my_ide_irq() {
- int i;
-
- _cli();
-
- /* we CANNOT use sprintf() here. sprintf() doesn't work to well from within an interrupt handler,
- * and can cause crashes in 16-bit realmode builds. */
- i = vga_width*(vga_height-1);
- vga_alpha_ram[i++] = 0x1F00 | 'I';
- vga_alpha_ram[i++] = 0x1F00 | 'R';
- vga_alpha_ram[i++] = 0x1F00 | 'Q';
- vga_alpha_ram[i++] = 0x1F00 | ':';
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 100000UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 10000UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 1000UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 100UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 10UL) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 1L) % 10UL));
- vga_alpha_ram[i++] = 0x1F00 | ' ';
- ide_irq_counter++;
-
- if (my_ide_irq_ide != NULL) {
- my_ide_irq_ide->irq_fired++;
-
- /* NTS: This code requires some explanation: On an Intel Core i3 mini-itx motherboard I recently
- * bought, the SATA controller (in IDE mode) has a problem with IDE interrupts where for reasons
- * beyond my understanding, once the IRQ fires, the IRQ continues to fire and will not stop no
- * matter what registers we read or ports we poke. It fires rapidly enough that our busy wait
- * code cannot proceed and the program "hangs" while the IRQ counter on the screen counts upward
- * very fast. It is only when exiting back to DOS that the BIOS somehow makes it stop.
- *
- * That motherboard is the reason this code was implemented. should any other SATA/IDE controller
- * have this problem, this code will eventually stop the IRQ flood by masking off the IRQ and
- * switching the IDE controller struct into polling mode so that the user can continue to use
- * this program without having to hit the reset button!
- *
- * Another Intel Core i3 system (2010) has the same problem, with SATA ports and one IDE port.
- * This happens even when talking to the IDE port and not the SATA-IDE emulation.
- *
- * It seems to be a problem with Intel-based motherboards, 2010 or later.
- *
- * Apparently the fix is to chain to the BIOS IRQ handler, which knows how to cleanup the IRQ signal. */
-
- /* ack IRQ on IDE controller */
- idelib_controller_ack_irq(my_ide_irq_ide);
- }
-
- if (!opt_irq_chain || my_ide_old_irq == NULL) {
- /* ack PIC */
- if (my_ide_irq_ide->irq >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
- }
- else {
- /* chain to previous */
- my_ide_old_irq();
- }
-
- /* If too many IRQs fired, then stop the IRQ and use polling from now on. */
- if (my_ide_irq_ide != NULL) {
- if (my_ide_irq_ide->irq_fired >= 0xFFFEU) {
- do_ide_controller_emergency_halt_irq(my_ide_irq_ide);
- vga_alpha_ram[i+12] = 0x1C00 | '!';
- my_ide_irq_ide->irq_fired = ~0; /* make sure the IRQ counter is as large as possible */
- }
- }
-}
-
-void do_ide_controller_hook_irq(struct ide_controller *ide) {
- if (my_ide_irq_number >= 0 || ide->irq < 0)
- return;
-
- /* let the IRQ know what IDE controller */
- my_ide_irq_ide = ide;
-
- /* enable on IDE controller */
- p8259_mask(ide->irq);
- idelib_otr_enable_interrupt(ide,1);
- idelib_controller_ack_irq(ide);
-
- /* hook IRQ */
- my_ide_old_irq = _dos_getvect(irq2int(ide->irq));
- _dos_setvect(irq2int(ide->irq),my_ide_irq);
- my_ide_irq_number = ide->irq;
-
- /* enable at PIC */
- p8259_unmask(ide->irq);
-}
-
-void do_ide_controller_unhook_irq(struct ide_controller *ide) {
- if (my_ide_irq_number < 0 || ide->irq < 0)
- return;
-
- /* disable on IDE controller, then mask at PIC */
- p8259_mask(ide->irq);
- idelib_controller_ack_irq(ide);
- idelib_otr_enable_interrupt(ide,0);
-
- /* restore the original vector */
- _dos_setvect(irq2int(ide->irq),my_ide_old_irq);
- my_ide_irq_number = -1;
- my_ide_old_irq = NULL;
-}
-
-void do_ide_controller_emergency_halt_irq(struct ide_controller *ide) {
- /* disable on IDE controller, then mask at PIC */
- if (ide->irq >= 0) p8259_mask(ide->irq);
- idelib_controller_ack_irq(ide);
- idelib_otr_enable_interrupt(ide,0);
-}
-
-void do_ide_controller_enable_irq(struct ide_controller *ide,unsigned char en) {
- if (!en || ide->irq < 0 || ide->irq != my_ide_irq_number)
- do_ide_controller_unhook_irq(ide);
- if (en && ide->irq >= 0)
- do_ide_controller_hook_irq(ide);
-}
-
-void do_ide_controller(struct ide_controller *ide) {
- struct vga_msg_box vgabox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- char redraw=1;
- int select=-1;
- int c;
-
- /* we're taking a drive, possibly out from MS-DOS.
- * make sure SMARTDRV flushes the cache so that it does not attempt to
- * write to the disk while we're controlling the IDE controller */
- if (smartdrv_version != 0) {
- for (c=0;c < 4;c++) smartdrv_flush();
- }
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c < 0) return;
-
- /* if the IDE struct says to use interrupts, then do it */
- do_ide_controller_enable_irq(ide,ide->flags.io_irq_enable);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- y = 5;
- vga_moveto(8,y++);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Main menu");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- y++;
-
- vga_moveto(8,y++);
- vga_write_color((select == 0) ? 0x70 : 0x0F);
- vga_write("Host Reset");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 1) ? 0x70 : 0x0F);
- vga_write("Tinker with Master device");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 2) ? 0x70 : 0x0F);
- vga_write("Tinker with Slave device");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
-
- vga_moveto(8,y++);
- vga_write_color((select == 3) ? 0x70 : 0x0F);
- vga_write("Currently using ");
- vga_write(ide->flags.io_irq_enable ? "IRQ" : "polling");
- vga_write(", switch to ");
- vga_write((!ide->flags.io_irq_enable) ? "IRQ" : "polling");
- while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1) {
- break;
- }
- else if (select == 0) { /* host reset */
- if (ide->alt_io != 0) {
- vga_msg_box_create(&vgabox,"Host reset in progress",0,0);
-
- idelib_device_control_set_reset(ide,1);
- t8254_wait(t8254_us2ticks(1000000));
- idelib_device_control_set_reset(ide,0);
-
- vga_msg_box_destroy(&vgabox);
-
- /* now wait for not busy */
- do_ide_controller_user_wait_busy_controller(ide);
- }
- }
- else if (select == 1) {
- do_ide_controller_drive(ide,0/*master*/);
- redraw = backredraw = 1;
- }
- else if (select == 2) {
- do_ide_controller_drive(ide,1/*slave*/);
- redraw = backredraw = 1;
- }
- else if (select == 3) {
- if (ide->irq >= 0)
- ide->flags.io_irq_enable = !ide->flags.io_irq_enable;
- else
- ide->flags.io_irq_enable = 0;
-
- do_ide_controller_enable_irq(ide,ide->flags.io_irq_enable);
- redraw = backredraw = 1;
- }
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = 3;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > 3)
- select = -1;
-
- redraw = 1;
- }
- }
-
- do_ide_controller_enable_irq(ide,0);
- idelib_otr_enable_interrupt(ide,1); /* NTS: Most BIOSes know to unmask the IRQ at the PIC, but there might be some
- idiot BIOSes who don't clear the nIEN bit in the device control when
- executing INT 13h, so it's probably best to do it for them. */
-}
-
-void do_main_menu() {
- char redraw=1;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- struct ide_controller *ide;
- unsigned int x,y,i;
- int select=-1;
- int c;
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller test program");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- y = 5;
- vga_moveto(8,y++);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Exit program");
- y++;
-
- for (i=0;i < MAX_IDE_CONTROLLER;i++) {
- ide = idelib_get_controller(i);
- if (ide != NULL) {
- vga_moveto(8,y++);
- vga_write_color((select == (int)i) ? 0x70 : 0x0F);
-
- sprintf(tmp,"Controller @ %04X",ide->base_io);
- vga_write(tmp);
-
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %04X",ide->alt_io);
- vga_write(tmp);
- }
-
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %2d",ide->irq);
- vga_write(tmp);
- }
- }
- }
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1) {
- break;
- }
- else if (select >= 0 && select < MAX_IDE_CONTROLLER) {
- ide = idelib_get_controller(select);
- if (ide != NULL) do_ide_controller(ide);
- backredraw = redraw = 1;
- }
- }
- else if (c == 0x4800) {
- if (select <= -1)
- select = MAX_IDE_CONTROLLER - 1;
- else
- select--;
-
- while (select >= 0 && idelib_get_controller(select) == NULL)
- select--;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- select++;
- while (select >= 0 && select < MAX_IDE_CONTROLLER && idelib_get_controller(select) == NULL)
- select++;
- if (select >= MAX_IDE_CONTROLLER)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-static void help() {
- printf("test [options]\n");
- printf("\n");
- printf("IDE ATA/ATAPI test program\n");
- printf("(C) 2012-2015 Jonathan Campbell, Hackipedia.org\n");
- printf("\n");
- printf(" /NS Don't check if SMARTDRV is resident\n");
- printf(" /NOIRQ Don't use IRQ by default\n");
-#ifdef PCI_SCAN
- printf(" /NOPCI Don't scan PCI bus\n");
-#endif
-#ifdef ISAPNP
- printf(" /NOISAPNP Don't scan ISA Plug & Play BIOS\n");
-#endif
- printf(" /NOPROBE Don't probe ISA legacy ports\n");
- printf(" /IRQCHAIN IRQ should chain to previous handler (default)\n");
- printf(" /IRQNOCHAIN IRQ should NOT chain to previous handler\n");
-}
-
-int parse_argv(int argc,char **argv) {
- char *a;
- int i;
-
- for (i=1;i < argc;) {
- a = argv[i++];
-
- if (*a == '/') {
- do { a++; } while (*a == '/');
-
- if (!strcasecmp(a,"?") || !strcasecmp(a,"h") || !strcasecmp(a,"help")) {
- help();
- return 1;
- }
- else if (!strcasecmp(a,"ns")) {
- opt_ignore_smartdrv = 1;
- }
- else if (!strcasecmp(a,"irqnochain")) {
- opt_irq_chain = 0;
- }
- else if (!strcasecmp(a,"irqchain")) {
- opt_irq_chain = 1;
- }
- else if (!strcasecmp(a,"noirq")) {
- opt_no_irq = 1;
- }
- else if (!strcasecmp(a,"nopci")) {
- opt_no_pci = 1;
- }
- else if (!strcasecmp(a,"noisapnp")) {
- opt_no_isapnp = 1;
- }
- else if (!strcasecmp(a,"noprobe")) {
- opt_no_isa_probe = 1;
- }
- else {
- printf("Unknown switch %s\n",a);
- return 1;
- }
- }
- else {
- help();
- return 1;
- }
- }
-
- return 0;
-}
-
-int main(int argc,char **argv) {
- struct ide_controller *idectrl;
- struct ide_controller *newide;
- int i;
-
- if (parse_argv(argc,argv))
- return 1;
-
- if (!opt_ignore_smartdrv) {
- if (smartdrv_detect()) {
- printf("WARNING: SMARTDRV %u.%02u or equivalent disk cache detected!\n",smartdrv_version>>8,smartdrv_version&0xFF);
-#ifdef MORE_TEXT
- printf(" Running this program with SMARTDRV enabled is NOT RECOMMENDED,\n");
- printf(" especially when using the snapshot functions!\n");
- printf(" If you choose to test anyway, this program will attempt to flush\n");
- printf(" the disk cache as much as possible to avoid conflict.\n");
-#endif
- }
- }
-
- /* we take a GUI-based approach (kind of) */
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
- /* the IDE code has some timing requirements and we'll use the 8254 to do it */
- /* I bet that by the time motherboard manufacturers stop implementing the 8254 the legacy DOS support this
- * program requires to run will be long gone too. */
- if (!probe_8254()) {
- printf("8254 chip not detected\n");
- return 1;
- }
- /* interrupt controller */
- if (!probe_8259()) {
- printf("8259 chip not detected\n");
- return 1;
- }
- if (!init_idelib()) {
- printf("Cannot init IDE lib\n");
- return 1;
- }
-#ifdef PCI_SCAN
- if (!opt_no_pci) {
- if (pci_probe(-1/*default preference*/) != PCI_CFG_NONE) {
- uint8_t bus,dev,func,iport;
-
- printf("PCI bus detected.\n");
- if (pci_bios_last_bus == -1) {
- printf(" Autodetecting PCI bus count...\n");
- pci_probe_for_last_bus();
- }
- printf(" Last bus: %d\n",pci_bios_last_bus);
- printf(" Bus decode bits: %d\n",pci_bus_decode_bits);
- for (bus=0;bus <= pci_bios_last_bus;bus++) {
- for (dev=0;dev < 32;dev++) {
- uint8_t functions = pci_probe_device_functions(bus,dev);
- for (func=0;func < functions;func++) {
- /* make sure something is there before announcing it */
- uint16_t vendor,device,subsystem,subvendor_id;
- struct ide_controller ide={0};
- uint32_t class_code;
- uint8_t revision_id;
- int IRQ_pin,IRQ_n;
- uint32_t reg;
-
- vendor = pci_read_cfgw(bus,dev,func,0x00); if (vendor == 0xFFFF) continue;
- device = pci_read_cfgw(bus,dev,func,0x02); if (device == 0xFFFF) continue;
- subvendor_id = pci_read_cfgw(bus,dev,func,0x2C);
- subsystem = pci_read_cfgw(bus,dev,func,0x2E);
- class_code = pci_read_cfgl(bus,dev,func,0x08);
- revision_id = class_code & 0xFF;
- class_code >>= 8UL;
-
- /* must be: class 0x01 (mass storage) 0x01 (IDE controller) */
- if ((class_code&0xFFFF00UL) != 0x010100UL)
- continue;
-
- /* read the command register. is the device enabled? */
- reg = pci_read_cfgw(bus,dev,func,0x04); /* read Command register */
- if (!(reg&1)) continue; /* if the I/O space bit is cleared, then no */
-
- /* tell the user! */
- printf(" Found PCI IDE controller %02x:%02x:%02x class=0x%06x\n",bus,dev,func,class_code&0xFFFFFFUL);
-
- /* enumerate from THAT the primary and secondary IDE */
- for (iport=0;iport < 2;iport++) {
- if (class_code&(0x01 << (iport*2))) { /* bit 0 is set if primary in native, bit 2 if secondary in native */
- /* "native mode" */
-
- /* read it from the BARs */
- reg = pci_read_cfgl(bus,dev,func,0x10+(iport*8)); /* command block */
- if ((reg&1) && (reg&0xFFFF0000UL) == 0UL) /* copy down IF an I/O resource */
- ide.base_io = reg & 0xFFFC;
-
- reg = pci_read_cfgl(bus,dev,func,0x14+(iport*8)); /* control block */
- if ((reg&1) && (reg&0xFFFF0000UL) == 0UL) { /* copy down IF an I/O resource */
- /* NTS: This requires some explanation: The PCI I/O resource encoding cannot
- * represent I/O port ranges smaller than 4 ports, nor can it represent
- * a 4-port resource unless the base port is a multiple of the I/O port
- * range length.
- *
- * The alt I/O port on legacy systems is 0x3F6/0x376. For a PCI device to
- * declare the same range, it must effectively declare 0x3F4/0x374 to
- * 0x3F7/377 and then map the legacy ports from 2 ports in from the base.
- *
- * When a newer chipset uses a different base port, the same rule applies:
- * the I/O resource is 4 ports large, and the last 2 ports (base+2) are
- * the legacy IDE I/O ports that would be 0x3F6/0x376. */
- ide.alt_io = (reg & 0xFFFC) + 2;
- }
-
- /* get IRQ number and PCI interrupt (A-D) */
- IRQ_n = pci_read_cfgb(bus,dev,func,0x3C);
- IRQ_pin = pci_read_cfgb(bus,dev,func,0x3D);
- if (IRQ_n != 0 && IRQ_n < 16 && IRQ_pin != 0 && IRQ_pin <= 4)
- ide.irq = IRQ_n;
- else
- ide.irq = -1;
-
- if (ide.base_io != 0 && (ide.base_io&7) == 0) {
- printf(" PCI IDE%u in native mode, IRQ=%d base=0x%3x alt=0x%3x\n",
- iport,ide.irq,ide.base_io,ide.alt_io);
-
- if ((newide = idelib_probe(&ide)) == NULL)
- printf(" Warning: probe failed\n");
-
- /* HACK: An ASUS Intel Core i3 motherboard I own has a SATA controller
- * that has problems with IDE interrupts (when set to IDE mode).
- * Once an IDE interrupt fires there's no way to shut it off and
- * the controller crapfloods the PIC causing our program to "hang"
- * running through the IRQ handler. */
- if (vendor == 0x8086 && device == 0x8C80) { /* Intel Haswell-based motherboard (2014) */
- idelib_enable_interrupt(newide,0); /* don't bother with interrupts */
- }
- }
- }
- else {
- /* "compatability mode".
- * this is retarded, why didn't the PCI standards people just come out and
- * say: guys, if you're a PCI device then frickin' show up as a proper PCI
- * device and announce what resources you're using in the BARs and IRQ
- * registers so OSes are not required to guess like this! */
- ide.base_io = iport ? 0x170 : 0x1F0;
- ide.alt_io = iport ? 0x376 : 0x3F6;
- ide.irq = iport ? 15 : 14;
-
- printf(" PCI IDE%u in compat mode, IRQ=%d base=0x%3x alt=0x%3x\n",
- iport,ide.irq,ide.base_io,ide.alt_io);
-
- if ((newide = idelib_probe(&ide)) == NULL)
- printf(" Warning: probe failed\n");
- }
- }
- }
- }
- }
- }
- }
-#endif
-#ifdef ISAPNP
- if (!opt_no_isapnp) {
- if (!init_isa_pnp_bios()) {
- printf("Cannot init ISA PnP\n");
- }
- if (find_isa_pnp_bios()) {
- unsigned int nodesize=0;
- unsigned char node=0,numnodes=0xFF,data[192];
-
- memset(data,0,sizeof(data));
- printf("ISA PnP BIOS detected\n");
- if (isa_pnp_bios_get_pnp_isa_cfg(data) == 0) {
- struct isapnp_pnp_isa_cfg *nfo = (struct isapnp_pnp_isa_cfg*)data;
- isapnp_probe_next_csn = nfo->total_csn;
- isapnp_read_data = nfo->isa_pnp_port;
- }
- else {
- printf(" ISA PnP BIOS failed to return configuration info\n");
- }
-
- /* enumerate device nodes reported by the BIOS */
- if (isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize) == 0 && numnodes != 0xFF && nodesize <= sizeof(devnode_raw)) {
- printf("Scanning ISA PnP BIOS devices...\n");
- for (node=0;node != 0xFF;) {
- struct isa_pnp_device_node far *devn;
- unsigned char far *rsc, far *rf;
- unsigned char this_node;
- struct isapnp_tag tag;
- unsigned int ioport1=0;
- unsigned int ioport2=0;
- unsigned int i;
- int irq = -1;
-
- /* apparently, start with 0. call updates node to
- * next node number, or 0xFF to signify end */
- this_node = node;
- if (isa_pnp_bios_get_sysdev_node(&node,devnode_raw,ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW) != 0) break;
-
- devn = (struct isa_pnp_device_node far*)devnode_raw;
- if (devn->type_code[0] == 0x01/*system device, hard disk controller*/ &&
- devn->type_code[1] == 0x01/*Generic ESDI/IDE/ATA controller*/ &&
- devn->type_code[2] == 0x00/*Generic IDE*/) {
- rsc = (unsigned char far*)devn + sizeof(*devn);
- rf = (unsigned char far*)devn + sizeof(devnode_raw);
-
- do {
- if (!isapnp_read_tag(&rsc,rf,&tag))
- break;
- if (tag.tag == ISAPNP_TAG_END)
- break;
-
- /* NTS: A Toshiba Satellite 465CDX I own lists the primary IDE controller's alt port range (0x3F6)
- * as having length == 1 for some reason. Probably because of the floppy controller. */
-
- switch (tag.tag) {
- case ISAPNP_TAG_IO_PORT: {
- struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
- if (ioport1 == 0 && x->length == 8)
- ioport1 = x->min_range;
- else if (ioport2 == 0 && (x->length == 1 || x->length == 2 || x->length == 4))
- ioport2 = x->min_range;
- } break;
- case ISAPNP_TAG_FIXED_IO_PORT: {
- struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
- if (ioport1 == 0 && x->length == 8)
- ioport1 = x->base;
- else if (ioport2 == 0 && (x->length == 1 || x->length == 2 || x->length == 4))
- ioport2 = x->base;
- } break;
- case ISAPNP_TAG_IRQ_FORMAT: {
- struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
- for (i=0;i < 16;i++) {
- if (x->irq_mask & (1U << (unsigned int)i)) { /* NTS: PnP devices usually support odd IRQs like IRQ 9 */
- if (irq < 0) irq = i;
- }
- }
- } break;
- }
- } while (1);
-
- if (ioport1 != 0) {
- struct ide_controller n;
-
- printf(" Found PnP IDE controller: base=0x%03x alt=0x%03x IRQ=%d\n",
- ioport1,ioport2,irq);
-
- memset(&n,0,sizeof(n));
- n.base_io = ioport1;
- n.alt_io = ioport2;
- n.irq = (int8_t)irq; /* -1 is no IRQ */
- if ((newide = idelib_probe(&n)) == NULL) {
- printf(" Warning: probe failed\n");
- /* not filling it in leaves it open for allocation again */
- }
- }
- }
- }
- }
- }
- }
-#endif
-
- if (!opt_no_isa_probe) {
- printf("Probing standard IDE ports...\n");
- for (i=0;(idectrl = (struct ide_controller*)idelib_get_standard_isa_port(i)) != NULL;i++) {
- printf(" %3X/%3X IRQ %d: ",idectrl->base_io,idectrl->alt_io,idectrl->irq); fflush(stdout);
-
- if ((newide = idelib_probe(idectrl)) != NULL) {
- printf("FOUND: alt=%X irq=%d\n",newide->alt_io,newide->irq);
- }
- else {
- printf("\x0D \x0D"); fflush(stdout);
- }
- }
- }
-
- if (opt_no_irq) {
- unsigned int i;
-
- for (i=0;i < MAX_IDE_CONTROLLER;i++) {
- struct ide_controller *ide = &ide_controller[i];
- if (idelib_controller_allocated(ide)) idelib_enable_interrupt(ide,0); /* don't bother with interrupts */
- }
- }
-
- printf("Hit ENTER to continue, ESC to cancel\n");
- i = wait_for_enter_or_escape();
- if (i == 27) {
- smartdrv_close();
- free_idelib();
- return 0;
- }
-
- if (int10_getmode() != 3) {
- int10_setmode(3);
- update_state_from_vga();
- }
-
- do_main_menu();
- smartdrv_close();
- free_idelib();
- return 0;
-}
-
+++ /dev/null
-
-extern unsigned char cdrom_read_mode;
-extern unsigned char pio_width_warning;
-extern unsigned char big_scary_write_test_warning;
-extern unsigned char opt_ignore_smartdrv;
-extern unsigned char opt_no_irq;
-extern unsigned char opt_no_pci;
-extern unsigned char opt_no_isapnp;
-extern unsigned char opt_no_isa_probe;
-extern unsigned char opt_irq_mask;
-extern unsigned char opt_irq_chain;
-
-extern char tmp[1024];
-extern uint16_t ide_info[256];
-
-#if TARGET_MSDOS == 32
-extern unsigned char cdrom_sector[512U*256U];/* ~128KB, enough for 64 CD-ROM sector or 256 512-byte sectors */
-#else
-# if defined(__LARGE__) || defined(__COMPACT__)
-extern unsigned char cdrom_sector[512U*16U]; /* ~8KB, enough for 4 CD-ROM sector or 16 512-byte sectors */
-# else
-extern unsigned char cdrom_sector[512U*8U]; /* ~4KB, enough for 2 CD-ROM sector or 8 512-byte sectors */
-# endif
-#endif
-
-void do_ide_controller_hook_irq(struct ide_controller *ide);
-void do_ide_controller_unhook_irq(struct ide_controller *ide);
-void do_ide_controller_enable_irq(struct ide_controller *ide,unsigned char en);
-void do_ide_controller_emergency_halt_irq(struct ide_controller *ide);
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__) || defined(__MEDIUM__))
- /* chop features out of the Compact memory model build to ensure all code fits inside 64KB */
-#else
-# define ISAPNP
-#endif
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- /* chop features out of the Compact memory model build to ensure all code fits inside 64KB */
-#else
-# define PCI_SCAN
-# define MORE_TEXT
-# define ATAPI_ZIP
-# define NOP_TEST
-# define MISC_TEST
-# define MULTIPLE_MODE_MENU
-# define PIO_MODE_MENU
-# define POWER_MENU
-# define TWEAK_MENU
-# define PIO_AUTODETECT
-# define READ_VERIFY
-#endif
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "test.h"
-
-/* returns: -1 if user said to cancel
- * 0 if not busy
- * 1 if still busy, but user said to proceed */
-int do_ide_controller_user_wait_busy_timeout_controller(struct ide_controller *ide,unsigned int timeout) {
- int ret = 0;
-
- if (ide == NULL)
- return -1;
-
- /* use the alt status register if possible, else the base I/O.
- * the alt status register is said not to clear pending interrupts */
- idelib_controller_update_status(ide);
- if (idelib_controller_is_busy(ide)) {
- unsigned long show_countdown = (unsigned long)timeout * 10UL; /* ms -> 100us units */
-
- do {
- idelib_controller_update_status(ide);
- if (!idelib_controller_is_busy(ide)) break;
-
- /* if the drive&controller is busy then show the dialog and wait for non-busy
- * or until the user forces us to proceed */
- if (show_countdown > 0UL) {
- if (--show_countdown == 0UL) {
- ret = 1;
- break;
- }
- }
-
- t8254_wait(t8254_us2ticks(100)); /* wait 100us (0.0001 seconds) */
- } while (1);
- }
-
- return ret;
-}
-
-/* returns: -1 if user said to cancel
- * 0 if not busy
- * 1 if still busy, but user said to proceed */
-int do_ide_controller_user_wait_busy_controller(struct ide_controller *ide) {
- struct vga_msg_box vgabox;
- int ret = 0,c = 0;
-
- if (ide == NULL)
- return -1;
-
- /* use the alt status register if possible, else the base I/O.
- * the alt status register is said not to clear pending interrupts */
- idelib_controller_update_status(ide);
- if (idelib_controller_is_busy(ide)) {
- unsigned long show_countdown = 500000UL / 100UL; /* 0.5s / 100us units */
- /* if the drive&controller is busy then show the dialog and wait for non-busy
- * or until the user forces us to proceed */
-
- do {
- idelib_controller_update_status(ide);
- if (!idelib_controller_is_busy(ide)) break;
-
- /* if the drive&controller is busy then show the dialog and wait for non-busy
- * or until the user forces us to proceed */
- if (show_countdown > 0UL) {
- if (--show_countdown == 0UL)
- vga_msg_box_create(&vgabox,"IDE controller busy, waiting...\n\nHit ESC to cancel, spacebar to proceed anyway",0,0);
- }
-
- if (show_countdown == 0UL && kbhit()) { /* if keyboard input and we're showing prompt */
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- ret = -1;
- break;
- }
- else if (c == ' ') {
- ret = 1;
- break;
- }
- }
-
- t8254_wait(t8254_us2ticks(100)); /* wait 100us (0.0001 seconds) */
- } while (1);
-
- if (show_countdown == 0UL)
- vga_msg_box_destroy(&vgabox);
- }
-
- return ret;
-}
-
-/* returns: -2 if an error happened
- * -1 if user said to cancel
- * 0 if not busy
- * 1 if still busy, but user said to proceed */
-int do_ide_controller_user_wait_drive_drq(struct ide_controller *ide) {
- struct vga_msg_box vgabox;
- int ret = 0,c = 0;
-
- if (ide == NULL)
- return -1;
-
- /* NTS: We ignore the Drive Ready Bit, because logically, that bit reflects
- * when the drive is ready for another command. Obviously if we're waiting
- * for DATA related to a command, then the command is not complete!
- * I'm also assuming there are dumbshit IDE controller and hard drive
- * implementations dumb enough to return such confusing state. */
- /* use the alt status register if possible, else the base I/O.
- * the alt status register is said not to clear pending interrupts */
- idelib_controller_update_status(ide);
- if (!idelib_controller_is_drq_ready(ide)) {
- unsigned long show_countdown = 500000UL / 100UL; /* 0.5s / 100us units */
-
- do {
- idelib_controller_update_status(ide);
- if (idelib_controller_is_drq_ready(ide))
- break;
- else if (idelib_controller_is_error(ide)) {
- ret = -2;
- break;
- }
-
- /* if the drive&controller is busy then show the dialog and wait for non-busy
- * or until the user forces us to proceed */
- if (show_countdown > 0UL) {
- if (--show_countdown == 0UL)
- vga_msg_box_create(&vgabox,"Waiting for Data Request from IDE device\n\nHit ESC to cancel, spacebar to proceed anyway",0,0);
- }
-
- if (show_countdown == 0UL && kbhit()) { /* if keyboard input and we're showing prompt */
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- ret = -1;
- break;
- }
- else if (c == ' ') {
- ret = 1;
- break;
- }
- }
-
- t8254_wait(t8254_us2ticks(100)); /* wait 100us (0.0001 seconds) */
- } while (1);
-
- if (show_countdown == 0UL)
- vga_msg_box_destroy(&vgabox);
- }
-
- return ret;
-}
-
-/* returns: -1 if user said to cancel
- * 0 if not busy
- * 1 if still busy, but user said to proceed */
-int do_ide_controller_user_wait_irq(struct ide_controller *ide,uint16_t count) {
- struct vga_msg_box vgabox;
- int ret = 0,c = 0;
-
- if (ide == NULL)
- return -1;
-
- if (ide->irq_fired < count) {
- unsigned long show_countdown = 500000UL / 100UL; /* 0.5s / 100us units */
-
- do {
- if (ide->irq_fired >= count)
- break;
-
- /* if the drive&controller is busy then show the dialog and wait for non-busy
- * or until the user forces us to proceed */
- if (show_countdown > 0UL) {
- if (--show_countdown == 0UL)
- vga_msg_box_create(&vgabox,"Waiting for IDE IRQ\n\nHit ESC to cancel, spacebar to proceed anyway",0,0);
- }
-
- if (show_countdown == 0UL && kbhit()) { /* if keyboard input and we're showing prompt */
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- ret = -1;
- break;
- }
- else if (c == ' ') {
- ret = 1;
- break;
- }
- }
-
- t8254_wait(t8254_us2ticks(100)); /* wait 100us (0.0001 seconds) */
- } while (1);
-
- if (show_countdown == 0UL)
- vga_msg_box_destroy(&vgabox);
- }
-
- return ret;
-}
-
-/* returns: -1 if user said to cancel
- * 0 if not busy
- * 1 if still busy, but user said to proceed */
-int do_ide_controller_user_wait_drive_ready(struct ide_controller *ide) {
- struct vga_msg_box vgabox;
- int ret = 0,c;
-
- if (ide == NULL)
- return -1;
-
- /* use the alt status register if possible, else the base I/O.
- * the alt status register is said not to clear pending interrupts */
- idelib_controller_update_status(ide);
- if (!idelib_controller_is_drive_ready(ide)) {
- unsigned long show_countdown = 500000UL / 100UL; /* 0.5s / 100us units */
-
- /* if the drive&controller is busy then show the dialog and wait for non-busy
- * or until the user forces us to proceed */
-
- do {
- idelib_controller_update_status(ide);
- if (idelib_controller_is_drive_ready(ide))
- break;
- else if (idelib_controller_is_error(ide))
- break; /* this is possible too?? or is VirtualBox fucking with us when the CD-ROM drive is on Primary slave? */
-
- if (show_countdown > 0UL) {
- if (--show_countdown == 0UL)
- vga_msg_box_create(&vgabox,"IDE device not ready, waiting...\n\nHit ESC to cancel, spacebar to proceed anyway",0,0);
- }
-
- if (show_countdown == 0UL && kbhit()) { /* if keyboard input and we're showing prompt */
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- ret = -1;
- break;
- }
- else if (c == ' ') {
- ret = 1;
- break;
- }
- }
-
- t8254_wait(t8254_us2ticks(100)); /* wait 100us (0.0001 seconds) */
- } while (1);
-
- if (show_countdown == 0UL)
- vga_msg_box_destroy(&vgabox);
- }
-
- return ret;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "test.h"
-
-int do_ide_controller_user_wait_busy_timeout_controller(struct ide_controller *ide,unsigned int timeout/*ms*/); /* returns 1 if timed out */
-int do_ide_controller_user_wait_irq(struct ide_controller *ide,uint16_t count);
-int do_ide_controller_user_wait_busy_controller(struct ide_controller *ide);
-int do_ide_controller_user_wait_drive_ready(struct ide_controller *ide);
-int do_ide_controller_user_wait_drive_drq(struct ide_controller *ide);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-void do_drive_atapi_eject_load(struct ide_controller *ide,unsigned char which,unsigned char atapi_eject_how) {
- struct vga_msg_box vgabox;
- uint8_t buf[12] = {0x1B/*EJECT*/,0x00,0x00,0x00, /* ATAPI EJECT (START/STOP UNIT) command */
- 0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00};
- /* NTS: buf[4] is filled in with how to start/stop the unit:
- * 0x00 STOP (spin down)
- * 0x01 START (spin up)
- * 0x02 EJECT (eject CD, usually eject CD-ROM tray)
- * 0x03 LOAD (load CD, close CD tray if drive is capable) */
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- if (idelib_controller_atapi_prepare_packet_command(ide,/*xfer=to host no DMA*/0x04,/*byte count=*/0) < 0) /* fill out taskfile with command */
- return;
- if (idelib_controller_apply_taskfile(ide,0xBE/*base_io+1-5&7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0) /* also writes command */
- return;
-
- /* NTS: Despite OSDev ATAPI advice, IRQ doesn't seem to fire at this stage, we must poll wait */
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- idelib_controller_update_atapi_state(ide);
- if (!(ide->last_status&1)) { /* if no error, read result from count register */
- do_warn_if_atapi_not_in_command_state(ide); /* sector count register should signal we're in the command stage */
-
- buf[4] = atapi_eject_how; /* fill in byte 4 which tells ATAPI how to start/stop the unit */
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- idelib_controller_atapi_write_command(ide,buf,12); /* write 12-byte ATAPI command data */
- if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-
- do_warn_if_atapi_not_in_complete_state(ide); /* sector count register should signal we're in the completed stage (command/data=1 input/output=1) */
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-static const char *drive_cdrom_startstop_strings[] = {
- "Show IDE register taskfile", /* 0 */
- "Eject",
- "Load",
- "Start",
- "Stop"
-};
-
-void do_drive_cdrom_startstop_test(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_cdrom_startstop_strings);
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* select the drive we want */
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
-
- /* in case the IDE controller is busy for that time */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
-
- /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
- do_ide_controller_atapi_device_check_post_host_reset(ide);
-
- /* wait for the drive to indicate readiness */
- /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
- * possibility that the device doesn't exist. This can happen for example if there
- * is a master attached but no slave. */
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
-
- /* for completeness, clear pending IRQ */
- idelib_controller_ack_irq(ide);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- vga_write(" << CD-ROM eject/load");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE drive main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /*Eject*/
- case 2: /*Load*/
- case 3: /*Start*/
- case 4: /*Stop*/ {
- static const unsigned char cmd[4] = {2/*eject*/,3/*load*/,1/*start*/,0/*stop*/};
- do_drive_atapi_eject_load(ide,which,cmd[select-1]);
- } break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
+++ /dev/null
-
-void do_drive_atapi_eject_load(struct ide_controller *ide,unsigned char which,unsigned char atapi_eject_how);
-void do_drive_cdrom_startstop_test(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-static void do_cdrom_drive_read_test(struct ide_controller *ide,unsigned char which,unsigned char continuous) {
- uint16_t drq_log[((unsigned long)sizeof(cdrom_sector))/2048UL];
- unsigned long sector = 16; /* read the ISO 9660 table of contents */
- unsigned long tlen = 2048; /* one sector */
- unsigned long tlen_sect = 1;
- unsigned char user_esc = 0;
- struct vga_msg_box vgabox;
- unsigned int drq_log_ent;
- unsigned int cleared=0;
- uint8_t buf[12] = {0};
- unsigned int x,y,i;
- int c;
-
- sector = prompt_cdrom_sector_number();
- if (sector == ~0UL)
- return;
- tlen_sect = prompt_cdrom_sector_count();
- if (tlen_sect == 0UL || tlen_sect == ~0UL)
- return;
- if (tlen_sect > ((unsigned long)sizeof(cdrom_sector) / 2048UL))
- tlen_sect = ((unsigned long)sizeof(cdrom_sector) / 2048UL);
- if (tlen_sect > ((65536UL/2048UL)-1UL)) /* don't try ATAPI requests 64KB or larger, the size field is 16-bit wide */
- tlen_sect = ((65536UL/2048UL)-1UL);
- tlen = tlen_sect * 2048UL;
-
-again: /* jump point: send execution back here for another sector */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- if (idelib_controller_atapi_prepare_packet_command(ide,/*xfer=to host no DMA*/0x04,/*byte count=*/tlen) < 0) /* fill out taskfile with command */
- return;
- if (idelib_controller_apply_taskfile(ide,0xBE/*base_io+1-5&7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0) /* also writes command */
- return;
-
- /* NTS: Despite OSDev ATAPI advice, IRQ doesn't seem to fire at this stage, we must poll wait */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- idelib_controller_update_atapi_state(ide);
- if (!(ide->last_status&1)) { /* if no error, read result from count register */
- do_warn_if_atapi_not_in_command_state(ide); /* sector count register should signal we're in the command stage */
-
- do_construct_atapi_scsi_mmc_read(buf,sector,tlen_sect,cdrom_read_mode);
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- idelib_controller_atapi_write_command(ide,buf,12); /* write 12-byte ATAPI command data */
- if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
- if (do_ide_controller_user_wait_irq(ide,1) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
- unsigned int ret_len = 0,drq_len,ey;
-
- /* NTS: I hate to break it to newbie IDE programmers, but reading back the sector isn't
- * quite the simple "read N bytes" from the drive. In reality, you wait for the drive
- * to signal DRQ, and then read back the length of data it has available for you to
- * read by, then you read that amount, and if more data is due, then you wait for
- * another IRQ and DRQ signal.
- *
- * In most cases, the DRQ returned by the drive is the same length you passed in,
- * but NOT ALWAYS. Many cheap laptop drives for example will only return "2048"
- * because they don't have a lot of buffer, and many DVD-ROM drives like to vary
- * the DRQ size per transfer for whatever reason, whether "dynamically" according
- * to CD-ROM spin speed or based on whatever data it's managed to read and buffer
- * so far.
- *
- * On the positive side, it means that on an error, the transfer can abort early if
- * it needs to. */
- drq_log_ent = 0;
- memset(cdrom_sector,0,tlen);
- while (ret_len < tlen) {
- if (idelib_controller_is_error(ide)) {
- vga_msg_box_create(&vgabox,"Error",0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- break;
- }
-
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- idelib_controller_update_atapi_drq(ide); /* also need to read back the DRQ (data) length the drive has chosen */
- if (idelib_controller_atapi_complete_state(ide)) { /* if suddenly in complete state, exit out */
- do_warn_if_atapi_not_in_data_input_state(ide); /* sector count register should signal we're in the completed stage (command/data=0 input/output=1) */
- break;
- }
-
- if (do_ide_controller_user_wait_drive_drq(ide) < 0) {
- user_esc = 1;
- break;
- }
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- idelib_controller_update_atapi_drq(ide); /* also need to read back the DRQ (data) length the drive has chosen */
- do_warn_if_atapi_not_in_data_input_state(ide); /* sector count register should signal we're in the completed stage (command/data=0 input/output=1) */
-
- assert(drq_log_ent < (sizeof(drq_log)/sizeof(drq_log[0])));
- drq_len = idelib_controller_read_atapi_drq(ide);
- drq_log[drq_log_ent++] = drq_len;
- if (drq_len < 2048UL || (drq_len % 2048UL) != 0UL || (drq_len+ret_len) > tlen) {
- /* we're asking for one sector (2048) bytes, the drive should return that, if not, something's wrong.
- * even cheap POS drives in old laptops will at least always return 2048! */
- sprintf(tmp,"Warning: ATAPI device returned unexpected DRQ=%u (%u+%u = %u)",
- drq_len,ret_len,tlen);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- break;
- }
-
- /* OK. read it in */
- idelib_read_pio_general(cdrom_sector+ret_len,drq_len,ide,IDELIB_PIO_WIDTH_DEFAULT);
- if (ide->flags.io_irq_enable) { /* NOW we wait for another IRQ (completion) */
- if (do_ide_controller_user_wait_irq(ide,1) < 0) {
- user_esc = 1;
- break;
- }
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0) {
- user_esc = 1;
- break;
- }
-
- ret_len += drq_len;
- }
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- do_warn_if_atapi_not_in_complete_state(ide); /* sector count register should signal we're in the completed stage (command/data=1 input/output=1) */
-
- /* ---- draw contents on the screen ---- */
- vga_write_color(0x0E);
- if (!cleared) {
- vga_clear();
- cleared = 1;
- }
-
- vga_moveto(0,0);
- vga_write("Contents of CD-ROM sector ");
- sprintf(tmp,"%lu-%lu",sector,sector+tlen_sect-1UL); vga_write(tmp);
- sprintf(tmp,"(%lu) bytes",(unsigned long)tlen); vga_write(tmp);
-
- ey = 3+16+3;
- vga_moveto(0,3+16+1);
- sprintf(tmp,"%u/%lu in %u DRQ transfers: ",ret_len,tlen,drq_log_ent);
- vga_write(tmp);
- for (x=0;x < drq_log_ent;x++) {
- int len = sprintf(tmp,"%u ",drq_log[x]);
- if ((vga_pos_x+len) > vga_width) vga_write("\n ");
- vga_write(tmp);
- }
- while (vga_pos_y <= ey) vga_write(" ");
-
- vga_moveto(0,2);
- vga_write_color(0x08);
- vga_write("BYTE ");
-
- vga_moveto(5,2);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"+%X ",x);
- vga_write(tmp);
- }
-
- vga_moveto(5+(16*3)+1,2);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"%X",x);
- vga_write(tmp);
- }
-
- for (i=0;i < (tlen/256UL);i++) { /* 16x16x8 = 2^(4+4+3) = 2^11 = 2048 */
- for (y=0;y < 16;y++) {
- vga_moveto(0,y+3);
- vga_write_color(0x08);
- sprintf(tmp,"%04X ",(i*256)+(y*16));
- vga_write(tmp);
- }
-
- for (y=0;y < 16;y++) {
- vga_moveto(5,y+3);
- vga_write_color(0x0F);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"%02X ",cdrom_sector[(i*256)+(y*16)+x]);
- vga_write(tmp);
- }
-
- vga_moveto(5+(16*3)+1,y+3);
- vga_write_color(0x0E);
- for (x=0;x < 16;x++) {
- vga_writec(sanitizechar(cdrom_sector[(i*256)+(y*16)+x]));
- }
- }
-
- if (continuous && !user_esc) {
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
- }
- break;
- }
- else {
- if ((c=wait_for_enter_or_escape()) == 27)
- break; /* allow user to exit early by hitting ESC */
- }
- }
-
- if (c != 27 && !user_esc) {
- /* if the user hit ENTER, then read another sector and display that too */
- sector += tlen_sect;
- goto again;
- }
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- do_warn_if_atapi_not_in_complete_state(ide); /* sector count register should signal we're in the completed stage (command/data=1 input/output=1) */
- }
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-static const char *drive_cdrom_reading_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "Read CD-ROM data sectors",
- "Read CD-ROM data continuously"
-};
-
-void do_drive_cdrom_reading(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_cdrom_reading_menustrings);
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* select the drive we want */
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
-
- /* in case the IDE controller is busy for that time */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
-
- /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
- do_ide_controller_atapi_device_check_post_host_reset(ide);
-
- /* wait for the drive to indicate readiness */
- /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
- * possibility that the device doesn't exist. This can happen for example if there
- * is a master attached but no slave. */
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
-
- /* for completeness, clear pending IRQ */
- idelib_controller_ack_irq(ide);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE drive main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /*Read sectors*/
- case 2: /*Read sectors continuously*/
- do_cdrom_drive_read_test(ide,which,/*continuous=*/(select==2));
- redraw = backredraw = 1;
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
+++ /dev/null
-
-void do_drive_read_one_sector_test(struct ide_controller *ide,unsigned char which);
-void do_drive_cdrom_reading(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "test.h"
-
-void common_ide_success_or_error_vga_msg_box(struct ide_controller *ide,struct vga_msg_box *vgabox) {
- if (!(ide->last_status&1)) {
- vga_msg_box_create(vgabox,"Success",0,0);
- }
- else {
- sprintf(tmp,"Device rejected with error %02X",ide->last_status);
- vga_msg_box_create(vgabox,tmp,0,0);
- }
-}
-
-void common_failed_to_read_taskfile_vga_msg_box(struct vga_msg_box *vgabox) {
- vga_msg_box_create(vgabox,"Failed to read taskfile",0,0);
-}
-
-void do_warn_if_atapi_not_in_command_state(struct ide_controller *ide) {
- struct vga_msg_box vgabox;
-
- if (!idelib_controller_atapi_command_state(ide)) {
- sprintf(tmp,"WARNING: ATAPI device not in command state as expected (state=%u)",idelib_controller_read_atapi_state(ide));
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-void do_warn_if_atapi_not_in_data_input_state(struct ide_controller *ide) {
- struct vga_msg_box vgabox;
-
- if (!idelib_controller_atapi_data_input_state(ide)) {
- sprintf(tmp,"WARNING: ATAPI device not in data input state as expected (state=%u)",idelib_controller_read_atapi_state(ide));
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-void do_warn_if_atapi_not_in_complete_state(struct ide_controller *ide) {
- struct vga_msg_box vgabox;
-
- if (!idelib_controller_atapi_complete_state(ide)) {
- sprintf(tmp,"WARNING: ATAPI device not in complete state as expected (state=%u)",idelib_controller_read_atapi_state(ide));
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-int do_ide_controller_drive_check_select(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
- int c,ret = 0;
-
- if (idelib_controller_update_taskfile(ide,0xC0/* status and drive/select */,IDELIB_TASKFILE_LBA48_UPDATE) < 0)
- return -1;
-
- if (which != ide->selected_drive || ide->head_select == 0xFF) {
- vga_msg_box_create(&vgabox,"IDE controller drive select unsuccessful\n\nHit ESC to cancel, spacebar to proceed anyway",0,0);
-
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- ret = -1;
- break;
- }
- else if (c == ' ') {
- ret = 1;
- break;
- }
- } while (1);
-
- vga_msg_box_destroy(&vgabox);
- return ret;
- }
-
- return ret;
-}
-
-void do_common_show_ide_taskfile(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
- int c;
-
- if (idelib_controller_update_taskfile(ide,0xFF,0) == 0) {
- struct ide_taskfile *tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
-
- vga_write_color(0x0F);
- vga_clear();
-
- vga_moveto(0,0);
- vga_write("IDE taskfile:\n\n");
-
- vga_write("IDE controller:\n");
- sprintf(tmp," selected_drive=%u last_status=0x%02x drive_address=0x%02x\n device_control=0x%02x head_select=0x%02x\n\n",
- ide->selected_drive, ide->last_status,
- ide->drive_address, ide->device_control,
- ide->head_select);
- vga_write(tmp);
-
- vga_write("IDE device:\n");
- sprintf(tmp," assume_lba48=%u\n",tsk->assume_lba48);
- vga_write(tmp);
- sprintf(tmp," error=0x%02x\n",tsk->error); /* aliased to features */
- vga_write(tmp);
- sprintf(tmp," sector_count=0x%04x\n",tsk->sector_count);
- vga_write(tmp);
- sprintf(tmp," lba0_3/chs_sector=0x%04x\n",tsk->lba0_3);
- vga_write(tmp);
- sprintf(tmp," lba1_4/chs_cyl_low=0x%04x\n",tsk->lba1_4);
- vga_write(tmp);
- sprintf(tmp," lba2_5/chs_cyl_high=0x%04x\n",tsk->lba2_5);
- vga_write(tmp);
- sprintf(tmp," head_select=0x%02x\n",tsk->head_select);
- vga_write(tmp);
- sprintf(tmp," command=0x%02x\n",tsk->command);
- vga_write(tmp);
- sprintf(tmp," status=0x%02x\n",tsk->status);
- vga_write(tmp);
-
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
- }
- else {
- common_failed_to_read_taskfile_vga_msg_box(&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-int confirm_pio32_warning(struct ide_controller *ide) {
- if (ide->pio_width < 32 && pio_width_warning) {
- struct vga_msg_box vgabox;
- char proceed = 1;
- int c;
-
- if (pio_width_warning) {
- vga_msg_box_create(&vgabox,
- "WARNING: Data I/O will not function correctly if your IDE controller\n"
- "does not support 32-bit PIO. IDE data transfers are traditionally\n"
- "carried out as 16-bit I/O.\n"
- "\n"
- "In most cases, if the IDE controller is connected as a PCI device and\n"
- "the controller was made 1998 or later, it's likely safe to enable.\n"
- "Some hardware in the 1994-1997 timeframe may have problems.\n"
- "\n"
- "Though not confirmed, 32-bit PIO may also work if your IDE controller\n"
- "is connected to the VESA local bus port of your 486 motherboard. In\n"
- "that case it is recommended to try 32-bit VLB sync PIO first.\n"
- "\n"
- "Hit ENTER to proceed, ESC to cancel"
- ,0,0);
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
- vga_msg_box_destroy(&vgabox);
- if (c == 27) {
- proceed = 0;
- }
- else {
- pio_width_warning = 0;
- }
- }
-
- return proceed;
- }
-
- return 1;
-}
-
-int prompt_sector_count() {
- int sector = -1;
- struct vga_msg_box box;
- VGA_ALPHA_PTR sco;
- char temp_str[16];
- int c,i=0;
-
- vga_msg_box_create(&box,"Enter sector count:",2,0);
- sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
- while (1) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- sector = (int)(~0UL);
- break;
- }
- else if (c == 13) {
- if (i == 0) break;
- temp_str[i] = 0;
- if (isdigit(temp_str[0]))
- sector = (int)strtol(temp_str,NULL,0);
- else
- sector = -1;
-
- break;
- }
- else if (isdigit(c)) {
- if (i < 15) {
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- }
- }
- else if (c == 8) {
- if (i > 0) i--;
- sco[i] = ' ' | 0x1E00;
- }
- }
- vga_msg_box_destroy(&box);
-
- return sector;
-}
-
-unsigned long prompt_cdrom_sector_number() {
- unsigned long sector = 16;
- struct vga_msg_box box;
- VGA_ALPHA_PTR sco;
- char temp_str[16];
- int c,i=0;
-
- vga_msg_box_create(&box,"Enter CD-ROM sector number:",2,0);
- sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
- while (1) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- sector = (int)(~0UL);
- break;
- }
- else if (c == 13) {
- if (i == 0) break;
- temp_str[i] = 0;
- if (isdigit(temp_str[0]))
- sector = strtol(temp_str,NULL,0);
- else
- sector = 16;
-
- break;
- }
- else if (isdigit(c)) {
- if (i < 15) {
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- }
- }
- else if (c == 8) {
- if (i > 0) i--;
- sco[i] = ' ' | 0x1E00;
- }
- }
- vga_msg_box_destroy(&box);
-
- return sector;
-}
-
-unsigned long prompt_cdrom_sector_count() {
- unsigned long sector = 1;
- struct vga_msg_box box;
- VGA_ALPHA_PTR sco;
- char temp_str[16];
- int c,i=0;
-
- vga_msg_box_create(&box,"Enter number of CD-ROM sectors to read at once:",2,0);
- sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
- while (1) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- sector = (int)(~0UL);
- break;
- }
- else if (c == 13) {
- if (i == 0) break;
- temp_str[i] = 0;
- if (isdigit(temp_str[0]))
- sector = strtol(temp_str,NULL,0);
- else
- sector = 1;
-
- break;
- }
- else if (isdigit(c)) {
- if (i < 15) {
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- }
- }
- else if (c == 8) {
- if (i > 0) i--;
- sco[i] = ' ' | 0x1E00;
- }
- }
- vga_msg_box_destroy(&box);
-
- return sector;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "test.h"
-
-void common_ide_success_or_error_vga_msg_box(struct ide_controller *ide,struct vga_msg_box *vgabox);
-int do_ide_controller_drive_check_select(struct ide_controller *ide,unsigned char which);
-void do_common_show_ide_taskfile(struct ide_controller *ide,unsigned char which);
-void common_failed_to_read_taskfile_vga_msg_box(struct vga_msg_box *vgabox);
-void do_warn_if_atapi_not_in_data_input_state(struct ide_controller *ide);
-void do_warn_if_atapi_not_in_complete_state(struct ide_controller *ide);
-void do_warn_if_atapi_not_in_command_state(struct ide_controller *ide);
-int confirm_pio32_warning(struct ide_controller *ide);
-unsigned long prompt_cdrom_sector_number();
-unsigned long prompt_cdrom_sector_count();
-int prompt_sector_count();
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-int do_ide_media_card_pass_through(struct ide_controller *ide,unsigned char which,unsigned char enable) {
- struct ide_taskfile *tsk;
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return -1;
-
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
- tsk->features = (enable != 0 ? 1 : 0);
- idelib_controller_apply_taskfile(ide,0x02/*base_io+1*/,IDELIB_TASKFILE_LBA48_UPDATE|IDELIB_TASKFILE_LBA48);
- idelib_controller_write_command(ide,0xD1); /* <- (D1h) CHECK MEDIA CARD TYPE */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (ide->last_status&1) return 1;
- return 0;
-}
-
-int do_ide_set_multiple_mode(struct ide_controller *ide,unsigned char which,unsigned char sz) {
- struct ide_taskfile *tsk;
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return -1;
-
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
- tsk->sector_count = sz;
- idelib_controller_apply_taskfile(ide,0x04/*base_io+2*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/);
- idelib_controller_write_command(ide,0xC6); /* <- (C6h) SET MULTIPLE MODE */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (ide->last_status&1) return 1;
- return 0;
-}
-
-int do_ide_identify(unsigned char *info/*512*/,unsigned int sz,struct ide_controller *ide,unsigned char which,unsigned char command) {
- if (sz < 512)
- return -1;
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return -1;
-
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
- idelib_controller_write_command(ide,command); /* <- (A1h) identify packet device (ECh) identify device */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (ide->last_status&1) return 1;
-
- /* read it */
- do_ide_controller_user_wait_drive_drq(ide);
- idelib_read_pio_general((unsigned char*)info,512,ide,IDELIB_PIO_WIDTH_DEFAULT);
- return 0;
-}
-
-int do_ide_flush(struct ide_controller *ide,unsigned char which,unsigned char lba48) {
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return -1;
-
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
- idelib_controller_write_command(ide,lba48?0xEA:0xE7); /* <- (E7h) FLUSH CACHE (EA) FLUSH CACHE EXT */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (ide->last_status&1) return 1;
- return 0;
-}
-
-int do_ide_device_diagnostic(struct ide_controller *ide,unsigned char which) {
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return -1;
-
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
- idelib_controller_write_command(ide,0x90); /* <- (90h) EXECUTE DEVICE DIAGNOSTIC */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (ide->last_status&1) return 1;
- return 0;
-}
-
-void do_ident_save(const char *basename,struct ide_controller *ide,unsigned char which,uint16_t *nfo/*512 bytes/256 words*/,unsigned char command) {
- unsigned char range[512];
- unsigned char orgl;
- char fname[24];
- int fd,r;
-
- /* also record how the drive records SET MULTIPLE MODE */
- orgl = nfo[59]&0xFF;
- vga_write("Scanning SET MULTIPLE MODE supported values\n");
- for (r=0;r < 256;r++) {
- /* set sector count, then use IDENTIFY DEVICE to read back the value */
- if (do_ide_set_multiple_mode(ide,which,r) < 0)
- break;
- if (do_ide_identify((unsigned char*)nfo,512,ide,which,command) < 0)
- break;
- range[r] = nfo[59]&0xFF;
-
- /* then set it back to "1" */
- if (do_ide_set_multiple_mode(ide,which,1) < 0)
- break;
- if (do_ide_identify((unsigned char*)nfo,512,ide,which,command) < 0)
- break;
- range[r+256] = nfo[59]&0xFF;
-
- vga_write(".");
- }
- vga_write("\n");
-
- /* restore the original value */
- if (do_ide_set_multiple_mode(ide,which,orgl) < 0)
- return;
- if (do_ide_identify((unsigned char*)nfo,512,ide,which,command) < 0)
- return;
-
- /* we might be running off the IDE drive we're about to write to.
- * so to avoid hangups in INT 13h and DOS we need to temporarily unhook the IRQ and
- * reenable the IRQ for the BIOS */
- do_ide_controller_enable_irq(ide,0);
- idelib_enable_interrupt(ide,1); /* <- in case of stupid/lazy BIOS */
-
- /* if SMARTDRV is resident, now is a good time to write to disk */
- if (smartdrv_version != 0) {
- for (r=0;r < 4;r++) smartdrv_flush();
- }
-
- /* OK. start writing */
- sprintf(fname,"%s.ID",basename);
- fd = open(fname,O_WRONLY|O_BINARY|O_CREAT|O_TRUNC,0666);
- if (fd >= 0) {
- write(fd,nfo,512);
- close(fd);
- }
-
- sprintf(fname,"%s.SMM",basename);
- fd = open(fname,O_WRONLY|O_BINARY|O_CREAT|O_TRUNC,0666);
- if (fd >= 0) {
- write(fd,range,512);
- close(fd);
- }
-
- /* if SMARTDRV is resident, flush our snapshot to disk because we're going
- * to take over the IDE controller again */
- if (smartdrv_version != 0) {
- for (r=0;r < 4;r++) smartdrv_flush();
- }
-
- /* OK. hook it again. */
- do_ide_controller_enable_irq(ide,ide->flags.io_irq_enable);
-}
-
-void do_drive_identify_device_test(struct ide_controller *ide,unsigned char which,unsigned char command) {
- unsigned int x,y,i;
- uint16_t info[256];
- int r;
-
- r = do_ide_identify((unsigned char*)info,sizeof(info),ide,which,command);
- if (r == 0) {
- /* ------------ PAGE 1 -------------*/
- vga_write_color(0x0E); vga_clear();
-
- vga_moveto(0,0); vga_write("Serial: ");
- for (x=0;x < 10;x++) {
- tmp[x*2 + 0] = info[10+x] >> 8;
- tmp[x*2 + 1] = info[10+x] & 0xFF;
- }
- tmp[10*2] = 0; vga_write(tmp);
-
- vga_write(" F/W rev: ");
- for (x=0;x < 4;x++) {
- tmp[x*2 + 0] = info[23+x] >> 8;
- tmp[x*2 + 1] = info[23+x] & 0xFF;
- }
- tmp[4*2] = 0; vga_write(tmp);
-
- vga_write(" Model: ");
- for (x=0;x < 20;x++) {
- tmp[x*2 + 0] = info[27+x] >> 8;
- tmp[x*2 + 1] = info[27+x] & 0xFF;
- }
- tmp[20*2] = 0; vga_write(tmp);
-
- vga_moveto(0,1);
- sprintf(tmp,"Logical C/H/S: %u/%u/%u ",info[1],info[3],info[6]);
- vga_write(tmp);
- sprintf(tmp,"Current C/H/S: %u/%u/%u", info[54],info[55],info[56]);
- vga_write(tmp);
-
- vga_moveto(0,2);
- sprintf(tmp,"Current Capacity: %lu Total user addressable: %lu",
- (unsigned long)info[57] | ((unsigned long)info[58] << 16UL),
- (unsigned long)info[60] | ((unsigned long)info[61] << 16UL));
- vga_write(tmp);
-
- vga_moveto(0,3);
- sprintf(tmp,"LBA48 capacity: %llu",
- (unsigned long long)info[100] | ((unsigned long long)info[101] << 16ULL) | ((unsigned long long)info[102] << 32ULL) | ((unsigned long long)info[103] << 48ULL));
- vga_write(tmp);
-
- vga_moveto(0,4);
- vga_write_color(0x0D);
- vga_write("For more information read ATA documentation. ENTER to continue, 'S' to save.");
-
- /* top row */
- vga_moveto(0,5);
- vga_write_color(0x08);
- vga_write("WORD ");
-
- vga_moveto(5,5);
- for (x=0;x < 8;x++) {
- sprintf(tmp,"+%u ",x);
- vga_write(tmp);
- }
- vga_moveto(46,5);
- for (x=0;x < 8;x++) {
- sprintf(tmp,"%u ",x);
- vga_write(tmp);
- }
- vga_write("HI/LO byte order");
-
- /* data, page by page */
- for (i=0;i < 2;i++) {
- for (y=0;y < 16;y++) {
- vga_moveto(0,6+y);
- vga_write_color(0x08);
- for (x=0;x < 8;x++) {
- sprintf(tmp,"%04x ",(y*8)+(i*128)+x);
- vga_write(tmp);
- }
-
- vga_moveto(5,6+y);
- vga_write_color(0x0F);
- for (x=0;x < 8;x++) {
- sprintf(tmp,"%04x ",info[(y*8)+(i*128)+x]);
- vga_write(tmp);
- }
-
- vga_moveto(46,6+y);
- vga_write_color(0x0E);
- for (x=0;x < 8;x++) {
- vga_writec(sanitizechar(info[(y*8)+(i*128)+x] >> 8));
- vga_writec(sanitizechar(info[(y*8)+(i*128)+x] & 0xFF));
- }
- }
-
- /* wait for ENTER, ESC, or 'S' */
- do {
- r=getch();
- if (r == 's' || r == 'S') {
- vga_write_color(0x0E); vga_clear(); vga_moveto(0,0);
- do_ident_save(command == 0xA1 ? "ATAPI" : "ATA",ide,which,info,command);
- vga_write("\nSaved. Hit ENTER to continue.\n");
- wait_for_enter_or_escape();
- break;
- }
- else if (r == 27 || r == 13) {
- break;
- }
- } while (1);
-
- /* ESC or 'S' to break out */
- if (r == 's' || r == 27)
- break;
- }
- }
- else if (r > 0) {
- struct vga_msg_box vgabox;
-
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
+++ /dev/null
-
-int do_ide_identify(unsigned char *buf/*512*/,unsigned int sz,struct ide_controller *ide,unsigned char which,unsigned char command);
-int do_ide_set_multiple_mode(struct ide_controller *ide,unsigned char which,unsigned char sz);
-void do_drive_identify_device_test(struct ide_controller *ide,unsigned char which,unsigned char command);
-int do_ide_flush(struct ide_controller *ide,unsigned char which,unsigned char lba48);
-int do_ide_device_diagnostic(struct ide_controller *ide,unsigned char which);
-int do_ide_media_card_pass_through(struct ide_controller *ide,unsigned char which,unsigned char enable);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "test.h"
-
-void menuboxbound_redraw(struct menuboxbounds *mbox,int select) {
- int i,x,y;
-
- for (i=0;i <= mbox->item_max;i++) {
- int col = i / mbox->rows;
- x = mbox->ofsx + (col * mbox->col_width);
- y = mbox->ofsy + (i % mbox->rows);
-
- vga_moveto(x,y);
- vga_write_color((select == i) ? 0x70 : 0x0F);
- vga_write(mbox->item_string[i]);
- while (vga_pos_x < (x+mbox->col_width) && vga_pos_x != 0) vga_writec(' ');
- }
-}
-
-void menuboxbounds_set_def_list(struct menuboxbounds *mbox,unsigned int ofsx,unsigned int ofsy,unsigned int cols) {
- mbox->cols = 1;
- mbox->ofsx = 4;
- mbox->ofsy = 7;
- mbox->rows = vga_height - (mbox->ofsy + 1);
- mbox->width = vga_width - (mbox->ofsx * 2);
- mbox->col_width = mbox->width / mbox->cols;
-}
-
-void menuboxbounds_set_item_strings_array(struct menuboxbounds *mbox,const char **str,unsigned int count) {
- mbox->item_string = str;
- mbox->item_max = count - 1;
-}
-
+++ /dev/null
-
-struct menuboxbounds {
- unsigned char cols,rows;
- unsigned char ofsx,ofsy;
- unsigned char col_width;
- unsigned char width,height;
- const char** item_string;
- int item_max;
-};
-
-void menuboxbound_redraw(struct menuboxbounds *mbox,int select);
-void menuboxbounds_set_def_list(struct menuboxbounds *mbox,unsigned int ofsx,unsigned int ofsy,unsigned int cols);
-void menuboxbounds_set_item_strings_array(struct menuboxbounds *mbox,const char **str,unsigned int count);
-
-#define menuboxbounds_set_item_strings_arraylen(mbox,str) \
- menuboxbounds_set_item_strings_array(mbox,str,sizeof(str)/sizeof(str[0]))
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "testmumo.h"
-#include "testmisc.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef MISC_TEST
-
-/*-----------------------------------------------------------------*/
-
-static const char *drive_misc_tests_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "Flush cache",
- "Flush cache ext (LBA48)",
- "Execute device diagnostic",
- "CFA Disable Media Card Pass through",
- "CFA Enable Media Card Pass through" /* 5*/
-};
-
-void do_drive_misc_tests(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- struct vga_msg_box vgabox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_misc_tests_menustrings);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller read/write tests ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE controller main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /* Flush cache */
- do_ide_flush(ide,which,/*lba48*/0);
- if (!idelib_controller_is_error(ide))
- vga_msg_box_create(&vgabox,"Success",0,0);
- else
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- redraw = 1;
- break;
- case 2: /* Flush cache ext */
- do_ide_flush(ide,which,/*lba48*/1);
- if (!idelib_controller_is_error(ide))
- vga_msg_box_create(&vgabox,"Success",0,0);
- else
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- redraw = 1;
- break;
- case 3: /* Execute device diagnostic */
- do_ide_device_diagnostic(ide,which);
- if (!idelib_controller_is_error(ide))
- vga_msg_box_create(&vgabox,"Success",0,0);
- else
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- redraw = 1;
- break;
- case 4: /* Disable media card pass through */
- do_ide_media_card_pass_through(ide,which,0);
- if (!idelib_controller_is_error(ide))
- vga_msg_box_create(&vgabox,"Success",0,0);
- else
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- redraw = 1;
- break;
- case 5: /* Enable media card pass through */
- do_ide_media_card_pass_through(ide,which,1);
- if (!idelib_controller_is_error(ide))
- vga_msg_box_create(&vgabox,"Success",0,0);
- else
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- redraw = 1;
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-#endif /* MISC_TEST */
-
+++ /dev/null
-
-void do_drive_misc_tests(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "testmumo.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef MULTIPLE_MODE_MENU
-
-static const char *drive_multiple_mode_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "Set sector count",
- "Probe valid values"
-};
-
-void do_drive_multiple_mode(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- uint16_t info[256];
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int r;
- int c;
-
- /* OK do it */
- r = do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
- if (r > 0) {
- struct vga_msg_box vgabox;
-
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
- else if (r < 0) {
- return;
- }
-
- /* WORD 47: [15:8] RESERVED
- * [7:0] Maximum number of sectors that shall be transferred per interrupt on READ/WRITE multiple */
- /* WORD 59: [15:9] RESERVED
- * [8] Multiple sector setting is valid
- * [7:0] Current setting for number of sectors to transfer per interrupt for multiple read/write */
- if (!(info[47]&0xFF)) {
- struct vga_msg_box vgabox;
-
- vga_msg_box_create(&vgabox,"WARNING: IDE device does not appear to support SET MULTIPLE.\nENTER to continue, ESC to cancel.",0,0);
- r = wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- if (r == 27/*ESC*/) return;
- }
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_multiple_mode_menustrings);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE multiple mode: ");
- sprintf(tmp,"sec=%u / max=%u ",info[59]&0xFF,info[47]&0xFF);
- vga_write(tmp);
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE controller main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /*set sector count*/ {
- r = prompt_sector_count();
- if (r >= 0 && r < 256) {
- do_ide_set_multiple_mode(ide,which,r);
- do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
- redraw = backredraw = 1;
- }
- } break;
- case 2: /*probe valid values*/ {
- unsigned char orig_sz = info[59]&0xFF;
-
- redraw = backredraw = 1;
- vga_moveto(0,0);
- vga_write_color(0x0F);
- vga_clear();
- vga_write("Probing valid sector counts:\n\n");
- vga_write_color(0x0E);
-
- for (r=0;r < 256;r++) {
- /* set sector count, then use IDENTIFY DEVICE to read back the value */
- if (do_ide_set_multiple_mode(ide,which,r) < 0)
- break;
- if (do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/) < 0)
- break;
-
- if ((info[59]&0xFF) == r) {
- sprintf(tmp,"%u ",r);
- vga_write(tmp);
- }
- }
- vga_write("\n\n");
-
- /* and then restore the sector count */
- do_ide_set_multiple_mode(ide,which,orig_sz);
- do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
-
- vga_write_color(0x0F);
- vga_write("Hit ENTER to continue.\n");
- wait_for_enter_or_escape();
- } break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-#endif /* MULTIPLE_MODE_MENU */
-
+++ /dev/null
-
-void do_drive_multiple_mode(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-/* IDE NOP test */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "test.h"
-
-#include "testnop.h"
-
-#ifdef NOP_TEST
-void do_ide_controller_drive_nop_test(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
- struct ide_taskfile *tsk;
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
-
- /* fill the registers with a pattern and then issue the NOP command.
- * the NOP command should come back with unmodified registers */
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- tsk->features = 0x00; /* will read back into error reg */
- tsk->sector_count = 0x12;
- tsk->lba0_3 = 0x34;
- tsk->lba1_4 = 0x56;
- tsk->lba2_5 = 0x78;
- tsk->command = 0x00; /* <- NOP */
- idelib_controller_apply_taskfile(ide,0xBE/*base_io+1-5&7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/);
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (!(ide->last_status&1)) {
- vga_msg_box_create(&vgabox,"Success?? (It's not supposed to!)",0,0);
- }
- else if ((ide->last_status&0xC9) != 0x41) {
- sprintf(tmp,"Device rejected with status %02X (not the way it's supposed to)",ide->last_status);
- vga_msg_box_create(&vgabox,tmp,0,0);
- }
- else {
- idelib_controller_update_taskfile(ide,0xBE,0);
- if ((tsk->error&0x04) != 0x04) {
- vga_msg_box_create(&vgabox,"Device rejected with non-abort (not the way it's supposed to)",0,0);
- }
- else {
- unsigned char c=0,cc=0;
-
- c=tsk->sector_count; cc += (c == 0x12)?1:0;
- c=tsk->lba0_3; cc += (c == 0x34)?1:0;
- c=tsk->lba1_4; cc += (c == 0x56)?1:0;
- c=tsk->lba2_5; cc += (c == 0x78)?1:0;
-
- if (cc == 4)
- vga_msg_box_create(&vgabox,"Success",0,0);
- else
- vga_msg_box_create(&vgabox,"Failed. Registers were modified.",0,0);
- }
- }
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-}
-#endif /* NOP_TEST */
-
+++ /dev/null
-
-void do_ide_controller_drive_nop_test(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef PIO_MODE_MENU
-
-static const char *drive_main_pio_mode_strings[] = {
- "16-bit PIO (standard)", /* 0 */
- "32-bit PIO",
- "32-bit PIO (VLB sync)",
- "Autodetect"
-};
-
-void do_drive_pio_mode(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_main_pio_mode_strings);
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* select the drive we want */
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
-
- /* in case the IDE controller is busy for that time */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
-
- /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
- do_ide_controller_atapi_device_check_post_host_reset(ide);
-
- /* wait for the drive to indicate readiness */
- /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
- * possibility that the device doesn't exist. This can happen for example if there
- * is a master attached but no slave. */
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
-
- /* for completeness, clear pending IRQ */
- idelib_controller_ack_irq(ide);
-
- /* match selection to PIO mode */
- if (ide->pio_width == 16)
- select = 0;
- else if (ide->pio_width == 32)
- select = 1;
- else if (ide->pio_width == 33)
- select = 2;
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- vga_write(" << PIO mode");
- if (ide->pio_width == 33)
- vga_write(" [32-bit VLB]");
- else if (ide->pio_width == 32)
- vga_write(" [32-bit]");
- else
- vga_write(" [16-bit]");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE drive main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- unsigned char doexit = 0;
-
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* 16-bit */
- doexit = 1;
- ide->pio_width = 16;
- break;
- case 1: /* 32-bit */
- if (confirm_pio32_warning(ide)) {
- ide->pio_width = 32;
- doexit = 1;
- }
- break;
- case 2: /* 32-bit VLB */
- if (confirm_pio32_warning(ide)) {
- ide->pio_width = 33;
- doexit = 1;
- }
- break;
- case 3: /* Autodetect */
- redraw = backredraw = 1;
- ide_pio_autodetect(ide,which);
- if (ide->pio_width == 16)
- select = 0;
- else if (ide->pio_width == 32)
- select = 1;
- else if (ide->pio_width == 33)
- select = 2;
- break;
- };
-
- if (doexit)
- break;
- else
- redraw = 1;
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-#endif /* PIO_MODE_MENU */
-
+++ /dev/null
-
-void do_drive_pio_mode(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef PIO_AUTODETECT
-
-void ide_pio_autodetect(struct ide_controller *ide,unsigned char which) {
- unsigned char ok32=0,ok32vlb=0;
- unsigned char ident=0,identpacket=0;
- unsigned char *info_16 = cdrom_sector; /* 512 bytes */
- unsigned char *info_32 = cdrom_sector + 512; /* 1024 bytes */
- struct vga_msg_box vgabox;
- int c;
-
- pio_width_warning = 0;
-
- vga_msg_box_create(&vgabox,
- "I will test various data transfers to try and auto-detect whether\n"
- "or not your IDE controller can do 32-bit PIO.\n"
- "\n"
- "Hit ENTER to proceed, ESC to cancel"
- ,0,0);
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
- vga_msg_box_destroy(&vgabox);
- if (c == 27) return;
-
- /* OK start */
- vga_write_color(0x0E);
- vga_clear();
- vga_moveto(0,0);
- vga_write("PIO test in progress...\n\n");
-
- /* ====================================== 16-bit PIO ================================ */
- /* the secondary purpose of this test is to autodetect whether to carry out 32-bit PIO
- * using Identify or Identify Packet commands */
- vga_write("16-bit PIO test: ");
-
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
- do_ide_controller_atapi_device_check_post_host_reset(ide);
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
- idelib_controller_ack_irq(ide);
- idelib_controller_reset_irq_counter(ide);
-
- /* first: try identify device */
- vga_write("[0xEC] ");
- idelib_controller_write_command(ide,0xEC/*Identify device*/);
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (!(ide->last_status&1)) {
- ident = 1; /* it worked! */
- vga_write("OK ");
- do_ide_controller_user_wait_drive_drq(ide);
- idelib_read_pio_general(info_16,512,ide,16/*PIO 16*/);
- }
-
- /* then try identify packet device */
- if (!ident) {
- vga_write("[0xA1] ");
- idelib_controller_write_command(ide,0xA1/*Identify packet device*/);
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (!(ide->last_status&1)) {
- identpacket = 1; /* it worked! */
- vga_write("OK ");
- do_ide_controller_user_wait_drive_drq(ide);
- idelib_read_pio_general(info_16,512,ide,16/*PIO 16*/);
- }
- }
- vga_write("\n");
-
- if (!ident && !identpacket) {
- vga_write("Sorry, neither command worked. I don't have a reliable way to test.\nHit ENTER to continue.");
- wait_for_enter_or_escape();
- return;
- }
-
- /* ====================================== 32-bit PIO VLB ================================ */
- vga_write("32-bit PIO VLB test: ");
-
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
- do_ide_controller_atapi_device_check_post_host_reset(ide);
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
- idelib_controller_ack_irq(ide);
- idelib_controller_reset_irq_counter(ide);
-
- /* do it */
- idelib_controller_write_command(ide,identpacket ? 0xA1/*Identify packet device*/ : 0xEC/*Identify device*/);
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (!(ide->last_status&1)) {
- vga_write("OK ");
- do_ide_controller_user_wait_drive_drq(ide);
- idelib_read_pio_general(info_32,1024,ide,33/*PIO 32 VLB*/);
- idelib_discard_pio_general(512,ide,16/*PIO 16*/); /* <- in case 32-bit PIO did nothing, discard using 16-bit PIO */
-
- /* compare the data. is it the same? if so, 32-bit PIO is supported */
- if (!memcmp(info_16,info_32,512)) {
- vga_write("Data matches 16-bit PIO read, 32-bit VLB PIO supported");
- ok32vlb = 1;
- }
- /* if we see the 16-bit PIO interleaved with some other WORD junk across 1024 bytes then
- * we can assume it's likely the 16-bit data in the lower WORD and the contents of
- * IDE registers 0x1F2-0x1F3 in the upper WORD */
- else if (!ide_memcmp_every_other_word(info_16,info_32,256)) {
- vga_write("Like 16-bit PIO interleaved with junk, not supported");
- }
- /* another possibility seen on a Toshiba Satellite Pro, is that 32-bit PIO is flat out
- * ignored and we read back 0xFFFFFFFF, and the device acts as no PIO ever occurred */
- else if (!ide_memcmp_all_FF(info_32,1024)) {
- vga_write("No data whatsoever (0xFFFFFFFF), not supported");
- }
- else {
- vga_write("???");
- }
- }
- vga_write("\n");
-
- /* ====================================== 32-bit PIO ================================ */
- vga_write("32-bit PIO test: ");
-
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
- do_ide_controller_atapi_device_check_post_host_reset(ide);
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
- idelib_controller_ack_irq(ide);
- idelib_controller_reset_irq_counter(ide);
-
- /* do it */
- idelib_controller_write_command(ide,identpacket ? 0xA1/*Identify packet device*/ : 0xEC/*Identify device*/);
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- if (!(ide->last_status&1)) {
- vga_write("OK ");
- do_ide_controller_user_wait_drive_drq(ide);
- idelib_read_pio_general(info_32,1024,ide,32/*PIO 32*/);
- idelib_discard_pio_general(512,ide,16/*PIO 16*/); /* <- in case 32-bit PIO did nothing, discard using 16-bit PIO */
-
- /* compare the data. is it the same? if so, 32-bit PIO is supported */
- if (!memcmp(info_16,info_32,512)) {
- vga_write("Data matches 16-bit PIO read, 32-bit PIO supported");
- ok32 = 1;
- }
- /* if we see the 16-bit PIO interleaved with some other WORD junk across 1024 bytes then
- * we can assume it's likely the 16-bit data in the lower WORD and the contents of
- * IDE registers 0x1F2-0x1F3 in the upper WORD */
- else if (!ide_memcmp_every_other_word(info_16,info_32,256)) {
- vga_write("Like 16-bit PIO interleaved with junk, not supported");
- }
- /* another possibility seen on a Toshiba Satellite Pro, is that 32-bit PIO is flat out
- * ignored and we read back 0xFFFFFFFF, and the device acts as no PIO ever occurred */
- else if (!ide_memcmp_all_FF(info_32,1024)) {
- vga_write("No data whatsoever (0xFFFFFFFF), not supported");
- }
- else {
- vga_write("???");
- }
- }
- vga_write("\n");
-
- /* DEBUG */
- vga_write_color(0x0F);
- vga_write("\nHit enter to accept new PIO mode, ESC to cancel\n");
- c = wait_for_enter_or_escape();
- if (c == 27) return;
-
- if (ok32) ide->pio_width = 32;
- else if (ok32vlb) ide->pio_width = 33;
- else ide->pio_width = 16;
-}
-
-#endif /* PIO_AUTODETECT */
-
+++ /dev/null
-
-void ide_pio_autodetect(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-/* IDE power management commands test */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef POWER_MENU
-
-/* =================================== test functions ================================= */
-
-void do_drive_standby_test(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
- idelib_controller_write_command(ide,0xE0); /* <- standby immediate */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-}
-
-void do_drive_idle_test(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- idelib_controller_reset_irq_counter(ide);
- idelib_controller_write_command(ide,0xE1); /* <- idle immediate */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-}
-
-void do_drive_sleep_test(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
- int c;
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
- idelib_controller_write_command(ide,0xE6); /* <- sleep */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- /* do NOT wait for drive ready---the drive is never ready when it's asleep! */
- if (!(ide->last_status&1)) {
- vga_msg_box_create(&vgabox,"Success.\n\nHit ENTER to re-awaken the device",0,0);
- c = wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-
- if (c != 27) { /* if the user did NOT hit ESCAPE, then re-awaken the device */
- /* clear IRQ state, wait for IDE controller to signal ready.
- * once in sleep state, the device probably won't respond normally until device reset.
- * do NOT wait for drive ready, the drive will never be ready in this state because
- * (duh) it's asleep. */
-
- /* now re-awaken the device with DEVICE RESET */
- idelib_controller_ack_irq(ide);
- idelib_controller_reset_irq_counter(ide);
- idelib_controller_write_command(ide,0x08); /* <- device reset */
-
- /* NTS: some laptops, especially Toshiba, have a hard drive connected to the primary
- * channel. for some reason, issuing ANY command after sleep causes the IDE
- * controller to signal BUSY and never come out of it. The only way out of
- * the situation is to do a host reset (reset the IDE controller). */
- if (do_ide_controller_user_wait_busy_timeout_controller(ide,1000/*ms*/)) { /* if we waited too long for IDE ready */
- vga_msg_box_create(&vgabox,"Host reset in progress",0,0);
-
- idelib_device_control_set_reset(ide,1);
- t8254_wait(t8254_us2ticks(1000000));
- idelib_device_control_set_reset(ide,0);
-
- vga_msg_box_destroy(&vgabox);
- }
-
- do_ide_controller_user_wait_busy_controller(ide);
- idelib_controller_update_taskfile(ide,0xFF,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/); /* updating the taskfile seems to help with getting CD-ROM drives online */
-
- /* it MIGHT have fired an IRQ... */
- idelib_controller_ack_irq(ide);
-
- if (!idelib_controller_is_error(ide))
- vga_msg_box_create(&vgabox,"Success",0,0);
- else
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-
- do_ide_controller_atapi_device_check_post_host_reset(ide);
- do_ide_controller_user_wait_drive_ready(ide);
- }
- else {
- do_ide_controller_atapi_device_check_post_host_reset(ide);
- do_ide_controller_user_wait_busy_controller(ide);
- }
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-void do_drive_check_power_mode(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
- struct ide_taskfile *tsk;
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- idelib_controller_reset_irq_counter(ide);
-
- /* in case command doesn't do anything, fill sector count value with 0x0A */
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- tsk->sector_count = 0x0A; /* our special "codeword" to tell if the command updated it or not */
- idelib_controller_apply_taskfile(ide,0x04/*base_io+2*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/);
-
- idelib_controller_write_command(ide,0xE5); /* <- check power mode */
- if (ide->flags.io_irq_enable) {
- do_ide_controller_user_wait_irq(ide,1);
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
- do_ide_controller_user_wait_busy_controller(ide);
- do_ide_controller_user_wait_drive_ready(ide);
-
- if (!(ide->last_status&1)) { /* if no error, read result from count register */
- const char *what = "";
- unsigned char x;
-
- /* read back from sector count field */
- idelib_controller_update_taskfile(ide,0x04/*base_io+2*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/);
-
- x = tsk->sector_count;
- if (x == 0) what = "Standby mode";
- else if (x == 0x0A) what = "?? (failure to update reg probably)";
- else if (x == 0x40) what = "NV Cache Power mode spun/spin down";
- else if (x == 0x41) what = "NV Cache Power mode spun/spin up";
- else if (x == 0x80) what = "Idle mode";
- else if (x == 0xFF) what = "Active or idle";
-
- sprintf(tmp,"Result: %02X %s",x,what);
- vga_msg_box_create(&vgabox,tmp,0,0);
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- }
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-}
-
-void do_drive_device_reset_test(struct ide_controller *ide,unsigned char which) {
- struct vga_msg_box vgabox;
- struct ide_taskfile *tsk;
- int c;
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* select the drive we want */
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
-
- /* in case the IDE controller is busy for that time */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
-
- /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
- do_ide_controller_atapi_device_check_post_host_reset(ide);
-
- /* wait for the drive to indicate readiness */
- /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
- * possibility that the device doesn't exist. This can happen for example if there
- * is a master attached but no slave. */
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
-
- /* for completeness, clear pending IRQ */
- idelib_controller_ack_irq(ide);
- idelib_controller_reset_irq_counter(ide);
-
- /* make sure the registers are cleared */
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
- tsk->error = 0x99;
- tsk->sector_count = 0xAA;
- tsk->lba0_3 = 0xBB;
- tsk->lba1_4 = 0xCC;
- tsk->lba2_5 = 0xDD;
- idelib_controller_apply_taskfile(ide,0x3E/*base_io+1-5*/,IDELIB_TASKFILE_LBA48_UPDATE|IDELIB_TASKFILE_LBA48);
- idelib_controller_write_command(ide,0x08); /* <- device reset */
- do_ide_controller_user_wait_busy_controller(ide);
-
- /* it MIGHT have fired an IRQ... */
- idelib_controller_ack_irq(ide);
-
- /* NTS: Device reset doesn't necessary seem to signal an IRQ, at least not
- * immediately. On some implementations the IRQ will have fired by now,
- * on others, it will have fired by now for hard drives but for CD-ROM
- * drives will not fire until the registers are read back, and others
- * don't fire at all. So don't count on the IRQ, just poll and busy
- * wait for the drive to signal readiness. */
-
- if (idelib_controller_update_taskfile(ide,0xFF,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) == 0) {
- sprintf(tmp,"Device response: (0x1F1-0x1F7) %02X %02X %02X %02X %02X %02X %02X",
- tsk->error, tsk->sector_count,
- tsk->lba0_3, tsk->lba1_4,
- tsk->lba2_5, tsk->head_select,
- tsk->status);
- vga_msg_box_create(&vgabox,tmp,0,0);
- }
- else {
- common_failed_to_read_taskfile_vga_msg_box(&vgabox);
- }
-
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- do_ide_controller_atapi_device_check_post_host_reset(ide); /* NTS: This will change the taskfile further! */
- do_ide_controller_user_wait_drive_ready(ide);
-}
-
-/* =================================== menu for tests ================================= */
-
-static const char *drive_main_power_states_strings[] = {
- "Show IDE register taskfile", /* 0 */
- "Device reset",
- "Standby",
- "Sleep",
- "Idle",
- "Power mode" /* 5 */
-};
-
-void do_drive_power_states_test(struct ide_controller *ide,unsigned char which) {
- VGA_ALPHA_PTR vga;
- struct menuboxbounds mbox;
- char backredraw=1;
- unsigned int x,y;
- char redraw=1;
- int select=-1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_main_power_states_strings);
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* select the drive we want */
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
-
- /* in case the IDE controller is busy for that time */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
-
- /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
- do_ide_controller_atapi_device_check_post_host_reset(ide);
-
- /* wait for the drive to indicate readiness */
- /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
- * possibility that the device doesn't exist. This can happen for example if there
- * is a master attached but no slave. */
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
-
- /* for completeness, clear pending IRQ */
- idelib_controller_ack_irq(ide);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- vga_write(" << Power states");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE drive main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /* device reset */
- do_drive_device_reset_test(ide,which);
- break;
- case 2: /* standby */
- do_drive_standby_test(ide,which);
- break;
- case 3: /* sleep */
- do_drive_sleep_test(ide,which);
- break;
- case 4: /* idle */
- do_drive_idle_test(ide,which);
- break;
- case 5: /* check power mode */
- do_drive_check_power_mode(ide,which);
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-#endif /* POWER_MENU */
-
+++ /dev/null
-
-void do_drive_idle_test(struct ide_controller *ide,unsigned char which);
-void do_drive_sleep_test(struct ide_controller *ide,unsigned char which);
-void do_drive_standby_test(struct ide_controller *ide,unsigned char which);
-void do_drive_check_power_mode(struct ide_controller *ide,unsigned char which);
-void do_drive_device_reset_test(struct ide_controller *ide,unsigned char which);
-
-void do_drive_power_states_test(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "testmumo.h"
-#include "testrdts.h"
-#include "testrdws.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-static const char *drive_read_test_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "*mode*", /* 1 */ /* rewritten (CHS, LBA, CHS MULTI, etc) */
- drive_readwrite_test_geo, /* 2 */
- drive_readwrite_test_chs, /* 3 */
- drive_readwrite_test_numsec, /* 4 */
- drive_readwrite_test_mult, /* 5 */
- "Read sectors", /* 6 */
- "Read sectors continuously", /* 7 */
- "Read sectors (Zip ATAPI)", /* 8 */
- "Read sectors (Zip ATAPI) continuously" /* 9 */
-};
-
-#ifdef ATAPI_ZIP
-static void do_hdd_drive_read_atapi_test(struct ide_controller *ide,unsigned char which,unsigned char continuous,struct drive_rw_test_info *nfo) {
- uint16_t drq_log[((unsigned long)sizeof(cdrom_sector))/512UL];
- unsigned long sector = 16; /* read the ISO 9660 table of contents */
- unsigned long tlen = 512; /* one sector */
- unsigned long tlen_sect = 1;
- unsigned char user_esc = 0;
- struct vga_msg_box vgabox;
- unsigned int drq_log_ent;
- unsigned int cleared=0;
- uint8_t buf[12] = {0};
- unsigned int x,y,i;
- int c;
-
- sector = nfo->lba;
- tlen_sect = nfo->read_sectors;
- if (tlen_sect > ((unsigned long)sizeof(cdrom_sector) / 512UL))
- tlen_sect = ((unsigned long)sizeof(cdrom_sector) / 512UL);
- if (tlen_sect > ((65536UL/512UL)-1UL)) /* don't try ATAPI requests 64KB or larger, the size field is 16-bit wide */
- tlen_sect = ((65536UL/512UL)-1UL);
- if (tlen_sect == 0)
- return;
- tlen = tlen_sect * 512UL;
-
-again: /* jump point: send execution back here for another sector */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
- if (idelib_controller_atapi_prepare_packet_command(ide,/*xfer=to host no DMA*/0x04,/*byte count=*/tlen) < 0) /* fill out taskfile with command */
- return;
- if (idelib_controller_apply_taskfile(ide,0xBE/*base_io+1-5&7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0) /* also writes command */
- return;
-
- /* NTS: Despite OSDev ATAPI advice, IRQ doesn't seem to fire at this stage, we must poll wait */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- idelib_controller_update_atapi_state(ide);
- if (!(ide->last_status&1)) { /* if no error, read result from count register */
- do_warn_if_atapi_not_in_command_state(ide); /* sector count register should signal we're in the command stage */
-
- memset(buf,0,12);
- /* command: READ(10) */
- buf[0] = 0x28;
-
- /* fill in the Logical Block Address */
- buf[2] = sector >> 24;
- buf[3] = sector >> 16;
- buf[4] = sector >> 8;
- buf[5] = sector;
-
- buf[7] = tlen_sect >> 8;
- buf[8] = tlen_sect;
-
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- idelib_controller_atapi_write_command(ide,buf,12); /* write 12-byte ATAPI command data */
- if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
- if (do_ide_controller_user_wait_irq(ide,1) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
- unsigned int ret_len = 0,drq_len,ey;
-
- /* NTS: I hate to break it to newbie IDE programmers, but reading back the sector isn't
- * quite the simple "read N bytes" from the drive. In reality, you wait for the drive
- * to signal DRQ, and then read back the length of data it has available for you to
- * read by, then you read that amount, and if more data is due, then you wait for
- * another IRQ and DRQ signal.
- *
- * In most cases, the DRQ returned by the drive is the same length you passed in,
- * but NOT ALWAYS. Many cheap laptop drives for example will only return "512"
- * because they don't have a lot of buffer, and many DVD-ROM drives like to vary
- * the DRQ size per transfer for whatever reason, whether "dynamically" according
- * to CD-ROM spin speed or based on whatever data it's managed to read and buffer
- * so far.
- *
- * On the positive side, it means that on an error, the transfer can abort early if
- * it needs to. */
- drq_log_ent = 0;
- memset(cdrom_sector,0,tlen);
- while (ret_len < tlen) {
- if (idelib_controller_is_error(ide)) {
- vga_msg_box_create(&vgabox,"Error",0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- break;
- }
-
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- idelib_controller_update_atapi_drq(ide); /* also need to read back the DRQ (data) length the drive has chosen */
- if (idelib_controller_atapi_complete_state(ide)) { /* if suddenly in complete state, exit out */
- do_warn_if_atapi_not_in_data_input_state(ide); /* sector count register should signal we're in the completed stage (command/data=0 input/output=1) */
- break;
- }
-
- if (do_ide_controller_user_wait_drive_drq(ide) < 0) {
- user_esc = 1;
- break;
- }
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- idelib_controller_update_atapi_drq(ide); /* also need to read back the DRQ (data) length the drive has chosen */
- do_warn_if_atapi_not_in_data_input_state(ide); /* sector count register should signal we're in the completed stage (command/data=0 input/output=1) */
-
- assert(drq_log_ent < (sizeof(drq_log)/sizeof(drq_log[0])));
- drq_len = idelib_controller_read_atapi_drq(ide);
- drq_log[drq_log_ent++] = drq_len;
- if (drq_len < 512UL || (drq_len % 512UL) != 0UL || (drq_len+ret_len) > tlen) {
- /* we're asking for one sector (512) bytes, the drive should return that, if not, something's wrong.
- * even cheap POS drives in old laptops will at least always return 512! */
- sprintf(tmp,"Warning: ATAPI device returned unexpected DRQ=%u (%u+%u = %u)",
- drq_len,ret_len,tlen);
- vga_msg_box_create(&vgabox,tmp,0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- break;
- }
-
- /* OK. read it in */
- idelib_read_pio_general(cdrom_sector+ret_len,drq_len,ide,IDELIB_PIO_WIDTH_DEFAULT);
- if (ide->flags.io_irq_enable) { /* NOW we wait for another IRQ (completion) */
- if (do_ide_controller_user_wait_irq(ide,1) < 0) {
- user_esc = 1;
- break;
- }
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0) {
- user_esc = 1;
- break;
- }
-
- ret_len += drq_len;
- }
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- do_warn_if_atapi_not_in_complete_state(ide); /* sector count register should signal we're in the completed stage (command/data=1 input/output=1) */
-
- /* ---- draw contents on the screen ---- */
- vga_write_color(0x0E);
- if (!cleared) {
- vga_clear();
- cleared = 1;
- }
-
- vga_moveto(0,0);
- vga_write("Contents of hdd sector ");
- sprintf(tmp,"%lu-%lu",sector,sector+tlen_sect-1UL); vga_write(tmp);
- sprintf(tmp,"(%lu) bytes",(unsigned long)tlen); vga_write(tmp);
-
- ey = 3+16+3;
- vga_moveto(0,3+16+1);
- sprintf(tmp,"%u/%lu in %u DRQ transfers: ",ret_len,tlen,drq_log_ent);
- vga_write(tmp);
- for (x=0;x < drq_log_ent;x++) {
- int len = sprintf(tmp,"%u ",drq_log[x]);
- if ((vga_pos_x+len) > vga_width) vga_write("\n ");
- vga_write(tmp);
- }
- while (vga_pos_y <= ey) vga_write(" ");
-
- vga_moveto(0,2);
- vga_write_color(0x08);
- vga_write("BYTE ");
-
- vga_moveto(5,2);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"+%X ",x);
- vga_write(tmp);
- }
-
- vga_moveto(5+(16*3)+1,2);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"%X",x);
- vga_write(tmp);
- }
-
- for (i=0;i < (tlen/256UL);i++) { /* 16x16x8 = 2^(4+4+3) = 2^11 = 512 */
- for (y=0;y < 16;y++) {
- vga_moveto(0,y+3);
- vga_write_color(0x08);
- sprintf(tmp,"%04X ",(i*256)+(y*16));
- vga_write(tmp);
- }
-
- for (y=0;y < 16;y++) {
- vga_moveto(5,y+3);
- vga_write_color(0x0F);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"%02X ",cdrom_sector[(i*256)+(y*16)+x]);
- vga_write(tmp);
- }
-
- vga_moveto(5+(16*3)+1,y+3);
- vga_write_color(0x0E);
- for (x=0;x < 16;x++) {
- vga_writec(sanitizechar(cdrom_sector[(i*256)+(y*16)+x]));
- }
- }
-
- if (continuous && !user_esc) {
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
- }
- break;
- }
- else {
- if ((c=wait_for_enter_or_escape()) == 27)
- break; /* allow user to exit early by hitting ESC */
- }
- }
-
- if (c != 27 && !user_esc) {
- /* if the user hit ENTER, then read another sector and display that too */
- sector += tlen_sect;
- goto again;
- }
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
-
- idelib_controller_update_atapi_state(ide); /* having completed the command, read ATAPI state again */
- do_warn_if_atapi_not_in_complete_state(ide); /* sector count register should signal we're in the completed stage (command/data=1 input/output=1) */
- }
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-#endif
-
-static void do_hdd_drive_read_test(struct ide_controller *ide,unsigned char which,unsigned char continuous,struct drive_rw_test_info *nfo) {
- unsigned char user_esc = 0;
- struct vga_msg_box vgabox;
- struct ide_taskfile *tsk;
- unsigned long tlen_sect;
- unsigned int cleared=0;
- unsigned int x,y,i;
- unsigned long tlen;
- int c;
-
- if (nfo->read_sectors == 0) return;
-
- /* multiple mode: make sure the multiple sector count doesn't exceed our buffer size.
- * if it does, try to set multiple count to lesser value. */
- if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
- if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL) && nfo->multiple_sectors > 1) {
- /* even though most IDE devices really only support power-of-2 sizes, we do a scan downward anyway */
- c = ((unsigned long)sizeof(cdrom_sector) / 512UL);
- do {
- if (c <= 1) break;
- do_ide_set_multiple_mode(ide,which,c);
- {
- uint16_t info[256];
-
- do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
- drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
- }
-
- if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL))
- c--;
- else
- break;
- } while (1);
- }
-
- if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL))
- return;
- if (nfo->multiple_sectors == 0)
- return;
- }
-
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
-
-again: /* jump point: send execution back here for another sector */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
-
- tlen_sect = nfo->read_sectors;
- if (tlen_sect > ((unsigned long)sizeof(cdrom_sector) / 512UL))
- tlen_sect = ((unsigned long)sizeof(cdrom_sector) / 512UL);
-
- /* C/H/S continuous: limit reads to within track, don't cross. we can't assume the drive will do that. */
- if (continuous && (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE)) {
- if ((nfo->sector + tlen_sect) > nfo->num_sector)
- tlen_sect = (nfo->num_sector + 1 - nfo->sector);
- }
-
- tlen = tlen_sect * 512UL;
-
- if (nfo->mode == DRIVE_RW_MODE_LBA48 || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
- tsk->sector_count = tlen_sect;
- tsk->lba0_3 = nfo->lba & 0xFF;
- tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
- tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
- tsk->lba0_3 |= ((nfo->lba >> 24) & 0xFF) << 8;
- tsk->lba1_4 |= ((nfo->lba >> 32) & 0xFF) << 8;
- tsk->lba2_5 |= ((nfo->lba >> 40) & 0xFF) << 8;
- tsk->head_select = (which << 4) | 0x40;
-
- if (nfo->mode == DRIVE_RW_MODE_LBA48)
- tsk->command = 0x24; /* READ SECTORS EXT */
- else if (nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE)
- tsk->command = 0x29; /* READ MULTIPLE EXT */
-
- if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE|IDELIB_TASKFILE_LBA48/*set LBA48*/) < 0)
- return;
- }
- else {
- if (tsk->sector_count > 256) return;
- tsk->sector_count = (tlen_sect&0xFF);
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- tsk->chs_sector = nfo->sector;
- tsk->chs_cylinder_low = nfo->cylinder & 0xFF;
- tsk->chs_cylinder_high = (nfo->cylinder >> 8) & 0xFF;
- tsk->head_select = (nfo->head & 0xF) | (which << 4) | 0xA0;
- }
- else if (nfo->mode == DRIVE_RW_MODE_LBA || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE) {
- tsk->lba0_3 = nfo->lba & 0xFF;
- tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
- tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
- tsk->head_select = ((nfo->lba >> 24) & 0xF) | (which << 4) | 0xE0;
- }
-
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_LBA)
- tsk->command = 0x20; /* READ SECTORS */
- else if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE)
- tsk->command = 0xC4; /* READ MULTIPLE */
-
- if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0)
- return;
- }
-
- if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
- if (do_ide_controller_user_wait_irq(ide,1) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
- unsigned int ret_len = 0,drq_len;
-
- memset(cdrom_sector,0,tlen);
- while (ret_len < tlen) {
- if (idelib_controller_is_error(ide)) {
- vga_msg_box_create(&vgabox,"Error",0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- break;
- }
-
- if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
- if (do_ide_controller_user_wait_irq(ide,1) < 0) {
- user_esc = 1;
- break;
- }
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0) {
- user_esc = 1;
- break;
- }
-
- if (do_ide_controller_user_wait_drive_drq(ide) < 0) {
- user_esc = 1;
- break;
- }
-
- if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE ||
- nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
- drq_len = nfo->multiple_sectors * 512;
- if ((ret_len+drq_len) > tlen) drq_len = tlen - ret_len;
- }
- else
- drq_len = 512;
-
- /* OK. read it in and acknowledge */
- idelib_read_pio_general(cdrom_sector+ret_len,drq_len,ide,IDELIB_PIO_WIDTH_DEFAULT);
- ret_len += drq_len;
- }
-
- /* ---- draw contents on the screen ---- */
- vga_write_color(0x0E);
- if (!cleared) {
- vga_clear();
- cleared = 1;
- }
-
- vga_moveto(0,0);
- vga_write("Contents of HDD sector ");
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- sprintf(tmp,"CHS %u/%u/%u",nfo->cylinder,nfo->head,nfo->sector); vga_write(tmp);
- }
- else {
- sprintf(tmp,"%llu-%llu",nfo->lba,nfo->lba+(unsigned long long)tlen_sect-1ULL); vga_write(tmp);
- }
- sprintf(tmp,"(%lu) bytes ",(unsigned long)tlen); vga_write(tmp);
-
- vga_moveto(0,2);
- vga_write_color(0x08);
- vga_write("BYTE ");
-
- vga_moveto(5,2);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"+%X ",x);
- vga_write(tmp);
- }
-
- vga_moveto(5+(16*3)+1,2);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"%X",x);
- vga_write(tmp);
- }
-
- for (i=0;i < (tlen/256UL);i++) { /* 16x16x8 = 2^(4+4+3) = 2^11 = 2048 */
- for (y=0;y < 16;y++) {
- vga_moveto(0,y+3);
- vga_write_color(0x08);
- sprintf(tmp,"%04X ",(i*256)+(y*16));
- vga_write(tmp);
- }
-
- for (y=0;y < 16;y++) {
- vga_moveto(5,y+3);
- vga_write_color(0x0F);
- for (x=0;x < 16;x++) {
- sprintf(tmp,"%02X ",cdrom_sector[(i*256)+(y*16)+x]);
- vga_write(tmp);
- }
-
- vga_moveto(5+(16*3)+1,y+3);
- vga_write_color(0x0E);
- for (x=0;x < 16;x++) {
- vga_writec(sanitizechar(cdrom_sector[(i*256)+(y*16)+x]));
- }
- }
-
- if (continuous && !user_esc) {
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
- }
- break;
- }
- else {
- if ((c=wait_for_enter_or_escape()) == 27)
- break; /* allow user to exit early by hitting ESC */
- }
- }
-
- if (c != 27 && !user_esc) {
- /* if the user hit ENTER, then read another sector and display that too */
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- nfo->sector += (unsigned long long)tlen_sect;
- while (nfo->sector > nfo->num_sector) {
- nfo->sector -= nfo->num_sector;
- nfo->head++;
- }
- while (nfo->head >= nfo->num_head) {
- nfo->head -= nfo->num_head;
- nfo->cylinder++;
- }
-
- if (nfo->cylinder >= 16384) {
- nfo->cylinder = 16383;
- nfo->sector = nfo->num_sector;
- nfo->head = nfo->num_head - 1;
- }
-
- nfo->lba = (unsigned long long)nfo->cylinder * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head;
- nfo->lba += (unsigned long long)nfo->head * (unsigned long long)nfo->num_sector;
- nfo->lba += (unsigned long long)nfo->sector - 1ULL;
- }
- else {
- nfo->lba += (unsigned long long)tlen_sect;
-
- nfo->sector = (int)(nfo->lba % (unsigned long long)nfo->num_sector) + 1;
- nfo->head = (int)((nfo->lba / (unsigned long long)nfo->num_sector) % (unsigned long long)nfo->num_head);
- if (nfo->lba >= (16384ULL * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head)) {
- nfo->cylinder = 16383;
- nfo->sector = nfo->num_sector;
- nfo->head = nfo->num_head - 1;
- }
- else {
- nfo->cylinder = (int)((nfo->lba / (unsigned long long)nfo->num_sector) / (unsigned long long)nfo->num_head);
- }
- }
-
- goto again;
- }
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-void do_drive_read_test(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_read_test_menustrings);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE r/w tests ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
-
- sprintf(tmp," lba=%u lba48=%u multiple=%u",
- drive_rw_test_nfo.can_do_lba?1:0,
- drive_rw_test_nfo.can_do_lba48?1:0,
- drive_rw_test_nfo.can_do_multiple?1:0);
- vga_write(tmp);
-
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- drive_read_test_menustrings[1] = drive_readwrite_test_modes[drive_rw_test_nfo.mode];
-
- sprintf(drive_readwrite_test_geo,"Geometry: C/H/S %u/%u/%u LBA %llu",
- drive_rw_test_nfo.num_cylinder,
- drive_rw_test_nfo.num_head,
- drive_rw_test_nfo.num_sector,
- drive_rw_test_nfo.max_lba);
-
- sprintf(drive_readwrite_test_chs,"Position: C/H/S %u/%u/%u LBA %llu",
- drive_rw_test_nfo.cylinder,
- drive_rw_test_nfo.head,
- drive_rw_test_nfo.sector,
- drive_rw_test_nfo.lba);
-
- sprintf(drive_readwrite_test_numsec,"Number of sectors per read: %u",
- drive_rw_test_nfo.read_sectors);
-
- sprintf(drive_readwrite_test_mult,"Multiple mode: %u sectors (max=%u)",
- drive_rw_test_nfo.multiple_sectors,
- drive_rw_test_nfo.max_multiple_sectors);
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE controller main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /* Mode */
- do_drive_readwrite_test_choose_mode(ide,which,&drive_rw_test_nfo);
- redraw = backredraw = 1;
- break;
- case 2: /* Edit geometry/max LBA */
- do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/1);
- redraw = 1;
- break;
- case 3: /* Edit position */
- do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/0);
- redraw = 1;
- break;
- case 4: /* Number of sectors */
- c = prompt_sector_count();
- if (c >= 1 && c <= 256) {
- drive_rw_test_nfo.read_sectors = c;
- redraw = 1;
- }
- break;
- case 5: /* Multiple mode sector count */
- c = prompt_sector_count();
- if (c >= 0 && c <= 255) {
- do_ide_set_multiple_mode(ide,which,c);
- {
- uint16_t info[256];
-
- do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
- drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
- }
- redraw = 1;
- }
- break;
- case 6: /*Read sectors*/
- case 7: /*Read sectors continuously*/
- do_hdd_drive_read_test(ide,which,/*continuous=*/(select==7),&drive_rw_test_nfo);
- redraw = backredraw = 1;
- break;
- case 8: /*Read sectors (Zip ATAPI) */
- case 9: /*Read sectors (Zip ATAPI) continuously*/
-#ifdef ATAPI_ZIP
- do_hdd_drive_read_atapi_test(ide,which,/*continuous=*/(select==9),&drive_rw_test_nfo);
- redraw = backredraw = 1;
-#endif
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- switch (select) {
- case 1: /* Mode */
- do {
- if (drive_rw_test_nfo.mode == 0)
- drive_rw_test_nfo.mode = DRIVE_RW_MODE_MAX-1;
- else
- drive_rw_test_nfo.mode--;
- } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
- break;
- case 4: /* Number of sectors */
- if (drive_rw_test_nfo.read_sectors > 1)
- drive_rw_test_nfo.read_sectors--;
- break;
- };
-
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- switch (select) {
- case 1: /* Mode */
- do {
- if (++drive_rw_test_nfo.mode >= DRIVE_RW_MODE_MAX)
- drive_rw_test_nfo.mode = 0;
- } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
- break;
- case 4: /* Number of sectors */
- if (drive_rw_test_nfo.read_sectors < 256)
- drive_rw_test_nfo.read_sectors++;
- break;
- };
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
+++ /dev/null
-
-void do_drive_read_test(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "testmumo.h"
-#include "testrdts.h"
-#include "testrdtv.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef READ_VERIFY
-static const char *drive_read_verify_test_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "*mode*", /* 1 */ /* rewritten (CHS, LBA, CHS MULTI, etc) */
- drive_readwrite_test_geo,
- drive_readwrite_test_chs,
- drive_readwrite_test_numsec,
- "Read verify sectors",
- "Read verify sectors continuously"
-};
-
-static void do_hdd_drive_read_verify_test(struct ide_controller *ide,unsigned char which,unsigned char continuous,struct drive_rw_test_info *nfo) {
- unsigned char user_esc = 0;
- struct ide_taskfile *tsk;
- unsigned long tlen_sect;
- unsigned int cleared=0;
- int c;
-
- if (nfo->read_sectors == 0) return;
- if (nfo->multiple_sectors == 0) return;
-
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
-
-again: /* jump point: send execution back here for another sector */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
-
- tlen_sect = nfo->read_sectors;
- /* C/H/S continuous: limit reads to within track, don't cross. we can't assume the drive will do that. */
- if (continuous && (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE)) {
- if ((nfo->sector + tlen_sect) > nfo->num_sector)
- tlen_sect = (nfo->num_sector + 1 - nfo->sector);
- }
-
- if (nfo->mode == DRIVE_RW_MODE_LBA48 || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
- tsk->sector_count = tlen_sect;
- tsk->lba0_3 = nfo->lba & 0xFF;
- tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
- tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
- tsk->lba0_3 |= ((nfo->lba >> 24) & 0xFF) << 8;
- tsk->lba1_4 |= ((nfo->lba >> 32) & 0xFF) << 8;
- tsk->lba2_5 |= ((nfo->lba >> 40) & 0xFF) << 8;
- tsk->head_select = (which << 4) | 0x40;
-
- tsk->command = 0x42; /* READ VERIFY EXT */
- if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE|IDELIB_TASKFILE_LBA48/*set LBA48*/) < 0)
- return;
- }
- else {
- if (tsk->sector_count > 256) return;
- tsk->sector_count = (tlen_sect&0xFF);
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- tsk->chs_sector = nfo->sector;
- tsk->chs_cylinder_low = nfo->cylinder & 0xFF;
- tsk->chs_cylinder_high = (nfo->cylinder >> 8) & 0xFF;
- tsk->head_select = (nfo->head & 0xF) | (which << 4) | 0xA0;
- }
- else if (nfo->mode == DRIVE_RW_MODE_LBA || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE) {
- tsk->lba0_3 = nfo->lba & 0xFF;
- tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
- tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
- tsk->head_select = ((nfo->lba >> 24) & 0xF) | (which << 4) | 0xE0;
- }
-
- tsk->command = 0x40; /* READ VERIFY */
- if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0)
- return;
- }
-
- if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
- if (do_ide_controller_user_wait_irq(ide,1) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- /* ---- draw contents on the screen ---- */
- vga_write_color(0x0E);
- if (!cleared) {
- vga_clear();
- cleared = 1;
- }
-
- vga_moveto(0,0);
- vga_write("Sector verification:\n");
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- sprintf(tmp,"CHS %u/%u/%u ",nfo->cylinder,nfo->head,nfo->sector); vga_write(tmp);
- }
- else {
- sprintf(tmp,"%llu-%llu",nfo->lba,nfo->lba+(unsigned long long)tlen_sect-1ULL); vga_write(tmp);
- }
-
- if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
- vga_write_color(0x0A);
- vga_write(" PASSED\n");
- }
- else {
- vga_write_color(0x0C);
- vga_write(" FAILED\n");
- }
-
- if (continuous && !user_esc) {
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
- }
- else {
- c = 0;
- }
- }
- else {
- if ((c=wait_for_enter_or_escape()) == 27)
- return; /* allow user to exit early by hitting ESC */
- }
-
- if (c != 27 && !user_esc) {
- /* if the user hit ENTER, then read another sector and display that too */
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- nfo->sector += (unsigned long long)tlen_sect;
- while (nfo->sector > nfo->num_sector) {
- nfo->sector -= nfo->num_sector;
- nfo->head++;
- }
- while (nfo->head >= nfo->num_head) {
- nfo->head -= nfo->num_head;
- nfo->cylinder++;
- }
-
- if (nfo->cylinder >= 16384) {
- nfo->cylinder = 16383;
- nfo->sector = nfo->num_sector;
- nfo->head = nfo->num_head - 1;
- }
-
- nfo->lba = (unsigned long long)nfo->cylinder * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head;
- nfo->lba += (unsigned long long)nfo->head * (unsigned long long)nfo->num_sector;
- nfo->lba += (unsigned long long)nfo->sector - 1ULL;
- }
- else {
- nfo->lba += (unsigned long long)tlen_sect;
-
- nfo->sector = (int)(nfo->lba % (unsigned long long)nfo->num_sector) + 1;
- nfo->head = (int)((nfo->lba / (unsigned long long)nfo->num_sector) % (unsigned long long)nfo->num_head);
- if (nfo->lba >= (16384ULL * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head)) {
- nfo->cylinder = 16383;
- nfo->sector = nfo->num_sector;
- nfo->head = nfo->num_head - 1;
- }
- else {
- nfo->cylinder = (int)((nfo->lba / (unsigned long long)nfo->num_sector) / (unsigned long long)nfo->num_head);
- }
- }
-
- goto again;
- }
-}
-#endif
-
-#ifdef READ_VERIFY
-void do_drive_read_verify_test(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_read_verify_test_menustrings);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE r/w tests ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
-
- sprintf(tmp," lba=%u lba48=%u multiple=%u",
- drive_rw_test_nfo.can_do_lba?1:0,
- drive_rw_test_nfo.can_do_lba48?1:0,
- drive_rw_test_nfo.can_do_multiple?1:0);
- vga_write(tmp);
-
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- drive_read_verify_test_menustrings[1] = drive_readwrite_test_modes[drive_rw_test_nfo.mode];
-
- sprintf(drive_readwrite_test_geo,"Geometry: C/H/S %u/%u/%u LBA %llu",
- drive_rw_test_nfo.num_cylinder,
- drive_rw_test_nfo.num_head,
- drive_rw_test_nfo.num_sector,
- drive_rw_test_nfo.max_lba);
-
- sprintf(drive_readwrite_test_chs,"Position: C/H/S %u/%u/%u LBA %llu",
- drive_rw_test_nfo.cylinder,
- drive_rw_test_nfo.head,
- drive_rw_test_nfo.sector,
- drive_rw_test_nfo.lba);
-
- sprintf(drive_readwrite_test_numsec,"Number of sectors per read: %u",
- drive_rw_test_nfo.read_sectors);
-
- sprintf(drive_readwrite_test_mult,"Multiple mode: %u sectors (max=%u)",
- drive_rw_test_nfo.multiple_sectors,
- drive_rw_test_nfo.max_multiple_sectors);
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE controller main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /* Mode */
- do_drive_readwrite_test_choose_mode(ide,which,&drive_rw_test_nfo);
- redraw = backredraw = 1;
- break;
- case 2: /* Edit geometry/max LBA */
- do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/1);
- redraw = 1;
- break;
- case 3: /* Edit position */
- do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/0);
- redraw = 1;
- break;
- case 4: /* Number of sectors */
- c = prompt_sector_count();
- if (c >= 1 && c <= 256) {
- drive_rw_test_nfo.read_sectors = c;
- redraw = 1;
- }
- break;
- case 5: /*Read sectors*/
- case 6: /*Read sectors continuously*/
- do_hdd_drive_read_verify_test(ide,which,/*continuous=*/(select==6),&drive_rw_test_nfo);
- redraw = backredraw = 1;
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- switch (select) {
- case 1: /* Mode */
- do {
- if (drive_rw_test_nfo.mode == 0)
- drive_rw_test_nfo.mode = DRIVE_RW_MODE_MAX-1;
- else
- drive_rw_test_nfo.mode--;
- } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
- break;
- case 4: /* Number of sectors */
- if (drive_rw_test_nfo.read_sectors > 1)
- drive_rw_test_nfo.read_sectors--;
- break;
- };
-
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- switch (select) {
- case 1: /* Mode */
- do {
- if (++drive_rw_test_nfo.mode >= DRIVE_RW_MODE_MAX)
- drive_rw_test_nfo.mode = 0;
- } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
- break;
- case 4: /* Number of sectors */
- if (drive_rw_test_nfo.read_sectors < 256)
- drive_rw_test_nfo.read_sectors++;
- break;
- };
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-#endif /*READ_VERIFY*/
-
+++ /dev/null
-
-void do_drive_read_verify_test(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "testmumo.h"
-#include "testrdts.h"
-#include "testrdtv.h"
-#include "testrdws.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-const char *drive_readwrite_test_modes[] = {
- "Mode: C/H/S",
- "Mode: C/H/S MULTIPLE",
- "Mode: LBA",
- "Mode: LBA MULTIPLE",
- "Mode: LBA48",
- "Mode: LBA48 MULTIPLE"
-};
-
-struct drive_rw_test_info drive_rw_test_nfo;
-
-char drive_readwrite_test_geo[128];
-char drive_readwrite_test_chs[128];
-char drive_readwrite_test_numsec[128];
-char drive_readwrite_test_mult[128];
-
-int drive_rw_test_mode_supported(struct drive_rw_test_info *nfo) {
- if (!drive_rw_test_nfo.can_do_multiple &&
- (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE ||
- nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE ||
- nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE))
- return 0;
-
- if (!drive_rw_test_nfo.can_do_lba &&
- (nfo->mode == DRIVE_RW_MODE_LBA ||
- nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE ||
- nfo->mode == DRIVE_RW_MODE_LBA48 ||
- nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE))
- return 0;
-
- if (!drive_rw_test_nfo.can_do_lba48 &&
- (nfo->mode == DRIVE_RW_MODE_LBA48 ||
- nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE))
- return 0;
-
- return 1;
-}
-
-void do_drive_readwrite_edit_chslba(struct ide_controller *ide,unsigned char which,struct drive_rw_test_info *nfo,unsigned char editgeo) {
- uint64_t lba,tmp;
- int cyl,head,sect;
- struct vga_msg_box box;
- unsigned char redraw=1;
- unsigned char ok=1;
- char temp_str[64];
- int select=0;
- int c,i=0;
-
- if (editgeo) {
- cyl = nfo->num_cylinder;
- sect = nfo->num_sector;
- head = nfo->num_head;
- lba = nfo->max_lba;
- }
- else {
- cyl = nfo->cylinder;
- sect = nfo->sector;
- head = nfo->head;
- lba = nfo->lba;
- }
-
- vga_msg_box_create(&box,editgeo ?
- "Edit disk geometry: " :
- "Edit position: ",
- 2+4,0);
- while (1) {
- char recalc = 0;
- char rekey = 0;
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(box.x+2,box.y+2+1 + 0);
- vga_write_color(0x1E);
- vga_write("Cylinder: ");
- vga_write_color(select == 0 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",cyl);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 1);
- vga_write_color(0x1E);
- vga_write("Head: ");
- vga_write_color(select == 1 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",head);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 2);
- vga_write_color(0x1E);
- vga_write("Sector: ");
- vga_write_color(select == 2 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%u",sect);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
-
- vga_moveto(box.x+2,box.y+2+1 + 3);
- vga_write_color(0x1E);
- vga_write("LBA: ");
- vga_write_color(select == 3 ? 0x70 : 0x1E);
- i=sprintf(temp_str,"%llu",lba);
- while (i < (box.w-4-11)) temp_str[i++] = ' ';
- temp_str[i] = 0;
- vga_write(temp_str);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
-nextkey: if (c == 27) {
- ok = 0;
- break;
- }
- else if (c == 13) {
- ok = 1;
- break;
- }
- else if (c == 0x4800) {
- if (--select < 0) select = 3;
- redraw = 1;
- }
- else if (c == 0x5000 || c == 9/*tab*/) {
- if (++select > 3) select = 0;
- redraw = 1;
- }
-
- else if (c == 0x4B00) { /* left */
- switch (select) {
- case 0:
- if (cyl == 0) cyl = editgeo ? 16383 : (nfo->num_cylinder - 1);
- else cyl--;
- break;
- case 1:
- if (head == 0) head = editgeo ? 16 : (nfo->num_head - 1);
- else head--;
- break;
- case 2:
- if (sect <= 1) sect = editgeo ? 256 : nfo->num_sector;
- else sect--;
- break;
- case 3:
- if (lba > 0ULL) lba--;
- break;
- };
-
- recalc = 1;
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- switch (select) {
- case 0:
- if ((++cyl) >= (editgeo ? 16384 : nfo->num_cylinder)) cyl = 0;
- break;
- case 1:
- if ((++head) >= (editgeo ? 17 : nfo->num_head)) head = 0;
- break;
- case 2:
- if ((++sect) >= (editgeo ? 257 : (nfo->num_sector+1))) sect = 1;
- break;
- case 3:
- lba++;
- break;
- };
-
- recalc = 1;
- redraw = 1;
- }
-
- else if (c == 8 || isdigit(c)) {
- unsigned int sy = box.y+2+1 + select;
- unsigned int sx = box.x+2+11;
-
- switch (select) {
- case 0: sprintf(temp_str,"%u",cyl); break;
- case 1: sprintf(temp_str,"%u",head); break;
- case 2: sprintf(temp_str,"%u",sect); break;
- case 3: sprintf(temp_str,"%llu",lba); break;
- }
-
- if (c == 8) {
- i = strlen(temp_str) - 1;
- if (i < 0) i = 0;
- temp_str[i] = 0;
- }
- else {
- i = strlen(temp_str);
- if (i == 1 && temp_str[0] == '0') i--;
- if ((i+2) < sizeof(temp_str)) {
- temp_str[i++] = (char)c;
- temp_str[i] = 0;
- }
- }
-
- redraw = 1;
- while (1) {
- if (redraw) {
- redraw = 0;
- vga_moveto(sx,sy);
- vga_write_color(0x70);
- vga_write(temp_str);
- while (vga_pos_x < (box.x+box.w-4) && vga_pos_x != 0) vga_writec(' ');
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 8) {
- if (i > 0) {
- temp_str[--i] = 0;
- redraw = 1;
- }
- }
- else if (isdigit(c)) {
- if ((i+2) < sizeof(temp_str)) {
- temp_str[i++] = (char)c;
- temp_str[i] = 0;
- redraw = 1;
- }
- }
- else {
- break;
- }
- }
-
- switch (select) {
- case 0: tmp=strtoull(temp_str,NULL,0); cyl=(tmp > 16383ULL ? 16383ULL : tmp); break;
- case 1: tmp=strtoull(temp_str,NULL,0); head=(tmp > 16ULL ? 16ULL : tmp); break;
- case 2: tmp=strtoull(temp_str,NULL,0); sect=(tmp > 256ULL ? 256ULL : tmp); break;
- case 3: lba=strtoull(temp_str,NULL,0); break;
- }
-
- rekey = 1;
- recalc = 1;
- }
-
- if (recalc) {
- recalc = 0;
- if (sect == 0) sect = 1;
- if (cyl > 16383) cyl = 16383;
-
- if (editgeo) {
- if (cyl < 1) cyl = 1;
- if (head < 1) head = 1;
- if (head > 16) head = 16;
- if (sect > 256) sect = 256;
-
- if (select == 3) {
- if (lba >= (16383ULL * 16ULL * 63ULL)) {
- sect = 63;
- head = 16;
- cyl = 16383;
- }
- else {
- cyl = (int)(lba / (unsigned long long)sect / (unsigned long long)head);
- if (cyl < 0) cyl = 1;
- if (cyl > 16383) cyl = 16383;
- }
- }
- else if (cyl < 16383) {
- lba = (unsigned long long)cyl * (unsigned long long)head * (unsigned long long)sect;
- }
- }
- else {
- if (cyl < 0) cyl = 0;
- if (head < 0) head = 0;
- if (head > 15) head = 15;
- if (sect > 255) sect = 255;
-
- if (select == 3) {
- sect = (int)(lba % (unsigned long long)nfo->num_sector) + 1;
- head = (int)((lba / (unsigned long long)nfo->num_sector) % (unsigned long long)nfo->num_head);
- if (lba >= (16384ULL * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head)) {
- cyl = 16383;
- sect = nfo->num_sector;
- head = nfo->num_head - 1;
- }
- else {
- cyl = (int)((lba / (unsigned long long)nfo->num_sector) / (unsigned long long)nfo->num_head);
- }
- }
- else {
- lba = (unsigned long long)cyl * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head;
- lba += (unsigned long long)head * (unsigned long long)nfo->num_sector;
- lba += (unsigned long long)sect - 1ULL;
- }
- }
-
- redraw = 1;
- }
-
- if (rekey) {
- rekey = 0;
- goto nextkey;
- }
- }
- vga_msg_box_destroy(&box);
-
- if (ok) {
- if (editgeo) {
- nfo->num_cylinder = cyl;
- nfo->num_sector = sect;
- nfo->num_head = head;
- nfo->max_lba = lba;
- }
- else {
- nfo->cylinder = cyl;
- nfo->sector = sect;
- nfo->head = head;
- nfo->lba = lba;
- }
- }
-}
-
-void do_drive_readwrite_test_choose_mode(struct ide_controller *ide,unsigned char which,struct drive_rw_test_info *nfo) {
- int select=drive_rw_test_nfo.mode;
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_readwrite_test_modes);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE r/w test mode ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
-
- sprintf(tmp," lba=%u lba48=%u multiple=%u",
- drive_rw_test_nfo.can_do_lba?1:0,
- drive_rw_test_nfo.can_do_lba48?1:0,
- drive_rw_test_nfo.can_do_multiple?1:0);
- vga_write(tmp);
-
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- struct vga_msg_box vgabox;
-
- if (!drive_rw_test_nfo.can_do_multiple &&
- (select == DRIVE_RW_MODE_CHSMULTIPLE ||
- select == DRIVE_RW_MODE_LBAMULTIPLE ||
- select == DRIVE_RW_MODE_LBA48_MULTIPLE)) {
-
- vga_msg_box_create(&vgabox,
- "The IDE device doesn't seem to support SET MULTIPLE/READ MULTIPLE.\n"
- "Are you sure you want to choose this mode?\n"
- "\n"
- "Hit ENTER to proceed, ESC to cancel"
- ,0,0);
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
- vga_msg_box_destroy(&vgabox);
- if (c == 27) continue;
- }
-
- if (!drive_rw_test_nfo.can_do_lba &&
- (select == DRIVE_RW_MODE_LBA ||
- select == DRIVE_RW_MODE_LBAMULTIPLE ||
- select == DRIVE_RW_MODE_LBA48 ||
- select == DRIVE_RW_MODE_LBA48_MULTIPLE)) {
-
- vga_msg_box_create(&vgabox,
- "The IDE device doesn't seem to support LBA mode.\n"
- "Are you sure you want to choose this mode?\n"
- "\n"
- "Hit ENTER to proceed, ESC to cancel"
- ,0,0);
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
- vga_msg_box_destroy(&vgabox);
- if (c == 27) continue;
- }
-
- if (!drive_rw_test_nfo.can_do_lba48 &&
- (select == DRIVE_RW_MODE_LBA48 ||
- select == DRIVE_RW_MODE_LBA48_MULTIPLE)) {
-
- vga_msg_box_create(&vgabox,
- "The IDE device doesn't seem to support 48-bit LBA.\n"
- "Are you sure you want to choose this mode?\n"
- "\n"
- "Hit ENTER to proceed, ESC to cancel"
- ,0,0);
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
- vga_msg_box_destroy(&vgabox);
- if (c == 27) continue;
- }
-
- if (select >= 0)
- drive_rw_test_nfo.mode = select;
-
- break;
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-/*-----------------------------------------------------------------*/
-
-const char *drive_readwrite_tests_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "Reading tests >>",
- "Writing tests >>",
- "Read verify tests"
-};
-
-void do_drive_readwrite_tests(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* get geometry and max sector count *NOW* then the user can tweak them later */
- memset(&drive_rw_test_nfo,0,sizeof(drive_rw_test_nfo));
- {
- uint16_t info[256];
-
- c = do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
- if (c < 0) return;
-
- drive_rw_test_nfo.can_do_lba = (info[49] & 0x200) ? 1 : 0;
- drive_rw_test_nfo.can_do_multiple = ((info[47] & 0xFF) != 0) ? 1 : 0;
- drive_rw_test_nfo.can_do_lba48 = drive_rw_test_nfo.can_do_lba && ((info[83] & 0x400) ? 1 : 0);
-
- /* NTS: Never mind the thousands of OSes out there still using these fields, ATA-8 marks them "obsolete".
- * Thanks. You guys realize this is the same logic behind the infuriating number of APIs in Windows
- * that are "obsolete" yet everything relies on them?
- *
- * This is why you keep OLDER copies of standards around, guys! */
- drive_rw_test_nfo.num_cylinder = info[54]; /* number of current logical cylinders */
- drive_rw_test_nfo.num_head = info[55]; /* number of current logical heads */
- drive_rw_test_nfo.num_sector = info[56]; /* number of current logical sectors */
- if (drive_rw_test_nfo.num_cylinder == 0 && drive_rw_test_nfo.num_head == 0 && drive_rw_test_nfo.num_sector == 0) {
- drive_rw_test_nfo.num_cylinder = info[1]; /* number of logical cylinders */
- drive_rw_test_nfo.num_head = info[3]; /* number of logical heads */
- drive_rw_test_nfo.num_sector = info[6]; /* number of logical sectors */
- }
-
- if (drive_rw_test_nfo.can_do_lba48)
- drive_rw_test_nfo.max_lba = ((uint64_t)info[103] << 48ULL) + ((uint64_t)info[102] << 32ULL) +
- ((uint64_t)info[101] << 16ULL) + ((uint64_t)info[100]);
- if (drive_rw_test_nfo.max_lba == 0)
- drive_rw_test_nfo.max_lba = ((uint64_t)info[61] << 16ULL) + ((uint64_t)info[60]);
- if (drive_rw_test_nfo.max_lba == 0)
- drive_rw_test_nfo.max_lba = ((uint64_t)info[58] << 16ULL) + ((uint64_t)info[57]);
-
- drive_rw_test_nfo.sector = 1;
- drive_rw_test_nfo.read_sectors = 1;
- drive_rw_test_nfo.mode = DRIVE_RW_MODE_CHS;
- if (drive_rw_test_nfo.can_do_multiple && (info[59]&0x100))
- drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
- if (drive_rw_test_nfo.can_do_multiple && (info[47]&0xFF) != 0)
- drive_rw_test_nfo.max_multiple_sectors = info[47]&0xFF;
- }
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_readwrite_tests_menustrings);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller read/write tests ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE controller main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /* Read tests */
- do_drive_read_test(ide,which);
- redraw = backredraw = 1;
- break;
- case 2: /* Write tests */
- do_drive_write_test(ide,which);
- redraw = backredraw = 1;
- break;
- case 3: /* Read verify tests */
-#ifdef READ_VERIFY
- do_drive_read_verify_test(ide,which);
- redraw = backredraw = 1;
-#endif
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
+++ /dev/null
-
-enum {
- DRIVE_RW_MODE_CHS=0,
- DRIVE_RW_MODE_CHSMULTIPLE,
- DRIVE_RW_MODE_LBA,
- DRIVE_RW_MODE_LBAMULTIPLE,
- DRIVE_RW_MODE_LBA48,
- DRIVE_RW_MODE_LBA48_MULTIPLE,
-
- DRIVE_RW_MODE_MAX
-};
-
-struct drive_rw_test_info {
- unsigned short int num_cylinder; /* likely 0-16383 */
- unsigned short int num_head,num_sector; /* likely 0-15 and 0-63 */
- unsigned short int cylinder;
- unsigned short int head,sector;
- unsigned short int multiple_sectors; /* multiple mode sector count */
- unsigned short int max_multiple_sectors;
- unsigned short int read_sectors; /* how many to read per command */
- uint64_t max_lba;
- uint64_t lba;
- unsigned char mode; /* DRIVE_RW_MODE_* */
- unsigned int can_do_lba:1;
- unsigned int can_do_lba48:1;
- unsigned int can_do_multiple:1;
-};
-
-extern const char *drive_readwrite_test_modes[DRIVE_RW_MODE_MAX];
-
-extern struct drive_rw_test_info drive_rw_test_nfo;
-
-extern char drive_readwrite_test_geo[128];
-extern char drive_readwrite_test_chs[128];
-extern char drive_readwrite_test_numsec[128];
-extern char drive_readwrite_test_mult[128];
-
-int drive_rw_test_mode_supported(struct drive_rw_test_info *nfo);
-void do_drive_readwrite_edit_chslba(struct ide_controller *ide,unsigned char which,struct drive_rw_test_info *nfo,unsigned char editgeo);
-void do_drive_readwrite_test_choose_mode(struct ide_controller *ide,unsigned char which,struct drive_rw_test_info *nfo);
-void do_drive_readwrite_tests(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "testcdrm.h"
-#include "testmumo.h"
-#include "testrdts.h"
-#include "testrdws.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-static unsigned char drive_write_warning = 1;
-
-static const char *drive_write_test_menustrings[] = {
- "Show IDE register taskfile", /* 0 */
- "*mode*", /* 1 */ /* rewritten (CHS, LBA, CHS MULTI, etc) */
- drive_readwrite_test_geo,
- drive_readwrite_test_chs,
- drive_readwrite_test_numsec,
- drive_readwrite_test_mult,
- "Write sectors",
- "Write sectors continuously"
-};
-
-static void do_hdd_drive_write_test(struct ide_controller *ide,unsigned char which,unsigned char continuous,struct drive_rw_test_info *nfo) {
- unsigned char user_esc = 0;
- struct vga_msg_box vgabox;
- struct ide_taskfile *tsk;
- unsigned long tlen_sect;
- unsigned int cleared=0;
- unsigned long tlen;
- unsigned int i;
- int c;
-
- if (nfo->read_sectors == 0) return;
-
- /* multiple mode: make sure the multiple sector count doesn't exceed our buffer size.
- * if it does, try to set multiple count to lesser value. */
- if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
- if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL) && nfo->multiple_sectors > 1) {
- /* even though most IDE devices really only support power-of-2 sizes, we do a scan downward anyway */
- c = ((unsigned long)sizeof(cdrom_sector) / 512UL);
- do {
- if (c <= 1) break;
- do_ide_set_multiple_mode(ide,which,c);
- {
- uint16_t info[256];
-
- do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
- drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
- }
-
- if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL))
- c--;
- else
- break;
- } while (1);
- }
-
- if (nfo->multiple_sectors > ((unsigned long)sizeof(cdrom_sector) / 512UL))
- return;
- if (nfo->multiple_sectors == 0)
- return;
- }
-
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
-
-again: /* jump point: send execution back here for another sector */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
- idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
-
- tlen_sect = nfo->read_sectors;
- if (tlen_sect > ((unsigned long)sizeof(cdrom_sector) / 512UL))
- tlen_sect = ((unsigned long)sizeof(cdrom_sector) / 512UL);
-
- /* C/H/S continuous: limit reads to within track, don't cross. we can't assume the drive will do that. */
- if (continuous && (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE)) {
- if ((nfo->sector + tlen_sect) > nfo->num_sector)
- tlen_sect = (nfo->num_sector + 1 - nfo->sector);
- }
-
- tlen = tlen_sect * 512UL;
-
- if (nfo->mode == DRIVE_RW_MODE_LBA48 || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
- tsk->sector_count = tlen_sect;
- tsk->lba0_3 = nfo->lba & 0xFF;
- tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
- tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
- tsk->lba0_3 |= ((nfo->lba >> 24) & 0xFF) << 8;
- tsk->lba1_4 |= ((nfo->lba >> 32) & 0xFF) << 8;
- tsk->lba2_5 |= ((nfo->lba >> 40) & 0xFF) << 8;
- tsk->head_select = (which << 4) | 0x40;
-
- if (nfo->mode == DRIVE_RW_MODE_LBA48)
- tsk->command = 0x34; /* WRITE SECTORS EXT */
- else if (nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE)
- tsk->command = 0x39; /* WRITE MULTIPLE EXT */
-
- if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE|IDELIB_TASKFILE_LBA48/*set LBA48*/) < 0)
- return;
- }
- else {
- if (tsk->sector_count > 256) return;
- tsk->sector_count = (tlen_sect&0xFF);
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- tsk->chs_sector = nfo->sector;
- tsk->chs_cylinder_low = nfo->cylinder & 0xFF;
- tsk->chs_cylinder_high = (nfo->cylinder >> 8) & 0xFF;
- tsk->head_select = (nfo->head & 0xF) | (which << 4) | 0xA0;
- }
- else if (nfo->mode == DRIVE_RW_MODE_LBA || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE) {
- tsk->lba0_3 = nfo->lba & 0xFF;
- tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
- tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
- tsk->head_select = ((nfo->lba >> 24) & 0xF) | (which << 4) | 0xE0;
- }
-
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_LBA)
- tsk->command = 0x30; /* WRITE SECTORS */
- else if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE)
- tsk->command = 0xC5; /* WRITE MULTIPLE */
-
- if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0)
- return;
- }
-
- /* wait for drive ready. drive will NOT fire an IRQ until the write is done. */
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
- return;
-
- if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
- unsigned int ret_len = 0,drq_len;
-
- /* make test data */
- for (i=0;i < tlen;i++) cdrom_sector[i] = i + (i >> 8);
-
- while (ret_len < tlen) {
- if (idelib_controller_is_error(ide)) {
- vga_msg_box_create(&vgabox,"Error",0,0);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- break;
- }
-
- if (do_ide_controller_user_wait_drive_drq(ide) < 0) {
- user_esc = 1;
- break;
- }
-
- if (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE ||
- nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
- drq_len = nfo->multiple_sectors * 512;
- if ((ret_len+drq_len) > tlen) drq_len = tlen - ret_len;
- }
- else
- drq_len = 512;
-
- /* OK. write it out and acknowledge */
- idelib_write_pio_general(cdrom_sector+ret_len,drq_len,ide,IDELIB_PIO_WIDTH_DEFAULT);
- ret_len += drq_len;
-
- /* you're supposed to wait for IRQ after writing the sector */
- if (ide->flags.io_irq_enable) {
- if (do_ide_controller_user_wait_irq(ide,1) < 0) {
- user_esc = 1;
- break;
- }
- idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
- idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
- }
-
- if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0) {
- user_esc = 1;
- break;
- }
- }
-
- /* ---- draw contents on the screen ---- */
- vga_write_color(0x0E);
- if (!cleared) {
- vga_clear();
- cleared = 1;
- }
-
- vga_moveto(0,0);
- vga_write("Sector writing:\n");
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- sprintf(tmp,"CHS %u/%u/%u ",nfo->cylinder,nfo->head,nfo->sector); vga_write(tmp);
- }
- else {
- sprintf(tmp,"%llu-%llu",nfo->lba,nfo->lba+(unsigned long long)tlen_sect-1ULL); vga_write(tmp);
- }
-
- if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
- vga_write_color(0x0A);
- vga_write(" PASSED\n");
- }
- else {
- vga_write_color(0x0C);
- vga_write(" FAILED\n");
- }
-
- if (continuous && !user_esc) {
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
- }
- else {
- c = 0;
- }
- }
- else {
- if ((c=wait_for_enter_or_escape()) == 27)
- return; /* allow user to exit early by hitting ESC */
- }
-
- if (c != 27 && !user_esc) {
- /* if the user hit ENTER, then read another sector and display that too */
- if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
- nfo->sector += (unsigned long long)tlen_sect;
- while (nfo->sector > nfo->num_sector) {
- nfo->sector -= nfo->num_sector;
- nfo->head++;
- }
- while (nfo->head >= nfo->num_head) {
- nfo->head -= nfo->num_head;
- nfo->cylinder++;
- }
-
- if (nfo->cylinder >= 16384) {
- nfo->cylinder = 16383;
- nfo->sector = nfo->num_sector;
- nfo->head = nfo->num_head - 1;
- }
-
- nfo->lba = (unsigned long long)nfo->cylinder * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head;
- nfo->lba += (unsigned long long)nfo->head * (unsigned long long)nfo->num_sector;
- nfo->lba += (unsigned long long)nfo->sector - 1ULL;
- }
- else {
- nfo->lba += (unsigned long long)tlen_sect;
-
- nfo->sector = (int)(nfo->lba % (unsigned long long)nfo->num_sector) + 1;
- nfo->head = (int)((nfo->lba / (unsigned long long)nfo->num_sector) % (unsigned long long)nfo->num_head);
- if (nfo->lba >= (16384ULL * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head)) {
- nfo->cylinder = 16383;
- nfo->sector = nfo->num_sector;
- nfo->head = nfo->num_head - 1;
- }
- else {
- nfo->cylinder = (int)((nfo->lba / (unsigned long long)nfo->num_sector) / (unsigned long long)nfo->num_head);
- }
- }
-
- goto again;
- }
- }
- else {
- common_ide_success_or_error_vga_msg_box(ide,&vgabox);
- wait_for_enter_or_escape();
- vga_msg_box_destroy(&vgabox);
- }
-}
-
-void do_drive_write_test(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- if (drive_write_warning) {
- struct vga_msg_box box;
-
- vga_msg_box_create(&box,
- "WARNING: This test is destructive. It overwrites the data on the disk.\n"
- " If you value the data on your hard drive DO NOT RUN THIS TEST.\n"
- "\n"
- "Hit ESC to cancel, ENTER to continue"
- ,0,0);
- c = wait_for_enter_or_escape();
- vga_msg_box_destroy(&box);
- if (c == 27) return;
-
- vga_msg_box_create(&box,
- "WARNING: Are you sure? The contents of the hard disk will be overwritten\n"
- " in the process of carrying out this test!\n"
- "\n"
- "Hit ESC to cancel, ENTER to continue"
- ,0,0);
- c = wait_for_enter_or_escape();
- vga_msg_box_destroy(&box);
- if (c == 27) return;
-
- vga_msg_box_create(&box,
- "FINAL WARNING: This test will overwrite the sectors on the disk with\n"
- " test data. The test is not undoable. ARE YOU SURE?\n"
- "\n"
- "If you confirm, this warning will not show again until the test program\n"
- "is restarted.\n"
- "\n"
- "Hit ESC to cancel, ENTER to continue"
- ,0,0);
- c = wait_for_enter_or_escape();
- vga_msg_box_destroy(&box);
- if (c == 27) return;
-
- /* if you say so! */
- drive_write_warning = 0;
- }
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_write_test_menustrings);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE r/w tests ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
-
- sprintf(tmp," lba=%u lba48=%u multiple=%u",
- drive_rw_test_nfo.can_do_lba?1:0,
- drive_rw_test_nfo.can_do_lba48?1:0,
- drive_rw_test_nfo.can_do_multiple?1:0);
- vga_write(tmp);
-
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- drive_write_test_menustrings[1] = drive_readwrite_test_modes[drive_rw_test_nfo.mode];
-
- sprintf(drive_readwrite_test_geo,"Geometry: C/H/S %u/%u/%u LBA %llu",
- drive_rw_test_nfo.num_cylinder,
- drive_rw_test_nfo.num_head,
- drive_rw_test_nfo.num_sector,
- drive_rw_test_nfo.max_lba);
-
- sprintf(drive_readwrite_test_chs,"Position: C/H/S %u/%u/%u LBA %llu",
- drive_rw_test_nfo.cylinder,
- drive_rw_test_nfo.head,
- drive_rw_test_nfo.sector,
- drive_rw_test_nfo.lba);
-
- sprintf(drive_readwrite_test_numsec,"Number of sectors per read: %u",
- drive_rw_test_nfo.read_sectors);
-
- sprintf(drive_readwrite_test_mult,"Multiple mode: %u sectors (max=%u)",
- drive_rw_test_nfo.multiple_sectors,
- drive_rw_test_nfo.max_multiple_sectors);
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE controller main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* show IDE register taskfile */
- do_common_show_ide_taskfile(ide,which);
- redraw = backredraw = 1;
- break;
- case 1: /* Mode */
- do_drive_readwrite_test_choose_mode(ide,which,&drive_rw_test_nfo);
- redraw = backredraw = 1;
- break;
- case 2: /* Edit geometry/max LBA */
- do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/1);
- redraw = 1;
- break;
- case 3: /* Edit position */
- do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/0);
- redraw = 1;
- break;
- case 4: /* Number of sectors */
- c = prompt_sector_count();
- if (c >= 1 && c <= 256) {
- drive_rw_test_nfo.read_sectors = c;
- redraw = 1;
- }
- break;
- case 5: /* Multiple mode sector count */
- c = prompt_sector_count();
- if (c >= 0 && c <= 255) {
- do_ide_set_multiple_mode(ide,which,c);
- {
- uint16_t info[256];
-
- do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
- drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
- }
- redraw = 1;
- }
- break;
- case 6: /*Read sectors*/
- case 7: /*Read sectors continuously*/
- do_hdd_drive_write_test(ide,which,/*continuous=*/(select==7),&drive_rw_test_nfo);
- redraw = backredraw = 1;
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- switch (select) {
- case 1: /* Mode */
- do {
- if (drive_rw_test_nfo.mode == 0)
- drive_rw_test_nfo.mode = DRIVE_RW_MODE_MAX-1;
- else
- drive_rw_test_nfo.mode--;
- } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
- break;
- case 4: /* Number of sectors */
- if (drive_rw_test_nfo.read_sectors > 1)
- drive_rw_test_nfo.read_sectors--;
- break;
- };
-
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- switch (select) {
- case 1: /* Mode */
- do {
- if (++drive_rw_test_nfo.mode >= DRIVE_RW_MODE_MAX)
- drive_rw_test_nfo.mode = 0;
- } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
- break;
- case 4: /* Number of sectors */
- if (drive_rw_test_nfo.read_sectors < 256)
- drive_rw_test_nfo.read_sectors++;
- break;
- };
-
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
+++ /dev/null
-
-void do_drive_write_test(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-#include "testmbox.h"
-#include "testcmui.h"
-#include "testbusy.h"
-#include "testpiot.h"
-#include "testrvfy.h"
-#include "testrdwr.h"
-#include "testidnt.h"
-#include "testcdej.h"
-#include "testpiom.h"
-#include "testtadj.h"
-#include "test.h"
-
-#include "testnop.h"
-#include "testpwr.h"
-
-#ifdef TWEAK_MENU
-
-static const char *drive_tweaks_and_adjustments_strings[] = {
- "" /* 0 */ /* "Allow 32-bit PIO for ATAPI command" */
-};
-
-void do_drive_tweaks_and_adjustments(struct ide_controller *ide,unsigned char which) {
- struct menuboxbounds mbox;
- char backredraw=1;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int select=-1;
- char redraw=1;
- int c;
-
- /* UI element vars */
- menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
- menuboxbounds_set_item_strings_arraylen(&mbox,drive_tweaks_and_adjustments_strings);
-
- /* most of the commands assume a ready controller. if it's stuck,
- * we'd rather the user have a visual indication that it's stuck that way */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* select the drive we want */
- idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
-
- /* in case the IDE controller is busy for that time */
- c = do_ide_controller_user_wait_busy_controller(ide);
- if (c != 0) return;
-
- /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
- c = do_ide_controller_drive_check_select(ide,which);
- if (c < 0) return;
-
- /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
- do_ide_controller_atapi_device_check_post_host_reset(ide);
-
- /* wait for the drive to indicate readiness */
- /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
- * possibility that the device doesn't exist. This can happen for example if there
- * is a master attached but no slave. */
- c = do_ide_controller_user_wait_drive_ready(ide);
- if (c < 0) return;
-
- /* for completeness, clear pending IRQ */
- idelib_controller_ack_irq(ide);
-
- while (1) {
- if (backredraw) {
- vga = vga_alpha_ram;
- backredraw = 0;
- redraw = 1;
-
- for (y=0;y < vga_height;y++) {
- for (x=0;x < vga_width;x++) {
- *vga++ = 0x1E00 + 177;
- }
- }
-
- vga_moveto(0,0);
-
- vga_write_color(0x1F);
- vga_write(" IDE controller ");
- sprintf(tmp,"@%X",ide->base_io);
- vga_write(tmp);
- if (ide->alt_io != 0) {
- sprintf(tmp," alt %X",ide->alt_io);
- vga_write(tmp);
- }
- if (ide->irq >= 0) {
- sprintf(tmp," IRQ %d",ide->irq);
- vga_write(tmp);
- }
- vga_write(which ? " Slave" : " Master");
- vga_write(" << Tweaks and adjustments");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
-
- vga_write_color(0xC);
- vga_write("WARNING: This code talks directly to your hard disk controller.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- vga_write_color(0xC);
- vga_write(" If you value the data on your hard drive do not run this program.");
- while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
- }
-
- if (redraw) {
- redraw = 0;
-
- drive_tweaks_and_adjustments_strings[0] =
- ide->pio32_atapi_command ?
- "Allow 32-bit PIO for ATAPI command (ENABLED)" :
- "Allow 32-bit PIO for ATAPI command (DISABLED)";
-
- vga_moveto(mbox.ofsx,mbox.ofsy - 2);
- vga_write_color((select == -1) ? 0x70 : 0x0F);
- vga_write("Back to IDE drive main menu");
- while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
-
- menuboxbound_redraw(&mbox,select);
- }
-
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- break;
- }
- else if (c == 13) {
- if (select == -1)
- break;
-
- switch (select) {
- case 0: /* 16-bit */
- redraw = 1;
- ide->pio32_atapi_command ^= 1;
- break;
- };
- }
- else if (c == 0x4800) {
- if (--select < -1)
- select = mbox.item_max;
-
- redraw = 1;
- }
- else if (c == 0x4B00) { /* left */
- redraw = 1;
- }
- else if (c == 0x4D00) { /* right */
- redraw = 1;
- }
- else if (c == 0x5000) {
- if (++select > mbox.item_max)
- select = -1;
-
- redraw = 1;
- }
- }
-}
-
-#endif /* TWEAK_MENU */
-
+++ /dev/null
-
-void do_drive_tweaks_and_adjustments(struct ide_controller *ide,unsigned char which);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/pci/pci.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/ide/idelib.h>
-
-#include "testutil.h"
-
-unsigned char sanitizechar(unsigned char c) {
- if (c < 32) return '.';
- return c;
-}
-
-int wait_for_enter_or_escape() {
- int c;
-
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
- } while (!(c == 13 || c == 27));
-
- return c;
-}
-
-/* construct ATAPI/SCSI-MMC READ command according to user's choice, either READ(10) or READ(12) */
-void do_construct_atapi_scsi_mmc_read(unsigned char *buf/*must be 12 bytes*/,uint32_t sector,uint32_t tlen_sect,unsigned char read_mode) {
- memset(buf,0,12);
- if (read_mode == 12) {
- /* command: READ(12) */
- buf[0] = 0xA8;
-
- /* fill in the Logical Block Address */
- buf[2] = sector >> 24;
- buf[3] = sector >> 16;
- buf[4] = sector >> 8;
- buf[5] = sector;
-
- buf[6] = tlen_sect >> 24UL;
- buf[7] = tlen_sect >> 16UL;
- buf[8] = tlen_sect >> 8UL;
- buf[9] = tlen_sect;
- }
- else {
- /* command: READ(10) */
- buf[0] = 0x28;
-
- /* fill in the Logical Block Address */
- buf[2] = sector >> 24;
- buf[3] = sector >> 16;
- buf[4] = sector >> 8;
- buf[5] = sector;
-
- buf[7] = tlen_sect >> 8;
- buf[8] = tlen_sect;
- }
-}
-
-/* check for another possible case where 16-bit PIO word is in lower half of 32-bit read, junk in upper */
-int ide_memcmp_every_other_word(unsigned char *pio16,unsigned char *pio32,unsigned int words) {
- while (words > 0) {
- uint16_t a = *((uint16_t*)pio16);
- uint16_t b = (uint16_t)(*((uint32_t*)pio32) & 0xFFFF);
- if (a != b) return (int)(a-b);
- pio16 += 2;
- pio32 += 4;
- words--;
- }
-
- return 0;
-}
-
-/* return 0 if all bytes are 0xFF */
-int ide_memcmp_all_FF(unsigned char *d,unsigned int bytes) {
- while (bytes > 0) {
- if (*d != 0xFF) return 1;
- d++;
- bytes--;
- }
-
- return 0;
-}
-
-/* A warning to people who may write their own IDE code: If a drive
- * has been put to sleep, or put through a host reset, the "drive ready"
- * bit will NEVER come up. If you are naive, your code will loop forever
- * waiting for drive ready. To get drive ready to come up you have to
- * send it a NO-OP command, which it will reply with an error, but it
- * will then signal readiness.
- *
- * Now, in this case the Status register (0x1F7/0x3F6) will always
- * read back 0x00, but 0x00 is also what would be read back if no
- * such device existed. How do we tell the two scenarios apart?
- * Well it turns out that if the device is there, then anything you
- * read/write from ports 0x1F2-0x1F5 will read back the same value.
- * If the IDE device does not exist, then ports 0x1F2-0x1F5 will
- * always return 0x00 (or 0xFF?) no matter what we write.
- *
- * Once we know the device is there, we can then "trick" the device
- * into reporting readiness by issuing ATA NO-OP, which the device
- * will respond to with an error, but more importantly, it will set
- * the Device Ready bit. */
-/* NOTE: The caller must have already gone through the process of writing the
- * head & drive select and waiting for controller readiness. if the
- * caller doesn't do that, this routine will probably end up running through
- * the routine on the wrong IDE device */
-int do_ide_controller_atapi_device_check_post_host_reset(struct ide_controller *ide) {
- idelib_controller_update_status(ide);
- if (idelib_controller_is_busy(ide)) return -1; /* YOU'RE SUPPOSED TO WAIT FOR CONTROLLER NOT-BUSY! */
- if (idelib_controller_is_drive_ready(ide)) return 0; /* Drive indicates readiness, nothing to do */
-
- if ((ide->last_status&0xC1) == 0) { /* <- typical post-reset state. VirtualBox/QEMU never raises Drive Ready bit */
- struct ide_taskfile *tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
-
- /* OK: If I write things to 0x1F2-0x1F5 can I read them back? */
- tsk->sector_count = 0x55;
- tsk->lba0_3 = 0xAA;
- tsk->lba1_4 = 0x3F;
-
- idelib_controller_apply_taskfile(ide,0x1C/*regs 2-4*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear*/);
- tsk->sector_count = tsk->lba0_3 = tsk->lba1_4 = 0; /* DEBUG: just to be sure */
- idelib_controller_update_taskfile(ide,0x1C/*regs 2-4*/,0);
-
- if (tsk->sector_count != 0x55 || tsk->lba0_3 != 0xAA || tsk->lba1_4 != 0x3F)
- return -1; /* Nope. IDE device is not there (also possibly the device is fucked up) */
-
- idelib_controller_update_status(ide);
- }
- if ((ide->last_status&0xC1) == 0) { /* <- if the first test did not trigger drive ready, then whack the command port with ATA NO-OP */
- idelib_controller_write_command(ide,0x00);
- t8254_wait(t8254_us2ticks(100000)); /* <- give it 100ms to respond */
- idelib_controller_update_status(ide);
- }
- if ((ide->last_status&0xC1) == 0) { /* <- if the NO-OP test didn't work, then forget it, I'm out of ideas */
- return -1;
- }
-
- idelib_controller_ack_irq(ide);
- return 0;
-}
-
+++ /dev/null
-
-void do_construct_atapi_scsi_mmc_read(unsigned char *buf/*must be 12 bytes*/,uint32_t sector,uint32_t tlen_sect,unsigned char read_mode);
-int ide_memcmp_every_other_word(unsigned char *pio16,unsigned char *pio32,unsigned int words);
-int do_ide_controller_atapi_device_check_post_host_reset(struct ide_controller *ide);
-int ide_memcmp_all_FF(unsigned char *d,unsigned int bytes);
-unsigned char sanitizechar(unsigned char c);
-int wait_for_enter_or_escape();
-
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NOW_BUILDING = HW_ISAPNP_LIB
-
-C_SOURCE = isapnp.c
-OBJS = $(SUBDIR)$(HPS)isapnp.obj $(SUBDIR)$(HPS)isapnp.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_ISAPNP_LIB): $(OBJS)
- wlib -q -b -c $(HW_ISAPNP_LIB) -+$(SUBDIR)$(HPS)isapnp.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_ISAPNP_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(SUBDIR)$(HPS)test.obj $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_ISAPNP_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_CPU_LINK_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_ISAPNP_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <dos/dos.h>
-#include <isapnp/isapnp.h>
-
-#include <hw/8254/8254.h> /* 8254 timer */
-
-uint16_t isapnp_read_data = 0;
-uint8_t isapnp_probe_next_csn = 0;
-
-const unsigned char isa_pnp_init_keystring[32] = {
- 0x6A,0xB5,0xDA,0xED,0xF6,0xFB,0x7D,0xBE,
- 0xDF,0x6F,0x37,0x1B,0x0D,0x86,0xC3,0x61,
- 0xB0,0x58,0x2C,0x16,0x8B,0x45,0xA2,0xD1,
- 0xE8,0x74,0x3A,0x9D,0xCE,0xE7,0x73,0x39
-};
-
-const char *isapnp_config_block_str[3] = {
- "Allocated",
- "Possible",
- "Compatible"
-};
-
-const char *isa_pnp_devd_pnp_0x00xx[] = { /* PNP00xx */
- "AT interrupt controller", /* 00 */
- "EISA interrupt controller", /* 01 */
- "MCA interrupt controller", /* 02 */
- "APIC", /* 03 */
- "Cyrix SLiC MP interrupt controller" /* 04 */
-};
-
-const char *isa_pnp_devd_pnp_0x01xx[] = { /* PNP01xx */
- "AT Timer", /* 00 */
- "EISA Timer", /* 01 */
- "MCA Timer" /* 02 */
-};
-
-const char *isa_pnp_devd_pnp_0x02xx[] = { /* PNP02xx */
- "AT DMA Controller", /* 00 */
- "EISA DMA Controller", /* 01 */
- "MCA DMA Controller" /* 02 */
-};
-
-const char *isa_pnp_devd_pnp_0x03xx[] = { /* PNP03xx */
- "IBM PC/XT keyboard controller (83-key)", /* 00 */
- "IBM PC/AT keyboard controller (86-key)", /* 01 */
- "IBM PC/XT keyboard controller (84-key)", /* 02 */
- "IBM Enhanced (101/102-key, PS/2 mouse support)", /* 03 */
- "Olivetti Keyboard (83-key)", /* 04 */
- "Olivetti Keyboard (102-key)", /* 05 */
- "Olivetti Keyboard (86-key)", /* 06 */
- "Microsoft Windows(R) Keyboard", /* 07 */
- "General Input Device Emulation Interface (GIDEI) legacy", /* 08 */
- "Olivetti Keyboard (A101/102 key)", /* 09 */
- "AT&T 302 keyboard", /* 0A */
- "Reserved by Microsoft", /* 0B */
- NULL, /* 0C */
- NULL, /* 0D */
- NULL, /* 0E */
- NULL, /* 0F */
- NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 10-17 */
- NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 18-1F */
- "Japanese 106-key keyboard A01", /* 20 */
- "Japanese 101-key keyboard", /* 21 */
- "Japanese AX keyboard", /* 22 */
- "Japanese 106-key keyboard 002/003", /* 23 */
- "Japanese 106-key keyboard 001", /* 24 */
- "Japanese Toshiba Desktop keyboard", /* 25 */
- "Japanese Toshiba Laptop keyboard", /* 26 */
- "Japanese Toshiba Notebook keyboard", /* 27 */
- NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 28-2F */
- NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 30-37 */
- NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, /* 38-3F */
- "Korean 84-key keyboard", /* 40 */
- "Korean 86-key keyboard", /* 41 */
- "Korean Enhanced keyboard", /* 42 */
- "Korean Enhanced keyboard 101c", /* 43 */
- "Korean Enhanced keyboard 103" /* 44 */
-};
-
-const char *isa_pnp_devd_pnp_0x04xx[] = { /* PNP04xx */
- "Standard LPT printer port", /* 00 */
- "ECP printer port" /* 01 */
-};
-
-const char *isa_pnp_devd_pnp_0x05xx[] = { /* PNP05xx */
- "Standard PC COM port", /* 00 */
- "16550A-compatible COM port", /* 01 */
- "Multiport serial device", /* 02 */
- NULL, /* 03 */
- NULL, /* 04 */
- NULL, /* 05 */
- NULL, /* 06 */
- NULL, /* 07 */
- NULL, /* 08 */
- NULL, /* 09 */
- NULL, /* 0A */
- NULL, /* 0B */
- NULL, /* 0C */
- NULL, /* 0D */
- NULL, /* 0E */
- NULL, /* 0F */
- "Generic IRDA-compatible", /* 10 */
- "Generic IRDA-compatible" /* 11 */
-};
-
-const char *isa_pnp_devd_pnp_0x06xx[] = { /* PNP06xx */
- "Generic ESDI/IDE/ATA controller", /* 00 */
- "Plus Hardcard II", /* 01 */
- "Plus Hardcard IIXL/EZ", /* 02 */
- "Generic IDE, Microsoft Device Bay Specification"/* 03 */
-};
-
-const char *isa_pnp_devd_pnp_0x07xx[] = { /* PNP07xx */
- "PC standard floppy disk controller", /* 00 */
- "Standard floppy, Microsoft Device Bay Specification" /* 01 */
-};
-
-const char *isa_pnp_devd_pnp_0x09xx[] = { /* PNP09xx */
- "VGA compatible", /* 00 */
- "Video Seven VRAM/VRAM II/1024i", /* 01 */
- "8514/A compatible", /* 02 */
- "Trident VGA", /* 03 */
- "Cirrus Logic Laptop VGA", /* 04 */
- "Cirrus Logic VGA", /* 05 */
- "Tseng ET4000", /* 06 */
- "Western Digital VGA", /* 07 */
- "Western Digital Laptop VGA", /* 08 */
- "S3 911/924", /* 09 */
- "ATI Ultra Pro/Plus Mach32", /* 0A */
- "ATI Ultra Mach8", /* 0B */
- "XGA compatible", /* 0C */
- "ATI VGA wonder", /* 0D */
- "Weitek P9000 graphics", /* 0E */
- "Oak VGA", /* 0F */
-
- "Compaq QVision", /* 10 */
- "XGA/2", /* 11 */
- "Tseng W32/W32i/W32p", /* 12 */
- "S3 801/928/964", /* 13 */
- "Cirrus 5429/5434", /* 14 */
- "Compaq advanced VGA", /* 15 */
- "ATI Ultra Pro Turbo Mach64", /* 16 */
- "Microsoft Reserved", /* 17 */
- "Matrox", /* 18 */
- "Compaq QVision 2000", /* 19 */
- "Tseng W128", /* 1A */
- NULL,NULL,NULL,NULL,NULL, /* 1B-1F */
-
- NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, /* 20-27 */
- NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, /* 28-2F */
-
- "Chips & Technologies SVGA", /* 30 */
- "Chips & Technologies accelerator", /* 31 */
- NULL,NULL, NULL,NULL,NULL,NULL, /* 32-37 */
- NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, /* 38-3F */
-
- "NCR 77c22e SVGA", /* 40 */
- "NCR 77c32blt" /* 41 */
-};
-
-const char *isa_pnp_devd_pnp_0x0Cxx[] = { /* PNP0Cxx */
- "Plug & Play BIOS", /* 00 */
- "System board", /* 01 */
- "Motherboard resources", /* 02 */
- "Plug & Play BIOS event interrupt", /* 03 */
- "Math coprocessor", /* 04 */
- "APM BIOS", /* 05 */
- "(early PnP #06)", /* 06 */
- "(early PnP #07)", /* 07 */
- "ACPI system board", /* 08 */
- "ACPI embedded controller", /* 09 */
- "ACPI control method battery", /* 0A */
- "ACPI fan", /* 0B */
- "ACPI power button", /* 0C */
- "ACPI lid", /* 0D */
- "ACPI sleep button", /* 0E */
- "PCI interrupt link", /* 0F */
- "ACPI system indicator", /* 10 */
- "ACPI thermal zone", /* 11 */
- "Device bay controller", /* 12 */
- "Plug & Play BIOS (non-ACPI?)" /* 13 */
-};
-
-const char *isa_pnp_devd_pnp_0x0Axx[] = { /* PNP0Axx */
- "ISA bus", /* 00 */
- "EISA bus", /* 01 */
- "MCA bus", /* 02 */
- "PCI bus", /* 03 */
- "VESA bus", /* 04 */
- "Generic ACPI bus", /* 05 that's a bus? */
- "Generic ACPI extended IO bus" /* 06 */
-};
-
-const char *isa_pnp_devd_pnp_0x0Exx[] = { /* PNP0Exx */
- "Intel 82365-compatible PCMCIA controller", /* 00 */
- "Cirrus Logic CL-PD6720 PCMCIA controller", /* 01 */
- "VLSI VL82C146 PCMCIA controller", /* 02 */
- "Intel 82365-compatible CardBus controller" /* 03 */
-};
-
-const char *isa_pnp_devd_pnp_0x0Fxx[] = { /* PNP0Fxx */
- "Microsoft bus mouse", /* 00 */
- "Microsoft serial", /* 01 */
- "Microsoft InPort", /* 02 */
- "Microsoft PS/2", /* 03 */
- "Mouse systems", /* 04 */
- "Mouse systems 3-button (COM2)", /* 05 */
- "Genius mouse (COM1)", /* 06 */
- "Genius mouse (COM2)", /* 07 */
- "Logitech serial", /* 08 */
- "Microsoft BallPoint serial", /* 09 */
- "Microsoft plug & play", /* 0A */
- "Microsoft plug & play BallPoint", /* 0B */
- "Microsoft compatible serial", /* 0C */
- "Microsoft compatible InPort compatible", /* 0D */
- "Microsoft compatible PS/2", /* 0E */
- "Microsoft compatible serial BallPoint compatible", /* 0F */
- "Texas Instruments QuickPort", /* 10 */
- "Microsoft compatible bus mouse", /* 11 */
- "Logitech PS/2", /* 12 */
- "PS/2 port for PS/2 mice", /* 13 */
- "Microsoft kids mouse", /* 14 */
- "Logitech bus mouse", /* 15 */
- "Logitech swift device", /* 16 */
- "Logitech compatible serial", /* 17 */
- "Logitech compatible bus mouse", /* 18 */
- "Logitech compatible PS/2", /* 19 */
- "Logitech compatible swift", /* 1A */
- "HP Omnibook mouse", /* 1B */
- "Compaq LTE trackball PS/2", /* 1C */
- "Compaq LTE trackball serial", /* 1D */
- "Microsoft kids trackball", /* 1E */
- NULL /* 1F */
-};
-
-const char *isapnp_fml32_miosize_str[4] = {
- "8-bit",
- "16-bit",
- "8/16-bit",
- "32-bit"
-};
-
-const char *isapnp_sdf_priority_strs[3] = {
- "Good",
- "Acceptable",
- "Sub-optimal"
-};
-
-const char *isapnp_dma_speed_str[4] = {
- "Compatible",
- "Type A",
- "Type B",
- "Type F"
-};
-
-const char *isapnp_dma_xfer_preference_str[4] = {
- "8-bit",
- "8/16-bit",
- "16-bit",
- "??"
-};
-
-const char *isapnp_tag_strs[] = {
- /* small tags +0x00 */
- NULL, /* 0x00 */
- "PnP version",
- "Logical device ID", /* 0x02 */
- "Compatible device ID",
- "IRQ", /* 0x04 */
- "DMA",
- "Dependent function start", /* 0x06 */
- "Dependent function end",
- "I/O port", /* 0x08 */
- "Fixed I/O port",
- NULL, /* 0x0A */
- NULL,
- NULL, /* 0x0C */
- NULL,
- "Vendor tag S-0xE", /* 0x0E */
- "End",
- /* large tags +0x10 */
- NULL, /* 0x10 */
- "Memory range",
- "Identifier string (ANSI)", /* 0x12 */
- "Identifier string (Unicode)",
- "Vendor tag L-0x4", /* 0x14 */
- "32-bit memory range",
- "32-bit fixed memory range" /* 0x16 */
-};
-
-uint16_t isa_pnp_bios_offset = 0;
-struct isa_pnp_bios_struct isa_pnp_info;
-unsigned int (__cdecl far *isa_pnp_rm_call)() = NULL;
-
-#if TARGET_MSDOS == 32
-uint16_t isa_pnp_pm_code_seg = 0; /* code segment to call protected mode BIOS if */
-uint16_t isa_pnp_pm_data_seg = 0; /* data segment to call protected mode BIOS if */
-uint8_t isa_pnp_pm_use = 0; /* 1=call protected mode interface 0=call real mode interface */
-uint8_t isa_pnp_pm_win95_mode = 0; /* 1=call protected mode interface with 32-bit stack (Windows 95 style) */
-uint16_t isa_pnp_rm_call_area_code_sel = 0;
-uint16_t isa_pnp_rm_call_area_sel = 0;
-void* isa_pnp_rm_call_area = NULL;
-#endif
-
-int init_isa_pnp_bios() {
-#if TARGET_MSDOS == 32
- isa_pnp_rm_call_area_code_sel = 0;
- isa_pnp_rm_call_area_sel = 0;
- isa_pnp_pm_code_seg = 0;
- isa_pnp_pm_data_seg = 0;
- isa_pnp_pm_use = 0;
-#endif
- return 1;
-}
-
-void free_isa_pnp_bios() {
-#if TARGET_MSDOS == 32
- if (isa_pnp_pm_code_seg != 0)
- dpmi_free_descriptor(isa_pnp_pm_code_seg);
- if (isa_pnp_pm_data_seg != 0)
- dpmi_free_descriptor(isa_pnp_pm_data_seg);
- if (isa_pnp_rm_call_area_code_sel != 0)
- dpmi_free_descriptor(isa_pnp_rm_call_area_code_sel);
- if (isa_pnp_rm_call_area_sel != 0)
- dpmi_free_dos(isa_pnp_rm_call_area_sel);
- isa_pnp_pm_code_seg = 0;
- isa_pnp_pm_data_seg = 0;
- isa_pnp_rm_call_area_sel = 0;
- isa_pnp_rm_call_area_code_sel = 0;
- isa_pnp_rm_call_area = NULL;
- isa_pnp_pm_use = 0;
-#endif
-}
-
-int find_isa_pnp_bios() {
-#if TARGET_MSDOS == 32
- uint8_t *scan = (uint8_t*)0xF0000;
-#else
- uint8_t far *scan = (uint8_t far*)MK_FP(0xF000U,0x0000U);
-#endif
- unsigned int offset,i;
-
- free_isa_pnp_bios();
- isa_pnp_bios_offset = (uint16_t)(~0U);
- memset(&isa_pnp_info,0,sizeof(isa_pnp_info));
-
- /* NTS: Stop at 0xFFE0 because 0xFFE0+0x21 >= end of 64K segment */
- for (offset=0U;offset != 0xFFE0U;offset += 0x10U,scan += 0x10) {
- if (scan[0] == '$' && scan[1] == 'P' && scan[2] == 'n' &&
- scan[3] == 'P' && scan[4] >= 0x10 && scan[5] >= 0x21) {
- uint8_t chk=0;
- for (i=0;i < scan[5];i++)
- chk += scan[i];
-
- if (chk == 0) {
- isa_pnp_bios_offset = (uint16_t)offset;
- _fmemcpy(&isa_pnp_info,scan,sizeof(isa_pnp_info));
- isa_pnp_rm_call = (void far*)MK_FP(isa_pnp_info.rm_ent_segment,
- isa_pnp_info.rm_ent_offset);
-
-#if TARGET_MSDOS == 32
- isa_pnp_rm_call_area = dpmi_alloc_dos(ISA_PNP_RM_DOS_AREA_SIZE,&isa_pnp_rm_call_area_sel);
- if (isa_pnp_rm_call_area == NULL) {
- fprintf(stderr,"WARNING: Failed to allocate common area for DOS realmode calling\n");
- goto fail;
- }
-
- /* allocate descriptors to make calling the BIOS from pm mode */
- if ((isa_pnp_pm_code_seg = dpmi_alloc_descriptor()) != 0) {
- if (!dpmi_set_segment_base(isa_pnp_pm_code_seg,isa_pnp_info.pm_ent_segment_base)) {
- fprintf(stderr,"WARNING: Failed to set segment base\n"); goto fail; }
- if (!dpmi_set_segment_limit(isa_pnp_pm_code_seg,0xFFFFUL)) {
- fprintf(stderr,"WARNING: Failed to set segment limit\n"); goto fail; }
- if (!dpmi_set_segment_access(isa_pnp_pm_code_seg,0x9A)) {
- fprintf(stderr,"WARNING: Failed to set segment access rights\n"); goto fail; }
- }
-
- if ((isa_pnp_pm_data_seg = dpmi_alloc_descriptor()) != 0) {
- if (!dpmi_set_segment_base(isa_pnp_pm_data_seg,isa_pnp_info.pm_ent_data_segment_base)) {
- fprintf(stderr,"WARNING: Failed to set segment base\n"); goto fail; }
- if (!dpmi_set_segment_limit(isa_pnp_pm_data_seg,0xFFFFUL)) {
- fprintf(stderr,"WARNING: Failed to set segment limit\n"); goto fail; }
- if (!dpmi_set_segment_access(isa_pnp_pm_data_seg,0x92)) {
- fprintf(stderr,"WARNING: Failed to set segment access rights\n"); goto fail; }
- }
-
- /* allocate code selector for realmode area */
- if ((isa_pnp_rm_call_area_code_sel = dpmi_alloc_descriptor()) != 0) {
- if (!dpmi_set_segment_base(isa_pnp_rm_call_area_code_sel,(uint32_t)isa_pnp_rm_call_area)) {
- fprintf(stderr,"WARNING: Failed to set segment base\n"); goto fail; }
- if (!dpmi_set_segment_limit(isa_pnp_rm_call_area_code_sel,0xFFFFUL)) {
- fprintf(stderr,"WARNING: Failed to set segment limit\n"); goto fail; }
- if (!dpmi_set_segment_access(isa_pnp_rm_call_area_code_sel,0x9A)) {
- fprintf(stderr,"WARNING: Failed to set segment access rights\n"); goto fail; }
- }
-
- isa_pnp_pm_use = 1;
-#endif
-
- return 1;
-#if TARGET_MSDOS == 32
-fail: free_isa_pnp_bios();
- return 0;
-#endif
- }
- }
- }
-
- return 0;
-}
-
-#if TARGET_MSDOS == 32
-
-static unsigned int isa_pnp_thunk_and_call() { /* private, don't export */
- unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
- if (isa_pnp_pm_use) {
- unsigned char *callfunc = (unsigned char*)isa_pnp_rm_call_area + 0x8;
- unsigned short ret_ax = ~0U,my_cs = 0;
-
- __asm {
- mov ax,cs
- mov my_cs,ax
- }
-
- /* 32-bit far pointer used in call below */
- *((uint32_t*)(callfunc+0+0)) = 0x08+0x8;
- *((uint32_t*)(callfunc+0+4)) = isa_pnp_rm_call_area_code_sel;
- /* 386 assembly language: CALL <proc> */
- *((uint8_t *)(callfunc+8+0)) = 0x9A;
- *((uint16_t*)(callfunc+8+1)) = (uint16_t)isa_pnp_info.pm_ent_offset;
- *((uint16_t*)(callfunc+8+3)) = (uint16_t)isa_pnp_pm_code_seg;
- /* 386 assembly language: from 16-bit segment: [32-bit] call far <32-bit code segment:offset of label "asshole"> */
- *((uint8_t *)(callfunc+8+5)) = 0x66;
- *((uint8_t *)(callfunc+8+6)) = 0x67;
- *((uint8_t *)(callfunc+8+7)) = 0xEA;
- *((uint32_t*)(callfunc+8+8)) = 0;
- *((uint32_t*)(callfunc+8+12)) = my_cs;
-
- /* protected mode call */
- if (isa_pnp_pm_win95_mode) {
- /* Windows 95 mode: call just like below, but DON'T switch stacks (leave SS:ESP => 32-bit stack).
- * This is what Windows 95 does and it's probably why the Bochs implementation of Plug & Play BIOS
- * doesn't work, since everything in the PnP spec implies 16-bit FAR pointers */
- __asm {
- pushad
- push fs
- cli
-
- ; These stupid acrobatics are necessary because Watcom has a hang-up
- ; about inline assembly referring to stack variables and doesn't like
- ; inline assembly referring to label addresses
- call acrobat1 ; near call to put label address on stack
- jmp asshole ; relative JMP address to the 'asshole' label below
-acrobat1: pop eax ; retrieve the address of the 'acrobat1' label
- add eax,dword ptr [eax+1] ; sum it against the relative 32-bit address portion of the JMP instruction (NTS: JMP = 0xEA <32-bit rel addr>)
- mov esi,callfunc
- mov dword ptr [esi+8+8],eax
-
-; mov cx,ss
- mov dx,ds
- mov ebx,esp
-; mov esi,ebp
-; xor ebp,ebp
- mov esp,isa_pnp_rm_call_area
- add esp,0x1F0
- mov ax,isa_pnp_rm_call_area_sel
- mov fs,ax
- mov ax,isa_pnp_pm_data_seg
- mov ds,ax
- mov es,ax
-
- ; call
- jmpf fword ptr fs:0x8
-
- ; WARNING: do NOT remove these NOPs
- nop
- nop
- nop
- nop
- nop
- nop
-asshole:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-
- ; restore stack (NTS: PnP BIOSes are supposed to restore ALL regs except AX)
- cli
-; mov ebp,esi
- mov esp,ebx
-; mov ss,cx
- mov ds,dx
- mov es,dx
-
- mov ret_ax,ax
-
- sti
- pop fs
- popad
- }
- }
- else {
- __asm {
- pushad
- cli
-
- ; These stupid acrobatics are necessary because Watcom has a hang-up
- ; about inline assembly referring to stack variables and doesn't like
- ; inline assembly referring to label addresses
- call acrobat1 ; near call to put label address on stack
- jmp asshole ; relative JMP address to the 'asshole' label below
-acrobat1: pop eax ; retrieve the address of the 'acrobat1' label
- add eax,dword ptr [eax+1] ; sum it against the relative 32-bit address portion of the JMP instruction (NTS: JMP = 0xEA <32-bit rel addr>)
- mov esi,callfunc
- mov dword ptr [esi+8+8],eax
-
- mov cx,ss
- mov dx,ds
- mov ebx,esp
- mov esi,ebp
- xor ebp,ebp
- mov esp,0x1F0
- mov ax,isa_pnp_rm_call_area_sel
- mov ss,ax
- mov ax,isa_pnp_pm_data_seg
- mov ds,ax
- mov es,ax
-
- ; call
- jmpf fword ptr ss:0x8
-
- ; WARNING: do NOT remove these NOPs
- nop
- nop
- nop
- nop
- nop
- nop
-asshole:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-
- ; restore stack (NTS: PnP BIOSes are supposed to restore ALL regs except AX)
- cli
- mov ebp,esi
- mov esp,ebx
- mov ss,cx
- mov ds,dx
- mov es,dx
-
- mov ret_ax,ax
-
- sti
- popad
- }
- }
-
- return ret_ax;
- }
- else {
- /* real-mode call via DPMI */
- /* ..but wait---we might be running under DOS4/G which doesn't
- provide the "real mode call" function! */
- struct dpmi_realmode_call d={0};
- unsigned int x = (unsigned int)(&d); /* NTS: Work around Watcom's "cannot take address of stack symbol" error */
- d.cs = isa_pnp_info.rm_ent_segment;
- d.ip = isa_pnp_info.rm_ent_offset;
- d.ss = sgm; /* our real-mode segment is also the stack during the call */
- d.sp = 0x1F0;
-
- if (dpmi_no_0301h < 0) probe_dpmi();
-
- if (dpmi_no_0301h > 0) {
- /* Fuck you DOS4/GW! */
- dpmi_alternate_rm_call_stacko(&d);
- }
- else {
- __asm {
- pushad
-
- push ds
- pop es
-
- mov eax,0x0301 ; DPMI call real-mode far routine
- xor ebx,ebx
- xor ecx,ecx
- mov edi,x
- int 0x31
-
- popad
- }
- }
-
- if (!(d.flags & 1))
- return d.eax&0xFF;
- }
-
- return ~0U;
-}
-
-unsigned int isa_pnp_bios_number_of_sysdev_nodes(unsigned char far *a,unsigned int far *b) {
- /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
- /* SEG:0x0000 = a
- * SEG:0x0004 = b
- * SEG:0x00F0 = stack for passing params */
- unsigned int *rb_a = (unsigned int*)((unsigned char*)isa_pnp_rm_call_area);
- unsigned int *rb_b = (unsigned int*)((unsigned char*)isa_pnp_rm_call_area + 4);
- unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
- unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
- unsigned int ret_ax = ~0;
-
- *rb_a = ~0UL; *rb_b = ~0UL;
-
- /* build the stack */
- stk[5] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
- stk[4] = sgm;
- stk[3] = 4; /* offset of "b" (segment will be filled in separately) */
- stk[2] = sgm;
- stk[1] = 0; /* offset of "a" (ditto) */
- stk[0] = 0; /* function */
-
- ret_ax = isa_pnp_thunk_and_call();
- if (ret_ax == ~0U) {
- fprintf(stderr,"WARNING: Thunk and call failed\n");
- }
- else {
- *a = (unsigned char)(*rb_a);
- *b = *rb_b & 0xFFFF;
- return ret_ax&0xFF;
- }
-
- return ~0;
-}
-
-unsigned int isa_pnp_bios_get_sysdev_node(unsigned char far *a,unsigned char far *b,unsigned int c) {
- /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
- /* SEG:0x0000 = a (node)
- * SEG:0x00F0 = stack for passing params
- * SEG:0x0100 = b (buffer for xfer)
- * SEF:0x0FFF = end */
- unsigned char *rb_a = (unsigned char*)((unsigned char*)isa_pnp_rm_call_area);
- unsigned char *rb_b = (unsigned char*)((unsigned char*)isa_pnp_rm_call_area + 0x200);
- unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
- unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
- unsigned int ret_ax = ~0;
-
- *rb_a = *a;
- rb_b[0] = rb_b[1] = 0;
-
- stk[6] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
- stk[5] = c;
- stk[4] = sgm; /* offset of "b" */
- stk[3] = 0x200;
- stk[2] = sgm; /* offset of "a" */
- stk[1] = 0;
- stk[0] = 1; /* function */
-
- ret_ax = isa_pnp_thunk_and_call();
- if (ret_ax == ~0U) {
- fprintf(stderr,"WARNING: Thunk and call failed\n");
- }
- else {
- unsigned int len = *((uint16_t*)rb_b); /* read back the size of the device node */
- *a = (unsigned char)(*rb_a);
- if ((0x100+len) > ISA_PNP_RM_DOS_AREA_SIZE) {
- fprintf(stderr,"Whoahhhh..... the returned device struct is too large! len=%u\n",len);
- return 0xFF;
- }
- else {
- if ((ret_ax&0xFF) == 0) _fmemcpy(b,rb_b,len);
- }
- return ret_ax&0xFF;
- }
-
- return ~0;
-}
-
-unsigned int isa_pnp_bios_get_static_alloc_resinfo(unsigned char far *a) {
- return ~0;
-}
-
-unsigned int isa_pnp_bios_get_pnp_isa_cfg(unsigned char far *a) {
- /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
- /* SEG:0x0000 = a (node)
- * SEG:0x00F0 = stack for passing params
- * SEG:0x0100 = b (buffer for xfer)
- * SEF:0x0FFF = end */
- unsigned char *rb_a = (unsigned char*)((unsigned char*)isa_pnp_rm_call_area + 0x200);
- unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
- unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
- unsigned int ret_ax = ~0;
-
- stk[3] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
- stk[2] = sgm; /* offset of "a" */
- stk[1] = 0x200;
- stk[0] = 0x40; /* function */
-
- ret_ax = isa_pnp_thunk_and_call();
- if (ret_ax == ~0U) {
- fprintf(stderr,"WARNING: Thunk and call failed\n");
- }
- else {
- if ((ret_ax&0xFF) == 0) _fmemcpy(a,rb_a,sizeof(struct isapnp_pnp_isa_cfg));
- return ret_ax&0xFF;
- }
-
- return ~0;
-}
-
-/* UPDATE 2011/05/27: Holy shit, found an ancient Pentium Pro system who's BIOS implements the ESCD functions! */
-unsigned int isa_pnp_bios_get_escd_info(unsigned int far *min_escd_write_size,unsigned int far *escd_size,unsigned long far *nv_storage_base) {
- /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
- /* SEG:0x0000 = a (node)
- * SEG:0x00F0 = stack for passing params
- * SEG:0x0100 = b (buffer for xfer)
- * SEF:0x0FFF = end */
- unsigned short *rb_a = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x200);
- unsigned short *rb_b = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x204);
- unsigned long *rb_c = (unsigned long*)((unsigned char*)isa_pnp_rm_call_area + 0x208);
- unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
- unsigned short sgm = isa_pnp_pm_use ? (unsigned short)isa_pnp_rm_call_area_sel : (unsigned short)((size_t)isa_pnp_rm_call_area >> 4);
- unsigned int ret_ax = ~0;
-
- *rb_a = ~0UL;
- *rb_b = ~0UL;
- *rb_c = ~0UL;
-
- stk[7] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
-
- stk[6] = sgm; /* offset of "c" */
- stk[5] = 0x208;
-
- stk[4] = sgm; /* offset of "b" */
- stk[3] = 0x204;
-
- stk[2] = sgm; /* offset of "a" */
- stk[1] = 0x200;
-
- stk[0] = 0x41; /* function */
-
- ret_ax = isa_pnp_thunk_and_call();
- if (ret_ax == ~0U) {
- fprintf(stderr,"WARNING: Thunk and call failed\n");
- }
- else {
- if ((ret_ax&0xFF) == 0) {
- *min_escd_write_size = *rb_a;
- *escd_size = *rb_b;
- *nv_storage_base = *rb_c;
- }
- return ret_ax&0xFF;
- }
-
- return ~0;
-}
-
-unsigned int isa_pnp_bios_send_message(unsigned int msg) {
- /* use the DOS segment we allocated as a "trampoline" for the 16-bit code to write the return values to */
- /* SEG:0x0000 = a (node)
- * SEG:0x00F0 = stack for passing params
- * SEG:0x0100 = b (buffer for xfer)
- * SEF:0x0FFF = end */
- unsigned short *stk = (unsigned short*)((unsigned char*)isa_pnp_rm_call_area + 0x1F0);
- unsigned int ret_ax = ~0;
-
- stk[2] = isa_pnp_pm_use ? (unsigned short)isa_pnp_pm_data_seg : (unsigned short)isa_pnp_info.rm_ent_data_segment; /* BIOS data segment */
- stk[1] = msg;
-
- stk[0] = 0x04; /* function */
-
- ret_ax = isa_pnp_thunk_and_call();
- if (ret_ax == ~0U) {
- fprintf(stderr,"WARNING: Thunk and call failed\n");
- }
- else {
- return ret_ax&0xFF;
- }
-
- return ~0U;
-}
-
-#endif
-
-void isa_pnp_product_id_to_str(char *str,unsigned long id) {
- sprintf(str,"%c%c%c%X%X%X%X",
- (unsigned char)(0x40+((id>>2)&0x1F)),
- (unsigned char)(0x40+((id&3)<<3)+((id>>13)&7)),
- (unsigned char)(0x40+((id>>8)&0x1F)),
- (unsigned char)((id>>20)&0xF),
- (unsigned char)((id>>16)&0xF),
- (unsigned char)((id>>28)&0xF),
- (unsigned char)((id>>24)&0xF));
-}
-
-const char *isapnp_tag_str(uint8_t tag) { /* tag from struct isapnp_tag NOT the raw byte */
- if (tag >= (sizeof(isapnp_tag_strs)/sizeof(isapnp_tag_strs[0])))
- return NULL;
-
- return isapnp_tag_strs[tag];
-}
-
-const char *isapnp_sdf_priority_str(uint8_t x) {
- if (x >= 3) return NULL;
- return isapnp_sdf_priority_strs[x];
-}
-
-int isapnp_read_tag(uint8_t far **pptr,uint8_t far *fence,struct isapnp_tag *tag) {
- uint8_t far *ptr = *pptr;
- unsigned char c;
-
- if (ptr >= fence)
- return 0;
-
- c = *ptr++;
- if (c & 0x80) { /* large tag */
- tag->tag = 0x10 + (c & 0x7F);
- tag->len = *((uint16_t far*)(ptr));
- ptr += 2;
- tag->data = ptr;
- ptr += tag->len;
- if (ptr > fence)
- return 0;
- }
- else { /* small tag */
- tag->tag = (c >> 3) & 0xF;
- tag->len = c & 7;
- tag->data = ptr;
- ptr += tag->len;
- if (ptr > fence)
- return 0;
- }
-
- *pptr = ptr;
- return 1;
-}
-
-const char *isa_pnp_device_category(uint32_t productid) {
- char tmp[8]; isa_pnp_product_id_to_str(tmp,productid);
- if (!memcmp(tmp,"PNP",3)) {
- switch (tmp[3]) {
- case '0': switch(tmp[4]) {
- case '0': return "System device, interrupt controller";
- case '1': return "System device, timer";
- case '2': return "System device, DMA controller";
- case '3': return "System device, keyboard";
- case '4': return "System device, parallel port";
- case '5': return "System device, serial port";
- case '6': return "System device, hard disk controller";
- case '7': return "System device, floppy disk controller";
- case '9': return "System device, display adapter";
- case 'A': return "System device, peripheral bus";
- case 'C': return "System device, motherboard device";
- case 'E': return "System device, PCMCIA controller";
- case 'F': return "System device, mouse";
- default: return "System devices";
- }
- case '8': return "Network devices";
- case 'A': return "SCSI & non-standard CD-ROM devices";
- case 'B': return "Sound, video & multimedia";
- case 'C': return "Modem devices";
- };
- }
-
- return NULL;
-}
-
-void isa_pnp_device_description(char desc[255],uint32_t productid) {
- char tmp[8]; isa_pnp_product_id_to_str(tmp,productid);
- desc[0] = 0;
-
- if (!memcmp(tmp,"PNP",3)) {
- unsigned int hex = (unsigned int)strtol(tmp+3,0,16),hexm = 0;
- const char *rets = NULL,**arr = NULL;
- unsigned int ars = 0;
- if (hex == 0x0800) {
- rets = "PC speaker";
- }
- else if (hex == 0x0B00) {
- rets = "Realtime clock";
- }
- else if (hex == 0x09FF) {
- rets = "Plug & Play DDC monitor";
- }
- else {
- switch (hex>>8) {
-#define PNP(a) \
- case a: ars = sizeof(isa_pnp_devd_pnp_##a##xx)/sizeof(isa_pnp_devd_pnp_##a##xx[0]); arr = isa_pnp_devd_pnp_##a##xx; hexm = 0xFF; break
- PNP(0x00); /* PNP00xx */ PNP(0x01); /* PNP01xx */
- PNP(0x02); /* PNP02xx */ PNP(0x03); /* PNP03xx */
- PNP(0x04); /* PNP04xx */ PNP(0x05); /* PNP05xx */
- PNP(0x06); /* PNP06xx */ PNP(0x07); /* PNP07xx */
- PNP(0x09); /* PNP09xx */ PNP(0x0A); /* PNP0Axx */
- PNP(0x0C); /* PNP0Cxx */ PNP(0x0E); /* PNP0Exx */
- PNP(0x0F); /* PNP0Fxx */
-#undef PNP
- }
- };
-
- if (rets == NULL && ars != (size_t)0 && arr != NULL && (hex&hexm) < ars)
- rets = arr[hex&hexm];
-
- if (rets != NULL)
- strcpy(desc,rets);
- }
-}
-
-const char *isa_pnp_device_type(const uint8_t far *b,const char **subtype,const char **inttype) {
- const char *st = NULL;
- const char *it = NULL;
- const char *t = NULL;
-
- switch (b[0]) {
- case 1: t = "Mass Storage Device";
- switch (b[1]) {
- case 0: st = "SCSI controller"; break;
- case 1: st = "IDE controller (Standard ATA compatible)";
- switch (b[2]) {
- case 0: it = "Generic IDE"; break;
- };
- break;
- case 2: st = "Floppy controller (Standard 765 compatible)";
- switch (b[2]) {
- case 0: it = "Generic floppy"; break;
- };
- break;
- case 3: st = "IPI controller";
- switch (b[2]) {
- case 0: it = "Generic"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 2: t = "Network Interface Controller";
- switch (b[1]) {
- case 0: st = "Ethernet controller";
- switch (b[2]) {
- case 0: it = "Generic"; break;
- };
- break;
- case 1: st = "Token ring controller";
- switch (b[2]) {
- case 0: it = "Generic"; break;
- };
- break;
- case 2: st = "FDDI controller";
- switch (b[2]) {
- case 0: it = "Generic"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 3: t = "Display Controller";
- switch (b[1]) {
- case 0: st = "VGA controller (Standard VGA compatible)";
- switch (b[2]) {
- case 0: it = "Generic VGA compatible"; break;
- case 1: it = "VESA SVGA compatible"; break;
- };
- break;
- case 1: st = "XGA compatible controller";
- switch (b[2]) {
- case 0: it = "General XGA compatible"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 4: t = "Multimedia Controller";
- switch (b[1]) {
- case 0: st = "Video controller";
- switch (b[2]) {
- case 0: it = "General video"; break;
- };
- break;
- case 1: st = "Audio controller";
- switch (b[2]) {
- case 0: it = "General audio"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 5: t = "Memory";
- switch (b[1]) {
- case 0: st = "RAM";
- switch (b[2]) {
- case 0: it = "General RAM"; break;
- };
- break;
- case 1: st = "Flash memory";
- switch (b[2]) {
- case 0: it = "General flash memory"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 6: t = "Bridge controller";
- switch (b[1]) {
- case 0: st = "Host processor bridge";
- switch (b[2]) {
- case 0: it = "General"; break;
- };
- break;
- case 1: st = "ISA bridge";
- switch (b[2]) {
- case 0: it = "General"; break;
- };
- break;
- case 2: st = "EISA bridge";
- switch (b[2]) {
- case 0: it = "General"; break;
- };
- break;
- case 3: st = "MCA bridge";
- switch (b[2]) {
- case 0: it = "General"; break;
- };
- break;
- case 4: st = "PCI bridge";
- switch (b[2]) {
- case 0: it = "General"; break;
- };
- break;
- case 5: st = "PCMCIA bridge";
- switch (b[2]) {
- case 0: it = "General"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 7: t = "Communications device";
- switch (b[1]) {
- case 0: st = "RS-232";
- switch (b[2]) {
- case 0: it = "Generic"; break;
- case 1: it = "16450-compatible"; break;
- case 2: it = "16550-compatible"; break;
- };
- break;
- case 1: st = "Parallel port (AT compatible)";
- switch (b[2]) {
- case 0: it = "General"; break;
- case 1: it = "Model 30 bidirectional port"; break;
- case 2: it = "ECP 1.x port"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 8: t = "System peripheral";
- switch (b[1]) {
- case 0: st = "Programmable Interrupt Controller (8259 compatible)";
- switch (b[2]) {
- case 0: it = "Generic"; break;
- case 1: it = "ISA"; break;
- case 2: it = "EISA"; break;
- };
- break;
- case 1: st = "DMA controller (8237 compatible)";
- switch (b[2]) {
- case 0: it = "General"; break;
- case 1: it = "ISA"; break;
- case 2: it = "EISA"; break;
- };
- break;
- case 2: st = "System Timer (8254 compatible)";
- switch (b[2]) {
- case 0: it = "General"; break;
- case 1: it = "ISA"; break;
- case 2: it = "EISA"; break;
- };
- break;
- case 3: st = "Real-time clock";
- switch (b[2]) {
- case 0: it = "Generic"; break;
- case 1: it = "ISA"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 9: t = "Input device";
- switch (b[1]) {
- case 0: st = "Keyboard controller";
- switch (b[2]) {
- case 0: it = "N/A"; break;
- };
- break;
- case 1: st = "Digitizer (pen)";
- switch (b[2]) {
- case 0: it = "N/A"; break;
- };
- break;
- case 2: st = "Mouse controller";
- switch (b[2]) {
- case 0: it = "N/A"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 10: t = "Docking station";
- switch (b[1]) {
- case 0: st = "Generic";
- switch (b[2]) {
- case 0: it = "N/A"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
- case 11: t = "CPU type";
- switch (b[1]) {
- case 0: st = "386";
- switch (b[2]) {
- case 0: it = "N/A"; break;
- };
- break;
- case 1: st = "486";
- switch (b[2]) {
- case 0: it = "N/A"; break;
- };
- break;
- case 2: st = "586";
- switch (b[2]) {
- case 0: it = "N/A"; break;
- };
- break;
- case 0x80:
- st = "Other";
- break;
- };
- break;
-
- };
-
- if (subtype != NULL)
- *subtype = st;
- if (inttype != NULL)
- *inttype = it;
-
- return t;
-}
-
-void isa_pnp_init_key() {
- unsigned int i;
-
- for (i=0;i < 4;i++)
- isa_pnp_write_address(0);
- for (i=0;i < 32;i++)
- isa_pnp_write_address(isa_pnp_init_keystring[i]);
-
- /* software must delay 1ms prior to starting the first pair of isolation reads and must wait
- * 250us between each subsequent pair of isolation reads. this delay gives the ISA card time
- * to access information for possibly very slow storage devices */
- t8254_wait(t8254_us2ticks(1200));
-}
-
-void isa_pnp_wake_csn(unsigned char id) {
- isa_pnp_write_address(3); /* Wake[CSN] */
- isa_pnp_write_data(id); /* isolation state */
-}
-
-/* the caller is expected to specify which card by calling isa_pnp_wake_csn() */
-int isa_pnp_init_key_readback(unsigned char *data/*9 bytes*/) {
- unsigned char checksum = 0x6a;
- unsigned char b,c1,c2,bit;
- unsigned int i,j;
-
- isa_pnp_write_address(1); /* serial isolation reg */
- for (i=0;i < 9;i++) {
- b = 0;
- for (j=0;j < 8;j++) {
- c1 = isa_pnp_read_data();
- c2 = isa_pnp_read_data();
- if (c1 == 0x55 && c2 == 0xAA) {
- b |= 1 << j;
- bit = 1;
- }
- else {
- bit = 0;
- }
-
- if (i < 8)
- checksum = ((((checksum ^ (checksum >> 1)) & 1) ^ bit) << 7) | (checksum >> 1);
-
- t8254_wait(t8254_us2ticks(275));
- }
- data[i] = b;
- }
-
- return (checksum == data[8]);
-}
-
-void isa_pnp_set_read_data_port(uint16_t port) {
- isa_pnp_write_address(0x00); /* RD_DATA port */
- isa_pnp_write_data(port >> 2);
-}
-
-unsigned char isa_pnp_read_config() {
- unsigned int patience = 20;
- unsigned char ret = 0xFF;
-
- do {
- isa_pnp_write_address(0x05);
- if (isa_pnp_read_data() & 1) {
- isa_pnp_write_address(0x04);
- ret = isa_pnp_read_data();
- break;
- }
- else {
- if (--patience == 0) break;
- t8254_wait(t8254_us2ticks(100));
- }
- } while (1);
- return ret;
-}
-
-uint8_t isa_pnp_read_data_register(uint8_t x) {
- isa_pnp_write_address(x);
- return isa_pnp_read_data();
-}
-
-void isa_pnp_write_data_register(uint8_t x,uint8_t data) {
- isa_pnp_write_address(0x00);
- isa_pnp_write_address(x);
- isa_pnp_write_data(data);
-}
-
-int isa_pnp_read_io_resource(unsigned int i) {
- uint16_t ret;
-
- if (i >= 8) return -1;
- ret = (uint16_t)isa_pnp_read_data_register(0x60 + (i*2)) << 8;
- ret |= (uint16_t)isa_pnp_read_data_register(0x60 + (i*2) + 1);
- return ret;
-}
-
-void isa_pnp_write_io_resource(unsigned int i,uint16_t port) {
- if (i >= 8) return;
- isa_pnp_write_data_register(0x60 + (i*2),port >> 8);
- isa_pnp_write_data_register(0x60 + (i*2) + 1,port);
- t8254_wait(t8254_us2ticks(250));
-}
-
-int isa_pnp_read_irq(unsigned int i) {
- uint8_t c;
-
- if (i >= 2) return -1;
- c = isa_pnp_read_data_register(0x70 + (i*2));
- if (c == 0xFF) return -1;
- if ((c & 15) == 0) return -1; /* not assigned */
- return (c & 15);
-}
-
-void isa_pnp_write_irq(unsigned int i,int irq) {
- if (i >= 2) return;
- if (irq < 0) irq = 0;
- isa_pnp_write_data_register(0x70 + (i*2),irq);
- t8254_wait(t8254_us2ticks(250));
-}
-
-void isa_pnp_write_irq_mode(unsigned int i,unsigned int im) {
- if (i >= 2) return;
- isa_pnp_write_data_register(0x70 + (i*2) + 1,im);
- t8254_wait(t8254_us2ticks(250));
-}
-
-int isa_pnp_read_dma(unsigned int i) {
- uint8_t c;
-
- if (i >= 2) return -1;
- c = isa_pnp_read_data_register(0x74 + i);
- if (c == 0xFF) return -1;
- if ((c & 7) == 4) return -1; /* not assigned */
- return (c & 7);
-}
-
-void isa_pnp_write_dma(unsigned int i,int dma) {
- if (i >= 2) return;
- if (dma < 0) dma = 4;
- isa_pnp_write_data_register(0x74 + i,dma);
- t8254_wait(t8254_us2ticks(250));
-}
+++ /dev/null
-
-#ifndef __ISAPNP_ISAPNP_H
-#define __ISAPNP_ISAPNP_H
-
-/* NOTES:
- *
- * Provides an API for BIOS PnP calls.
- * Contrary to what you might expect this is apparently done by scanning the ROM area
- * for a structure then making far calls to a memory address stored there. There is
- * a real-mode and protected mode interface.
- * - If compiled for 16-bit real mode, then only the real mode interface is
- * supported by this code. The calls to the BIOS are provided by macros that
- * make direct calls to the subroutine.
- * - If compiled for 32-bit protected (flat) mode, then both real and protected
- * mode interfaces are supported. Real mode calls are made via the DPMI server
- * functions (thunking to real or v86 mode) and protected mode is dealt with
- * through abuse of the DPMI selector functions and willingness to jump between
- * 16/32-bit code segments (since the protected mode entry point is 16-bit
- * protected mode, and we are a 32-bit flat protected mode DOS program.... see
- * the conflict?). While I've tested this code as best I can, I can't really
- * guarantee that the code will work 100% reliably if your BIOS is funny or
- * broken in the protected mode entry point.
- *
- * The protected mode version of this code uses DPMI and DOS to create a "common
- * area" below the 1MB boundary where parameters and stack are maintained to call
- * the BIOS with (real or protected).
- *
- * This also provides basic functions for direct ISA PnP I/O including management
- * of address and data ports.
- *
- * Requires the 8254 timer functions. Calling program is expected to init the 8254
- * library. The timer routines are needed for configuration read timeouts.
- *
- * DO NOT RUN THIS CODE UNDER MS WINDOWS!!! I'm not certain how well the Windows 9x
- * and Windows 3.1 kernels would take us mucking around with ISA configuration
- * registers but it would probably cause a hard crash! RUN THIS CODE FROM PURE DOS
- * MODE!
- *
- * WARNING: There are some worst case scenarios you should be aware of:
- * - The BIOS subroutine may have serious bugs especially in protected mode
- * - Calls to the BIOS can crash in really bad situations
- * - If the motherboard, hardware, or overall computer implementation is
- * cheap and crappy, this code might trigger some serious problems and
- * hang the machine.
- * - If for any reason something OTHER than the ROM BIOS exists at 0xF0000-0xFFFFF
- * and reading triggers any hardware activity, this code will probably cause
- * problems there as well. */
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-enum {
- ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW=1,
- ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NEXT_BOOT=2
-};
-
-/* number of configuration "blocks" in a system device node.
- * each "block" is one after the other, terminated by an END tag.
- * first one is what is allocated, next is what is possible, third
- * is what is compatible. */
-#define ISAPNP_CONFIG_BLOCKS 3
-
-extern const char *isapnp_dma_xfer_preference_str[4];
-extern const char *isapnp_fml32_miosize_str[4];
-extern const char *isapnp_sdf_priority_strs[3];
-extern const char *isapnp_config_block_str[3];
-extern const char *isapnp_dma_speed_str[4];
-extern const char *isapnp_tag_strs[];
-
-#pragma pack(push,1)
-struct isa_pnp_bios_struct {
- char signature[4]; /* 0x00 */
- uint8_t version; /* 0x04 */
- uint8_t length; /* 0x05 */
- uint16_t control; /* 0x06 */
- uint8_t checksum; /* 0x08 */
- uint32_t event_notify_flag_addr; /* 0x09 */
- uint16_t rm_ent_offset; /* 0x0D */
- uint16_t rm_ent_segment; /* 0x0F */
- uint16_t pm_ent_offset; /* 0x11 */
- uint32_t pm_ent_segment_base; /* 0x13 */
- uint32_t oem_device_id; /* 0x17 */
- uint16_t rm_ent_data_segment; /* 0x1B */
- uint32_t pm_ent_data_segment_base;/* 0x1D */
- /* 0x21 */
-};
-
-/* NTS: This actually represents the fixed portion of the struct.
- * Variable length records follow */
-struct isa_pnp_device_node {
- uint16_t size; /* 0x00 ...of entire node */
- uint8_t handle; /* 0x02 */
- uint32_t product_id; /* 0x03 */
- uint8_t type_code[3]; /* 0x07 */
- uint16_t attributes; /* 0x0A */
-#define ISAPNP_DEV_ATTR_CANT_DISABLE (1 << 0)
-#define ISAPNP_DEV_ATTR_CANT_CONFIGURE (1 << 1)
-#define ISAPNP_DEV_ATTR_CAN_BE_PRIMARY_OUTPUT (1 << 2)
-#define ISAPNP_DEV_ATTR_CAN_BE_PRIMARY_INPUT (1 << 3)
-#define ISAPNP_DEV_ATTR_CAN_BE_PRIMARY_IPL (1 << 4)
-#define ISAPNP_DEV_ATTR_DOCKING_STATION_DEVICE (1 << 5)
-#define ISAPNP_DEV_ATTR_REMOVEABLE_STATION_DEVICE (1 << 6)
-
-#define ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE(x) (((x) >> 7) & 3)
-
-#define ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE_ONLY_NEXT_BOOT 0
-#define ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE_AT_RUNTIME 1
-#define ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE_ONLY_RUNTIME 3
-
- /* variable length fields follow */
-};
-#pragma pack(pop)
-
-/* small tags */
-#define ISAPNP_TAG_PNP_VERSION 0x01
-#define ISAPNP_TAG_LOGICAL_DEVICE_ID 0x02
-#define ISAPNP_TAG_COMPATIBLE_DEVICE_ID 0x03
-#define ISAPNP_TAG_IRQ_FORMAT 0x04
-#define ISAPNP_TAG_DMA_FORMAT 0x05
-#define ISAPNP_TAG_START_DEPENDENT_FUNCTION 0x06
-#define ISAPNP_TAG_END_DEPENDENT_FUNCTION 0x07
-#define ISAPNP_TAG_IO_PORT 0x08
-#define ISAPNP_TAG_FIXED_IO_PORT 0x09
-#define ISAPNP_TAG_VENDOR 0x0E
-#define ISAPNP_TAG_END 0x0F
-/* large tags */
-#define ISAPNP_TAG_ANSI_ID_STRING 0x12
-#define ISAPNP_TAG_FIXED_MEMORY_LOCATION_32 0x16
-
-struct isapnp_tag {
- uint8_t tag; /* tag: 0x00+N = small tag N 0x10+N = large tag N */
- uint16_t len; /* length of data */
- uint8_t far* data; /* data */
-};
-
-#pragma pack(push,1)
-struct isapnp_tag_compatible_device_id {
- uint32_t id;
-};
-
-struct isapnp_tag_pnp_version { /* ISAPNP_TAG_PNP_VERSION len=2 */
- uint8_t pnp;
- uint8_t vendor;
-};
-
-struct isapnp_tag_logical_device_id {
- uint32_t logical_device_id;
- uint8_t flags;
- uint8_t flags2; /* if length >= 6 */
-};
-
-struct isapnp_tag_irq_format {
- uint16_t irq_mask;
- /*------------------------*/
- uint8_t hte:1; /* bit 0 */
- uint8_t lte:1; /* bit 1 */
- uint8_t htl:1; /* bit 2 */
- uint8_t ltl:1; /* bit 3 */
- uint8_t reserved:4; /* bit 4-7 */
-};
-
-struct isapnp_tag_dma_format {
- uint8_t dma_mask;
- uint8_t xfer_preference:2; /* bit 0-1 */
-#define ISAPNP_TAG_DMA_XFER_PREF_8BIT_ONLY 0
-#define ISAPNP_TAG_DMA_XFER_PREF_8_OR_16_BIT 1
-#define ISAPNP_TAG_DMA_XFER_PREF_16BIT_ONLY 2
- uint8_t bus_master:1; /* bit 2 */
- uint8_t byte_count:1; /* bit 3 */
- uint8_t word_count:1; /* bit 4 */
- uint8_t dma_speed:2; /* bit 5-6 */
-#define ISAPNP_TAG_DMA_XFER_SPEED_COMPATIBLE 0
-#define ISAPNP_TAG_DMA_XFER_SPEED_TYPE_A 1
-#define ISAPNP_TAG_DMA_XFER_SPEED_TYPE_B 2
-#define ISAPNP_TAG_DMA_XFER_SPEED_TYPE_F 3
- uint8_t reserved:1; /* bit 7 */
-};
-
-struct isapnp_tag_start_dependent_function { /* WARNING: only typecast tag->data if tag->length > 0! */
- uint8_t priority;
-#define ISAPNP_TAG_SDF_PRIO_GOOD 0
-#define ISAPNP_TAG_SDF_PRIO_ACCEPTABLE 1
-#define ISAPNP_TAG_SDF_PRIO_SUB_OPTIMAL 2
-};
-
-struct isapnp_tag_io_port {
- uint8_t decode_16bit:1; /* bit 0: decodes 16-bit ISA addresses */
- uint8_t reserved1:7;
-
- uint16_t min_range,max_range;
- uint8_t alignment;
- uint8_t length;
-};
-
-struct isapnp_tag_fixed_io_port {
- uint16_t base;
- uint8_t length;
-};
-
-struct isapnp_tag_fixed_memory_location_32 {
- uint8_t writeable:1; /* bit 0 */
- uint8_t cacheable:1; /* bit 1 */
- uint8_t support_hi_addr:1; /* bit 2 */
- uint8_t memory_io_size:2; /* bit 3-4 */
-#define ISAPNP_TAG_FML32_MIOSIZE_8BIT_ONLY 0
-#define ISAPNP_TAG_FML32_MIOSIZE_16BIT_ONLY 1
-#define ISAPNP_TAG_FML32_MIOSIZE_8_16_BIT 2
-#define ISAPNP_TAG_FML32_MIOSIZE_32BIT_ONLY 3
- uint8_t shadowable:1; /* bit 5 */
- uint8_t expansion_rom:1; /* bit 6 */
- uint8_t mio_reserved:1; /* bit 7 */
- uint32_t base,length;
-};
-
-struct isapnp_pnp_isa_cfg {
- uint8_t revision; /* +0 */
- uint8_t total_csn;
- uint16_t isa_pnp_port;
- uint16_t reserved;
-};
-#pragma pack(pop)
-
-extern struct isa_pnp_bios_struct isa_pnp_info;
-extern uint16_t isa_pnp_bios_offset;
-extern unsigned int (__cdecl far *isa_pnp_rm_call)();
-extern const unsigned char isa_pnp_init_keystring[32];
-
-#if TARGET_MSDOS == 32
-# define ISA_PNP_RM_DOS_AREA_SIZE 8192
-extern uint16_t isa_pnp_pm_code_seg; /* code segment to call protected mode BIOS if */
-extern uint16_t isa_pnp_pm_data_seg; /* data segment to call protected mode BIOS if */
-extern uint8_t isa_pnp_pm_use; /* 1=call protected mode interface 0=call real mode interface */
-extern uint8_t isa_pnp_pm_win95_mode; /* 1=call protected mode interface with 32-bit stack (Windows 95 style) */
-extern uint16_t isa_pnp_rm_call_area_code_sel;
-extern uint16_t isa_pnp_rm_call_area_sel;
-extern void* isa_pnp_rm_call_area;
-#endif
-
-int init_isa_pnp_bios();
-void free_isa_pnp_bios();
-int find_isa_pnp_bios();
-
-const char *isa_pnp_device_type(const uint8_t far *b,const char **subtype,const char **inttype);
-int isapnp_read_tag(uint8_t far **pptr,uint8_t far *fence,struct isapnp_tag *tag);
-void isa_pnp_device_description(char desc[255],uint32_t productid);
-void isa_pnp_product_id_to_str(char *str,unsigned long id);
-const char *isa_pnp_device_category(uint32_t productid);
-const char *isapnp_sdf_priority_str(uint8_t x);
-const char *isapnp_tag_str(uint8_t tag);
-
-int isa_pnp_init_key_readback(unsigned char *data/*9 bytes*/);
-void isa_pnp_set_read_data_port(uint16_t port);
-void isa_pnp_wake_csn(unsigned char id);
-unsigned char isa_pnp_read_config();
-void isa_pnp_init_key();
-
-/* these I/O ports are fixed */
-#define ISAPNP_ADDRESS 0x279
-#define ISAPNP_WRITE_DATA 0xA79
-/* this port varies, can change at runtime. caller is expected to fill this variable in */
-#define ISAPNP_READ_DATA isapnp_read_data
-
-#define isa_pnp_write_address(x) outp(ISAPNP_ADDRESS,(uint8_t)(x))
-#define isa_pnp_write_data(x) outp(ISAPNP_WRITE_DATA,(uint8_t)(x))
-#define isa_pnp_read_data(x) inp(ISAPNP_READ_DATA)
-
-extern uint16_t isapnp_read_data;
-extern uint8_t isapnp_probe_next_csn;
-
-int isa_pnp_read_irq(unsigned int i);
-int isa_pnp_read_dma(unsigned int i);
-int isa_pnp_read_io_resource(unsigned int i);
-uint8_t isa_pnp_read_data_register(uint8_t x);
-void isa_pnp_write_dma(unsigned int i,int dma);
-void isa_pnp_write_irq(unsigned int i,int irq);
-void isa_pnp_write_data_register(uint8_t x,uint8_t data);
-void isa_pnp_write_io_resource(unsigned int i,uint16_t port);
-void isa_pnp_write_irq_mode(unsigned int i,unsigned int im);
-
-#if TARGET_MSDOS == 32
-unsigned int isa_pnp_bios_number_of_sysdev_nodes(unsigned char far *a,unsigned int far *b);
-unsigned int isa_pnp_bios_get_sysdev_node(unsigned char far *a,unsigned char far *b,unsigned int c);
-unsigned int isa_pnp_bios_send_message(unsigned int msg);
-unsigned int isa_pnp_bios_get_static_alloc_resinfo(unsigned char far *a);
-unsigned int isa_pnp_bios_get_pnp_isa_cfg(unsigned char far *a);
-unsigned int isa_pnp_bios_get_escd_info(unsigned int far *min_escd_write_size,unsigned int far *escd_size,unsigned long far *nv_storage_base);
-#else
-/* we can call the real-mode subroutine directly, no translation */
-/* NTS: __cdecl follows the documented calling convention of this call i.e. Microsoft C++ style */
-# define isa_pnp_bios_number_of_sysdev_nodes(a,b) ((unsigned int (__cdecl far *)(int,unsigned char far *,unsigned int far *,unsigned int))isa_pnp_rm_call)(0,a,b,isa_pnp_info.rm_ent_data_segment)
-# define isa_pnp_bios_get_sysdev_node(a,b,c) ((unsigned int (__cdecl far *)(int,unsigned char far *,unsigned char far *,unsigned int,unsigned int))isa_pnp_rm_call)(1,a,b,c,isa_pnp_info.rm_ent_data_segment)
-# define isa_pnp_bios_send_message(a) ((unsigned int (__cdecl far *)(int,unsigned int,unsigned int))isa_pnp_rm_call)(4,a,isa_pnp_info.rm_ent_data_segment)
-# define isa_pnp_bios_get_static_alloc_resinfo(a) ((unsigned int (__cdecl far *)(int,unsigned char far *,unsigned int))isa_pnp_rm_call)(0x0A,a,isa_pnp_info.rm_ent_data_segment)
-# define isa_pnp_bios_get_pnp_isa_cfg(a) ((unsigned int (__cdecl far *)(int,unsigned char far *,unsigned int))isa_pnp_rm_call)(0x40,a,isa_pnp_info.rm_ent_data_segment)
-# define isa_pnp_bios_get_escd_info(a,b,c) ((unsigned int (__cdecl far *)(int,unsigned int far *,unsigned int far *,unsigned long far *,unsigned int))isa_pnp_rm_call)(0x41,a,b,c,isa_pnp_info.rm_ent_data_segment)
-#endif
-
-/* abc = ASCII letters of the alphabet
- * defg = hexadecimal digits */
-#define ISAPNP_ID(a,b,c,d,e,f,g) ( \
- (((a)&0x1FUL) << 2UL) | \
- (((b)&0x1FUL) >> 3UL) | \
- ((((b)&0x1FUL)&7UL) << 13UL) | \
- (((c)&0x1FUL) << 8UL) | \
- (((d)&0x0FUL) << 20UL) | \
- (((e)&0x0FUL) << 16UL) | \
- (((f)&0x0FUL) << 28UL) | \
- (((g)&0x0FUL) << 24UL) )
-
-#define ISAPNP_ID_FMATCH(id,a,b,c) (ISAPNP_ID(a,b,c,0,0,0,0) == ((id) & 0x0000FF7FUL))
-#define ISAPNP_ID_LMATCH(id,h) (ISAPNP_ID(0,0,0,(h>>12)&0xF,(h>>8)&0xF,(h>>4)&0xF,h&0xF) == ((id) & 0xFFFF0000UL))
-
-#endif /* __ISAPNP_ISAPNP_H */
-
+++ /dev/null
-This is a database of ISA PnP device IDs not covered by the device id database
-in the specification.
-
-TOS7009 DeviceType 07,80,00 Toshiba FIR infared port
-
-TOS700D DeviceType 07,00,02 Toshiba internal model (COM2)
-
-TOS7400 DeviceType 09,02,00 Toshiba PS/2 compatible mouse
- (the "diddle" in the middle of the keyboard)
-
-YMH0021 DeviceType 04,01,00 Yamaha OPL3-SA3 sound card
-
+++ /dev/null
-/* notes:
- *
- * Ancient Pentium Pro 200MHZ system:
- * - Real mode calling works perfectly.
- * - Protected mode interface crashed until we increased the stack size during
- * the call to 0x200 bytes (up from 0x100)
- * - PnP structures reveal some mystery devices at I/O ports 0x78-0x7F and 0x80...
- * what are they?
- * - Another mystery device at 0x290-0x297, what is it?
- * - BIOS settings allow you to specify a Plug & Play OS, and then, if Serial &
- * Parallel ports are set to "Auto", the BIOS says it doesn't configure them and
- * leaves it up to the OS to do it. Sure enough, according to the PnP info,
- * the serial ports show up as being disabled (IO base 0 len 0) waiting to be
- * set to one of the "possible resources" listed! Neat!
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <isapnp/isapnp.h>
-
-static unsigned char far devnode_raw[4096];
-
-int main(int argc,char **argv) {
- char tmp[129];
- int c,i;
-
- printf("ISA Plug & Play test program\n");
-
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!init_isa_pnp_bios()) {
- printf("Cannot init ISA PnP\n");
- return 1;
- }
- if (!find_isa_pnp_bios()) {
- printf("ISA PnP BIOS not found\n");
- return 1;
- }
-
- printf("Your BIOS provides a ISA PnP structure\n");
- printf(" version=0x%02X length=0x%02X control=0x%04X event_notify_flag @ 0x%08lX\n",
- isa_pnp_info.version, isa_pnp_info.length,
- isa_pnp_info.control, (unsigned long)isa_pnp_info.event_notify_flag_addr);
- printf(" realmode entry: %04X:%04X pm entry: %08lX + %04X oem device id=0x%08lX\n",
- isa_pnp_info.rm_ent_segment, isa_pnp_info.rm_ent_offset,
- isa_pnp_info.pm_ent_segment_base, isa_pnp_info.pm_ent_offset,
- isa_pnp_info.oem_device_id);
- printf(" data segment: realmode: %04X pm base: %08lX\n",
- isa_pnp_info.rm_ent_data_segment,
- (unsigned long)isa_pnp_info.pm_ent_data_segment_base);
- printf("WARNING: Part of the ISA PnP callback mechanism involves doing direct calls via\n");
- printf(" the entry pointers above. If your BIOS is badly written, this program\n");
- printf(" will crash when asked to do so.\n");
-#if TARGET_MSDOS == 32
- printf("This program runs in protected mode, and will use the protected mode interface.\n");
- printf("If you would like to use the real-mode interface, hit 'R' (Shift+R) now.\n");
- printf("Or hit 'W' (Shift+W) to enable 'Windows 95' mode.\n");
-#else
- printf("This program runs in real mode, and will use the real mode interface.\n");
-#endif
- while ((c=getch()) != 13) {
-#if TARGET_MSDOS == 32
- if (c == 'R') {
- if (isa_pnp_pm_use) {
- isa_pnp_pm_use = 0;
- isa_pnp_pm_win95_mode = 0;
- printf("\n\n**** I will use DPMI real-mode calling functions to call into PnP BIOS\n");
- }
- }
- else if (c == 'W') {
- if (isa_pnp_pm_win95_mode == 0) {
- isa_pnp_pm_win95_mode = 1;
- isa_pnp_pm_use = 1;
- printf("\n\n**** I will use DPMI prot-mode calling functions to call into PnP BIOS, Win95 style\n");
- }
- }
-
-#endif
- }
-
- int10_setmode(3);
- vga_bios_set_80x50_text();
-
- while (1) {
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
- vga_write("1. Get Number of System Device Nodes 2. Get statically alloc resource info\n");
- vga_write("3. ISA PnP configuration 4. Get ESCD information\n");
- vga_write("5. Send message 6. Init key and readback\n");
- vga_write("7. Readback SHIFT-7. Readback with detail\n");
- vga_write_sync();
-
- c = getch();
-again: if (c == 27) {
- break;
- }
- else if (c == '&') { /* SHIFT-7 = & */
- if (isapnp_read_data == 0 || isapnp_probe_next_csn == 0) {
- vga_write("I haven't yet asked your BIOS for the PnP read port.\n");
- vga_write("Hit ESC and then use command '3' to init the I/O port from the PnP BIOS\n");
- vga_write("Or type 'D' to reprogram and use the read port at I/O port 0x20F.\n");
- vga_write("Be aware that if you do, and then run the program later with BIOS settings,\n");
- vga_write("that the BIOS settings may not work (because we changed the RD_DATA port)\n");
- c = getch();
- if (c == '3') goto again;
- else if (c == 'D' || c == 'd') {
- isapnp_read_data = 0x20F;
- isapnp_probe_next_csn = 1;
- for (i=0;i < 256;i++) { /* I can't assume that I can write once and set all the cards */
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
- isa_pnp_set_read_data_port(0x20F);
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
- }
- }
- }
- else {
- struct isapnp_tag tag;
- unsigned char far *rsc;
- unsigned char data[256],cc;
- unsigned int ok=0,j,csn;
-
- vga_write("Listing all CSNs\n");
- csn = 1;
- do {
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
-
- ok = 0;
- if (!ok) {
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() == csn) ok = 1;
- }
-
- if (ok) {
- sprintf(tmp,"index %u:\n",csn);
- vga_write(tmp);
-
- isa_pnp_write_address(0x06); /* CSN */
- isa_pnp_write_data(csn);
-
- isa_pnp_write_address(0x07); /* logical dev index */
- isa_pnp_write_data(0); /* main dev */
-
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() != csn)
- vga_write(" - Warning, cannot readback CSN[1]\n");
-
- /* apparently doing this lets us read back the serial and vendor ID in addition to resource data */
- /* if we don't, then we only read back the resource data */
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
-
- for (j=0;j < 9;j++) data[j] = isa_pnp_read_config();
- sprintf(tmp,"assign %u: %02x %02x %02x %02x %02x %02x %02x %02x %02x ",csn,
- data[0],data[1],data[2],data[3],
- data[4],data[5],data[6],data[7],
- data[8]);
- vga_write(tmp);
-
- {
- isa_pnp_product_id_to_str(tmp,*((uint32_t*)data));
- vga_write(tmp);
- vga_write("\n");
- }
-
- do { /* parse until done */
- cc = isa_pnp_read_config();
- data[0] = cc;
- if (cc & 0x80) {
- unsigned int len;
- /* large tag; TODO */
- data[1] = isa_pnp_read_config();
- data[2] = isa_pnp_read_config();
- len = ((unsigned int)data[2] << 8) | (unsigned int)data[1];
- if ((len+3) > sizeof(data)) break;
- for (j=0;(unsigned char)j < len;j++) data[j+3] = isa_pnp_read_config();
- }
- else {
- unsigned char len = cc & 7;
- for (j=0;(unsigned char)j < len;j++) data[j+1] = isa_pnp_read_config();
- }
-
- rsc = data;
- if (!isapnp_read_tag(&rsc,data+sizeof(data),&tag))
- break;
- if (tag.tag == ISAPNP_TAG_END)
- break;
-
- sprintf(tmp,"%14s: ",isapnp_tag_str(tag.tag));
- if (tag.tag == ISAPNP_TAG_START_DEPENDENT_FUNCTION ||
- tag.tag == ISAPNP_TAG_END_DEPENDENT_FUNCTION)
- vga_write("---------------------");
- vga_write(tmp);
-
- switch (tag.tag) {
-/*---------------------------------------------------------------------------------*/
-case ISAPNP_TAG_PNP_VERSION: {
- struct isapnp_tag_pnp_version far *x = (struct isapnp_tag_pnp_version far*)tag.data;
- sprintf(tmp,"PnP v%u.%u Vendor=0x%02X",x->pnp>>4,x->pnp&0xF,x->vendor);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_COMPATIBLE_DEVICE_ID: {
- struct isapnp_tag_compatible_device_id far *x = (struct isapnp_tag_compatible_device_id far*)tag.data;
- isa_pnp_product_id_to_str(tmp,x->id);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_IRQ_FORMAT: {
- struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
- sprintf(tmp,"HTE=%u LTE=%u HTL=%u LTL=%u\n",x->hte,x->lte,x->htl,x->ltl);
- vga_write(tmp);
- vga_write(" IRQ: ");
- for (i=0;i < 16;i++) {
- if (x->irq_mask & (1U << (unsigned int)i)) {
- sprintf(tmp,"%u ",i);
- vga_write(tmp);
- }
- }
-} break;
-case ISAPNP_TAG_DMA_FORMAT: {
- struct isapnp_tag_dma_format far *x = (struct isapnp_tag_dma_format far*)tag.data;
- if (x->bus_master) vga_write("BusMaster ");
- if (x->byte_count) vga_write("ByteCount ");
- if (x->word_count) vga_write("WordCount ");
-
- sprintf(tmp,"Speed=%s xferPref=%s\n",isapnp_dma_speed_str[x->dma_speed],isapnp_dma_xfer_preference_str[x->xfer_preference]);
- vga_write(tmp);
-
- vga_write(" DMA channels: ");
- for (i=0;i < 8;i++) {
- if (x->dma_mask & (1U << (unsigned int)i)) {
- sprintf(tmp,"%u ",i);
- vga_write(tmp);
- }
- }
-} break;
-case ISAPNP_TAG_START_DEPENDENT_FUNCTION: {
- if (tag.len > 0) {
- struct isapnp_tag_start_dependent_function far *x =
- (struct isapnp_tag_start_dependent_function far*)tag.data;
- sprintf(tmp," Priority=%s",isapnp_sdf_priority_str(x->priority));
- vga_write(tmp);
- }
-} break;
-case ISAPNP_TAG_END_DEPENDENT_FUNCTION:
- break;
-case ISAPNP_TAG_IO_PORT: {
- struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
- sprintf(tmp,"Decode %ubit, range 0x%04X-0x%04X, align 0x%02X, length: 0x%02X",x->decode_16bit?16:10,
- x->min_range,x->max_range,x->alignment,x->length);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_FIXED_IO_PORT: {
- struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
- sprintf(tmp,"At %04X, length %02X",x->base,x->length);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_LOGICAL_DEVICE_ID: {
- struct isapnp_tag_logical_device_id far *x = (struct isapnp_tag_logical_device_id far*)tag.data;
- isa_pnp_product_id_to_str(tmp,x->logical_device_id);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_FIXED_MEMORY_LOCATION_32: {
- struct isapnp_tag_fixed_memory_location_32 far *x =
- (struct isapnp_tag_fixed_memory_location_32 far*)tag.data;
- sprintf(tmp,"%s %s %s %s %s %s\n",
- x->writeable ? "Writeable" : "Read only",
- x->cacheable ? "Cacheable" : "No-cache",
- x->support_hi_addr ? "Hi-addr" : "",
- isapnp_fml32_miosize_str[x->memory_io_size],
- x->shadowable ? "Shadowable" : "No-shadow",
- x->expansion_rom ? "Expansion ROM" : "RAM");
- vga_write(tmp);
- sprintf(tmp," Base 0x%08lX len 0x%08lX",
- (unsigned long)x->base, (unsigned long)x->length);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_ANSI_ID_STRING: {
- i = tag.len;
- if ((i+1) > sizeof(tmp)) i = sizeof(tmp) - 1;
- if (i != 0) _fmemcpy(tmp,tag.data,i);
- tmp[i] = 0;
- vga_write(tmp);
-} break;
-default:
- vga_write("FIXME: not implemented");
-break;
-/*---------------------------------------------------------------------------------*/
- };
-
- vga_write("\n");
- } while (1);
-
- while (getch() != 13);
- }
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
-
- csn++;
- } while (csn < 255);
- while (getch() != 13);
- }
- }
- else if (c == '7') {
- if (isapnp_read_data == 0 || isapnp_probe_next_csn == 0) {
- vga_write("I haven't yet asked your BIOS for the PnP read port.\n");
- vga_write("Hit ESC and then use command '3' to init the I/O port from the PnP BIOS\n");
- vga_write("Or type 'D' to reprogram and use the read port at I/O port 0x20F.\n");
- vga_write("Be aware that if you do, and then run the program later with BIOS settings,\n");
- vga_write("that the BIOS settings may not work (because we changed the RD_DATA port)\n");
- c = getch();
- if (c == '3') goto again;
- else if (c == 'D' || c == 'd') {
- isapnp_read_data = 0x20F;
- isapnp_probe_next_csn = 1;
- for (i=0;i < 256;i++) { /* I can't assume that I can write once and set all the cards */
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
- isa_pnp_set_read_data_port(0x20F);
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
- }
- }
- }
- else {
- unsigned char data[9];
- unsigned int i,ok=0,j;
-
- vga_write("Listing all CSNs\n");
- i = 1;
- do {
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
-
- ok = 0;
- if (!ok) {
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() == i) ok = 1;
- }
-
- if (ok) {
- sprintf(tmp,"index %u:\n",i);
- vga_write(tmp);
-
- isa_pnp_write_address(0x06); /* CSN */
- isa_pnp_write_data(i);
-
- isa_pnp_write_address(0x07); /* logical dev index */
- isa_pnp_write_data(0); /* main dev */
-
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() != i)
- vga_write(" - Warning, cannot readback CSN[1]\n");
-
- /* apparently doing this lets us read back the serial and vendor ID in addition to resource data */
- /* if we don't, then we only read back the resource data */
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
-
- for (j=0;j < 9;j++) data[j] = isa_pnp_read_config();
- sprintf(tmp,"assign %u: %02x %02x %02x %02x %02x %02x %02x %02x %02x ",i,
- data[0],data[1],data[2],data[3],
- data[4],data[5],data[6],data[7],
- data[8]);
- vga_write(tmp);
-
- {
- isa_pnp_product_id_to_str(tmp,*((uint32_t*)data));
- vga_write(tmp);
- vga_write("\n");
- }
-
- /* dump configuration bytes to prove we can read it */
- /* NTS: the configuration data covers ALL logical devices, you will get the same
- * data no matter what logical dev index you use */
- vga_write(" - Config: ");
- for (j=0;j < 22;j++) {
- data[0] = isa_pnp_read_config();
- sprintf(tmp,"%02x ",data[0]);
- vga_write(tmp);
- }
- vga_write("\n");
-
- while (getch() != 13);
- }
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
-
- i++;
- } while (i < 255);
- while (getch() != 13);
- }
- }
- else if (c == '6') {
- if (isapnp_read_data == 0 || isapnp_probe_next_csn == 0) {
- vga_write("I haven't yet asked your BIOS for the PnP read port.\n");
- vga_write("Hit ESC and then use command '3' to init the I/O port from the PnP BIOS\n");
- vga_write("Or type 'D' to reprogram and use the read port at I/O port 0x20F.\n");
- vga_write("Be aware that if you do, and then run the program later with BIOS settings,\n");
- vga_write("that the BIOS settings may not work (because we changed the RD_DATA port)\n");
- c = getch();
- if (c == '3') goto again;
- else if (c == 'D' || c == 'd') {
- isapnp_read_data = 0x20F;
- isapnp_probe_next_csn = 1;
-
- for (i=0;i < 256;i++) {
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
- isa_pnp_write_address(0x00); /* RD_DATA port */
- isa_pnp_write_data(0x20F >> 2);
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
- }
- }
- }
- else {
- unsigned char data[9],cc;
- unsigned int i,ok=0,j;
-
- vga_write("ISA PnP key (reset CSNs)\n");
- isa_pnp_init_key();
- for (i=1;i < 256;i++) { /* FIXME: "a write to bit 2 causes all CARDS to reset their CSNs to zero" (or is that all log devs)? */
- isa_pnp_wake_csn(i);
- isa_pnp_write_address(0x02);
- isa_pnp_write_data(0x04); /* reset CSN */
- }
- for (i=1;i < 256;i++) { /* FIXME: "a write to bit 1 causes all CARDS to enter wait for key" (or is that all log devs)? */
- isa_pnp_wake_csn(i);
- isa_pnp_write_address(0x02);
- isa_pnp_write_data(0x02); /* wait for key state */
- }
-
- /* FIXME: This works in Microsoft Virtual PC, but re-selecting the dev later doesn't work? */
- vga_write("Reprogramming all CSNs\n");
- i = 1;
- do {
- isa_pnp_init_key();
- isa_pnp_wake_csn(0); /* any card with CSN=0 */
- ok = isa_pnp_init_key_readback(data);
- if (ok) {
- sprintf(tmp,"assign %u: %02x %02x %02x %02x %02x %02x %02x %02x %02x ",i,
- data[0],data[1],data[2],data[3],
- data[4],data[5],data[6],data[7],
- data[8]);
- vga_write(tmp);
-
- {
- isa_pnp_product_id_to_str(tmp,*((uint32_t*)data));
- vga_write(tmp);
- vga_write("\n");
- }
-
- isa_pnp_write_address(0x06); /* CSN */
- isa_pnp_write_data(i);
-
- isa_pnp_write_address(0x07); /* logical dev index */
- isa_pnp_write_data(0); /* main dev */
-
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() != i)
- vga_write(" - Warning, cannot readback CSN[1]\n");
-
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
-
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() != i)
- vga_write(" - Warning, cannot readback CSN[1]\n");
-
- /* read an discard the vendor, serial number data */
- for (j=0;j < 9;j++) {
- cc = isa_pnp_read_config();
- if (cc != data[j]) {
- vga_write(" - WARNING: Despite key and CSN device does not re-send vendor_id and serial and checksum\n");
- break;
- }
- }
-
- /* dump configuration bytes to prove we can read it */
- vga_write(" - Config: ");
- for (j=0;j < 22;j++) {
- data[0] = isa_pnp_read_config();
- sprintf(tmp,"%02x ",data[0]);
- vga_write(tmp);
- }
- vga_write("\n");
-
- i++;
- while (getch() != 13);
- }
- else if (i == 1) { /* if this happened on the first attempt, then the RD_DATA port is conflicting */
- vga_write("WARNING: Failure to read PnP card & configuration on first pass. The RD_DATA\n");
- vga_write(" port may be conflicting with another device on the ISA bus!\n");
-
- sprintf(tmp,"got: %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- data[0],data[1],data[2],data[3],
- data[4],data[5],data[6],data[7],
- data[8]);
- vga_write(tmp);
-
- }
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
- } while (i < 255 && ok);
- while (getch() != 13);
- }
- }
- else if (c == '5') {
- unsigned int ret_ax=0;
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
- vga_write("1. Power off 2. PnP OS Active 3. PnP OS Inactive\n");
- c = getch();
-
- if (c == '1') {
- ret_ax = isa_pnp_bios_send_message(0x0041); /* POWER_OFF */
- }
- else if (c == '2') {
- ret_ax = isa_pnp_bios_send_message(0x0042); /* PNP_OS_ACTIVE */
- }
- else if (c == '3') {
- ret_ax = isa_pnp_bios_send_message(0x0043); /* PNP_OS_INACTIVE */
- }
-
- vga_write("Result: ");
- sprintf(tmp,"AX=%04x\n",ret_ax);
- vga_write(tmp);
- while (getch() != 13);
- }
- else if (c == '4') {
- unsigned int min_escd_write=0,escd_size=0;
- unsigned long nv_base=0;
- unsigned int ret_ax;
-
- vga_write("Calling...");
- vga_write_sync();
-
- ret_ax = isa_pnp_bios_get_escd_info(&min_escd_write,&escd_size,&nv_base);
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
-
- vga_write("BIOS call results:\n");
- sprintf(tmp," return value (AX): 0x%04X\n",ret_ax);
- vga_write(tmp);
- vga_write("\n");
-
- if (ret_ax == 0) {
- sprintf(tmp," Min ESCD write: %u\n",min_escd_write);
- vga_write(tmp);
-
- sprintf(tmp," ESCD size: %u\n",escd_size);
- vga_write(tmp);
-
- sprintf(tmp," NV Base: 0x%lX\n",nv_base);
- vga_write(tmp);
- }
-
- /* TODO: Find an emulator or actual PC where this function is implemented */
-
- vga_write_sync();
- while (getch() != 13);
- }
- else if (c == '3') {
- struct isapnp_pnp_isa_cfg far *nfo;
- unsigned int ret_ax;
- int c;
-
- vga_write("Calling...");
- vga_write_sync();
-
- _fmemset(devnode_raw,0,sizeof(*nfo));
- ret_ax = isa_pnp_bios_get_pnp_isa_cfg(devnode_raw);
- nfo = (struct isapnp_pnp_isa_cfg far*)devnode_raw;
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
-
- vga_write("BIOS call results:\n");
- sprintf(tmp," return value (AX): 0x%04X\n",ret_ax);
- vga_write(tmp);
- vga_write("\n");
-
- if (ret_ax == 0) {
- sprintf(tmp," Struct revision: %u\n",nfo->revision);
- vga_write(tmp);
- if (nfo->revision == 1) {
- if (isapnp_probe_next_csn < nfo->total_csn)
- isapnp_probe_next_csn = nfo->total_csn;
-
- sprintf(tmp," Total CSNs: %u\n",nfo->total_csn);
- vga_write(tmp);
-
- isapnp_read_data = nfo->isa_pnp_port;
- sprintf(tmp," ISA PnP port: 0x%X\n",nfo->isa_pnp_port);
- vga_write(tmp);
-
- }
- }
-
- vga_write("Press 'D' to set the RD_DATA port to BIOS value (if you changed it earlier)\n");
- vga_write("Press '8' to set the RD_DATA port to 0x20B\n");
- vga_write_sync();
- while ((c=getch()) != 13) {
- if (c == '8') {
- if (isapnp_read_data != 0) {
- vga_write("Programming BIOS value into RD_DATA\n");
- for (i=0;i < 256;i++) { /* I can't assume that I can write once and set all the cards */
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
- isa_pnp_set_read_data_port(isapnp_read_data = 0x20B);
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
- }
- }
- }
- else if (c == 'D') {
- if (isapnp_read_data != 0) {
- vga_write("Programming BIOS value into RD_DATA\n");
- for (i=0;i < 256;i++) { /* I can't assume that I can write once and set all the cards */
- isa_pnp_init_key();
- isa_pnp_wake_csn(i);
- isa_pnp_set_read_data_port(isapnp_read_data);
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
- }
- }
- }
- }
- }
- else if (c == '2') {
- unsigned int ret_ax;
-
- vga_write("Calling...");
- vga_write_sync();
-
- ret_ax = isa_pnp_bios_get_static_alloc_resinfo(devnode_raw);
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
-
- vga_write("BIOS call results:\n");
- sprintf(tmp," return value (AX): 0x%04X\n",ret_ax);
- vga_write(tmp);
- vga_write("\n");
-
- /* TODO: Find an emulator or actual PC where this function is implemented */
-
- vga_write_sync();
- while (getch() != 13);
- }
- else if (c == '1') {
- struct isa_pnp_device_node far *devn;
- unsigned char numnodes=0xFF;
- unsigned int ret_ax,nodesize=0xFFFF;
- struct isapnp_tag tag;
- unsigned char node;
-
- vga_write("Calling...");
- vga_write_sync();
-
- ret_ax = isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize);
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
-
- vga_write("BIOS call results:\n");
- sprintf(tmp," return value (AX): 0x%04X\n",ret_ax);
- vga_write(tmp);
- sprintf(tmp," NumNodes: 0x%02X\n",numnodes);
- vga_write(tmp);
- sprintf(tmp," NodeSize: 0x%04X\n",nodesize);
- vga_write(tmp);
- vga_write("\n");
-
- if (ret_ax != 0 || numnodes == 0xFF || nodesize > sizeof(devnode_raw)) {
- vga_write("Nothing to see here. Hit ENTER to continue\n");
- vga_write_sync();
- while (getch() != 13);
- }
- else {
- vga_write("Ok... whew! Your BIOS is obviously not crap, so let's move on...\n\n");
- vga_write("Would you like me to enumerate each node? [yn] ");
- vga_write_sync();
-
- if (getch() != 'y')
- continue;
-
- /* NTS: How nodes are enumerated in the PnP BIOS: set node = 0, pass address of node
- * to BIOS. BIOS, if it returns node information, will also overwrite node with
- * the node number of the next node, or with 0xFF if this is the last one.
- * On the last one, stop enumerating. */
- for (node=0;node != 0xFF;) {
- const char *dev_class = NULL,*dev_type = NULL,*dev_stype = NULL,*dev_itype = NULL;
- char dev_product[256] = {0};
- unsigned char far *rsc;
- char pnpid[8];
- int liter;
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
-
- sprintf(tmp,"Node %02X ",node);
- vga_write(tmp);
- vga_write_sync();
-
- /* apparently, start with 0. call updates node to
- * next node number, or 0xFF to signify end */
- ret_ax = isa_pnp_bios_get_sysdev_node(&node,devnode_raw,
- ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW);
-
- if (ret_ax != 0)
- break;
-
- devn = (struct isa_pnp_device_node far*)devnode_raw;
- sprintf(tmp," -> %02X: AX=%04X\n",node,ret_ax);
- vga_write(tmp);
-
- isa_pnp_product_id_to_str(pnpid,devn->product_id);
- sprintf(tmp,"Size=%u handle=%02X product_id=%08lX (%s) DeviceType=%02X,%02X,%02X\n",
- devn->size,devn->handle,
- (unsigned long)devn->product_id,pnpid,
- (unsigned char)devn->type_code[0],
- (unsigned char)devn->type_code[1],
- (unsigned char)devn->type_code[2]);
- vga_write(tmp);
-
- dev_type = isa_pnp_device_type(devn->type_code,&dev_stype,&dev_itype);
- dev_class = isa_pnp_device_category(devn->product_id);
- isa_pnp_device_description(dev_product,devn->product_id);
-
- if (dev_class != NULL) {
- vga_write("Device category: ");
- vga_write(dev_class);
- vga_write("\n");
- }
-
- if (dev_product[0] != 0) {
- vga_write("Device descript: ");
- vga_write(dev_product);
- vga_write("\n");
- }
-
- if (dev_type != NULL) {
- vga_write("Device: ");
- vga_write(dev_type);
- vga_write("\n");
- }
- if (dev_stype != NULL) {
- vga_write(" ");
- vga_write(dev_stype);
- vga_write("\n");
- }
- if (dev_itype != NULL) {
- vga_write(" ");
- vga_write(dev_itype);
- vga_write("\n");
- }
-
- sprintf(tmp,"Attributes (%04X): \n",devn->attributes); vga_write(tmp);
- if (devn->attributes & ISAPNP_DEV_ATTR_CANT_DISABLE)
- vga_write(" - Device cannot be disabled\n");
- if (devn->attributes & ISAPNP_DEV_ATTR_CANT_CONFIGURE)
- vga_write(" - Device is not configurable\n");
- if (devn->attributes & ISAPNP_DEV_ATTR_CAN_BE_PRIMARY_OUTPUT)
- vga_write(" - Device is capable of being primary output device\n");
- if (devn->attributes & ISAPNP_DEV_ATTR_CAN_BE_PRIMARY_INPUT)
- vga_write(" - Device is capable of being primary input device\n");
- if (devn->attributes & ISAPNP_DEV_ATTR_CAN_BE_PRIMARY_IPL)
- vga_write(" - Device is capable of being primary IPL device\n");
- if (devn->attributes & ISAPNP_DEV_ATTR_DOCKING_STATION_DEVICE)
- vga_write(" - Device is a docking station device\n");
- if (devn->attributes & ISAPNP_DEV_ATTR_REMOVEABLE_STATION_DEVICE)
- vga_write(" - Device is a removeable station device\n");
-
- switch (ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE(devn->attributes)) {
- case ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE_ONLY_NEXT_BOOT:
- vga_write(" - Device can only be configured for next boot\n"); break;
- case ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE_AT_RUNTIME:
- vga_write(" - Device can be configured at runtime\n"); break;
- case ISAPNP_DEV_ATTR_WHEN_CONFIGURABLE_ONLY_RUNTIME:
- vga_write(" - Device can only be configured at runtime\n"); break;
- };
-
- rsc = devnode_raw + sizeof(*devn);
- for (i=sizeof(*devn);i < devn->size;i++) {
- if (vga_pos_x >= (vga_width-2)) vga_write("\n");
- sprintf(tmp,"%02X ",devnode_raw[i]);
- vga_write(tmp);
- }
- vga_write("\n");
- vga_write_sync();
- while ((c=getch()) != 13) {
- if (c == 27) break;
- }
- if (c == 27)
- break;
-
- /* the three configuration blocks are in this one buffer, one after the other */
- for (liter=0;liter <= 2;liter++) {
- if (!isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag))
- break;
- if (tag.tag == ISAPNP_TAG_END)
- continue;
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
-
- vga_write(isapnp_config_block_str[liter]);
- vga_write(" resource configuration block\n");
- vga_write("\n");
-
- do {
- if (tag.tag == ISAPNP_TAG_END) /* end tag */
- break;
-
- sprintf(tmp,"%14s: ",isapnp_tag_str(tag.tag));
- if (tag.tag == ISAPNP_TAG_START_DEPENDENT_FUNCTION ||
- tag.tag == ISAPNP_TAG_END_DEPENDENT_FUNCTION)
- vga_write("---------------------");
- vga_write(tmp);
-
- switch (tag.tag) {
-/*---------------------------------------------------------------------------------*/
-case ISAPNP_TAG_PNP_VERSION: {
- struct isapnp_tag_pnp_version far *x = (struct isapnp_tag_pnp_version far*)tag.data;
- sprintf(tmp,"PnP v%u.%u Vendor=0x%02X",x->pnp>>4,x->pnp&0xF,x->vendor);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_COMPATIBLE_DEVICE_ID: {
- struct isapnp_tag_compatible_device_id far *x = (struct isapnp_tag_compatible_device_id far*)tag.data;
- isa_pnp_product_id_to_str(tmp,x->id);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_IRQ_FORMAT: {
- struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
- sprintf(tmp,"HTE=%u LTE=%u HTL=%u LTL=%u\n",x->hte,x->lte,x->htl,x->ltl);
- vga_write(tmp);
- vga_write(" IRQ: ");
- for (i=0;i < 16;i++) {
- if (x->irq_mask & (1U << (unsigned int)i)) {
- sprintf(tmp,"%u ",i);
- vga_write(tmp);
- }
- }
-} break;
-case ISAPNP_TAG_DMA_FORMAT: {
- struct isapnp_tag_dma_format far *x = (struct isapnp_tag_dma_format far*)tag.data;
- if (x->bus_master) vga_write("BusMaster ");
- if (x->byte_count) vga_write("ByteCount ");
- if (x->word_count) vga_write("WordCount ");
-
- sprintf(tmp,"Speed=%s xferPref=%s\n",isapnp_dma_speed_str[x->dma_speed],isapnp_dma_xfer_preference_str[x->xfer_preference]);
- vga_write(tmp);
-
- vga_write(" DMA channels: ");
- for (i=0;i < 8;i++) {
- if (x->dma_mask & (1U << (unsigned int)i)) {
- sprintf(tmp,"%u ",i);
- vga_write(tmp);
- }
- }
-} break;
-case ISAPNP_TAG_START_DEPENDENT_FUNCTION: {
- if (tag.len > 0) {
- struct isapnp_tag_start_dependent_function far *x =
- (struct isapnp_tag_start_dependent_function far*)tag.data;
- sprintf(tmp," Priority=%s",isapnp_sdf_priority_str(x->priority));
- vga_write(tmp);
- }
-} break;
-case ISAPNP_TAG_END_DEPENDENT_FUNCTION:
- break;
-case ISAPNP_TAG_IO_PORT: {
- struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
- sprintf(tmp,"Decode %ubit, range 0x%04X-0x%04X, align 0x%02X, length: 0x%02X",x->decode_16bit?16:10,
- x->min_range,x->max_range,x->alignment,x->length);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_FIXED_IO_PORT: {
- struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
- sprintf(tmp,"At %04X, length %02X",x->base,x->length);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_LOGICAL_DEVICE_ID: {
- struct isapnp_tag_logical_device_id far *x = (struct isapnp_tag_logical_device_id far*)tag.data;
- isa_pnp_product_id_to_str(tmp,x->logical_device_id);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_FIXED_MEMORY_LOCATION_32: {
- struct isapnp_tag_fixed_memory_location_32 far *x =
- (struct isapnp_tag_fixed_memory_location_32 far*)tag.data;
- sprintf(tmp,"%s %s %s %s %s %s\n",
- x->writeable ? "Writeable" : "Read only",
- x->cacheable ? "Cacheable" : "No-cache",
- x->support_hi_addr ? "Hi-addr" : "",
- isapnp_fml32_miosize_str[x->memory_io_size],
- x->shadowable ? "Shadowable" : "No-shadow",
- x->expansion_rom ? "Expansion ROM" : "RAM");
- vga_write(tmp);
- sprintf(tmp," Base 0x%08lX len 0x%08lX",
- (unsigned long)x->base, (unsigned long)x->length);
- vga_write(tmp);
-} break;
-case ISAPNP_TAG_ANSI_ID_STRING: {
- i = tag.len;
- if ((i+1) > sizeof(tmp)) i = sizeof(tmp) - 1;
- if (i != 0) _fmemcpy(tmp,tag.data,i);
- tmp[i] = 0;
- vga_write(tmp);
-} break;
-default:
- vga_write("FIXME: not implemented");
-break;
-/*---------------------------------------------------------------------------------*/
- };
-
- vga_write("\n");
- } while (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag));
-
- vga_write_sync();
- while ((c=getch()) != 13) {
- if (c == 27) {
- liter = 2;
- break;
- }
- }
-
- if (c == 27)
- break;
- }
- }
-
- vga_write_color(0x07);
- vga_clear();
- vga_moveto(0,0);
- vga_write("That's it for nodes.");
- vga_write_sync();
- while ((c=getch()) != 13) {
- if (c == 27) break;
- }
- }
- }
- }
-
- int10_setmode(3);
- free_isa_pnp_bios();
-
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# configuration file generated by Bochs
-plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, gameport=1, iodebug=1, pci_ide=1, acpi=1, ioapic=1
-config_interface: textconfig
-display_library: x
-memory: host=64, guest=1024
-romimage: file="/usr/share/bochs/BIOS-bochs-latest"
-vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
-boot: floppy
-floppy_bootsig_check: disabled=0
-floppya: type=1_44, 1_44="win95.dsk", status=inserted, write_protected=0
-# no floppyb
-ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
-ata0-master: type=disk, mode=flat, translation=auto, path="hdd.dsk", cylinders=16, heads=16, spt=63, biosdetect=auto, model="Generic 1234"
-ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
-ata2: enabled=0
-ata3: enabled=0
-parport1: enabled=1, file=""
-parport2: enabled=0
-com1: enabled=1, mode=null, dev=""
-com2: enabled=0
-com3: enabled=0
-com4: enabled=0
-usb_uhci: enabled=0
-usb_ohci: enabled=0
-i440fxsupport: enabled=1
-vga_update_interval: 50000
-vga: extension=vbe
-cpu: count=1, ips=4000000, reset_on_triple_fault=1, ignore_bad_msrs=1
-print_timestamps: enabled=0
-debugger_log: -
-magic_break: enabled=0
-port_e9_hack: enabled=0
-private_colormap: enabled=0
-clock: sync=none, time0=local
-# no cmosimage
-ne2k: enabled=0
-pnic: enabled=0
-sb16: enabled=0
-# no loader
-log: -
-logprefix: %t%e%d
-panic: action=ask
-error: action=report
-info: action=report
-debug: action=ignore
-keyboard_type: mf
-keyboard_serial_delay: 250
-keyboard_paste_delay: 100000
-keyboard_mapping: enabled=0, map=
-user_shortcut: keys=none
-mouse: enabled=0, type=ps2, toggle=ctrl+mbutton
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_LLMEM_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-AFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NASMFLAGS_THIS =
-
-# NTS: CPU functions here are to be moved at some point to the cpu library!
-C_SOURCE = cpu.c
-OBJS = $(SUBDIR)$(HPS)llmemasm.obj $(SUBDIR)$(HPS)llmem.obj
-
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_LLMEM_LIB): $(OBJS)
- wlib -q -b -c $(HW_LLMEM_LIB) -+$(SUBDIR)$(HPS)llmemasm.obj -+$(SUBDIR)$(HPS)llmem.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-lib: $(HW_LLMEM_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_LLMEM_LIB) $(HW_LLMEM_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj library $(HW_LLMEM_LIB) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_CPU_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-DEVICE=HIMEM.SYS /testmem:off\r
-DEVICE=EMM386.EXE\r
-FILES=30\r
-BUFFERS=20\r
-\r
-REM DEVICE=dos\cd1.SYS /D:banana\r
-\r
-rem DEVICE=cd1.SYS /D:banana /P:1f0,14\r
-rem DEVICE=cd1.SYS /D:banana /P:170,15\r
-rem DEVICE=cd1.SYS /D:banana /P:170,10\r
-rem DEVICE=cd1.SYS /D:banana /P:1e8,12\r
-rem DEVICE=cd1.SYS /D:banana /P:1e8,11\r
-rem DEVICE=cd1.SYS /D:banana /P:168,10\r
-rem DEVICE=cd1.SYS /D:banana /P:168,9\r
-\r
-LASTDRIVE=Z\r
+++ /dev/null
-/* NOTES:
- * This code works perfectly on most test systems I have.
- * Some systems do provide interesting insight though when they do fail.
- *
- * Test: Oracle VirtualBox 4.1.8 with 64-bit guest and AMD VT-X acceleration:
- * Result: VirtualBox reports PAE and PSE, and 32-bit test program works perfectly.
- * The 16-bit real mode builds however, cause the virtual machine to hang
- * when attempting to use the PSE method. This hang does not occur when
- * AMD VT-x is disabled.
- *
- * Test: Dell netbook with Intel Atom processor
- * Result: Processor reports via CPUID that it has 32-bit linear and 32-bit physical
- * address space. And it means it. The minute this program steps beyond 4GB,
- * the CPU faults and the system resets. This is true regardless of whether
- * the 16-bit real mode or the 32-bit protected mode version is used. This is
- * true whether you use PSE-36 or PAE.
- *
- * So apparently, they don't do what 386/486/pentium systems USED to do and just
- * silently wrap the addresses, eh?
- *
- * That means this code should make use of the "extended CPUID" to read those
- * limits and then llmemcpy() should enforce them. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/llmem/llmem.h>
-#include <hw/cpu/cpuidext.h>
-#include <hw/dos/doswin.h>
-
-unsigned char llmem_probed = 0;
-unsigned char llmem_meth_pse = 0;
-unsigned char llmem_meth_pae = 0;
-unsigned char llmem_available = 0;
-uint64_t llmem_phys_limit = 0ULL;
-uint64_t llmem_pse_limit = 0ULL;
-const char* llmem_reason = NULL; /* non-NULL if probing failed */
-
-/* page tables created on-demand for the llmemcpy() function.
- * they are created once and retained so llmemcpy() is faster.
- * they will be freed and recreated if we have to do so.
- * you can do llmemcpy_free() to free up memory */
-volatile void FAR* llmemcpy_pagetables = NULL;
-volatile void FAR* llmemcpy_pagetables_raw = NULL;
-size_t llmemcpy_pagetables_size = 0;
-unsigned char llmemcpy_pagefmt = 0;
-#if TARGET_MSDOS == 16
-uint32_t far* llmemcpy_gdt = NULL;
-uint16_t llmemcpy_gdtr[4];
-uint16_t llmemcpy_idtr[4];
-uint32_t llmemcpy_vcpi[0x20];
-uint32_t llmemcpy_vcpi_return[2];
-uint8_t llmemcpy_vcpi_tss[108];
-#endif
-
-#if TARGET_MSDOS == 16
-void llmem_memcpy_16_inner_pae(void);
-void llmem_memcpy_16_inner_pse(void);
-void __cdecl llmem_memcpy_16_inner_pae_vcpi(uint32_t dst,uint32_t src,uint32_t cpy);
-void __cdecl llmem_memcpy_16_inner_pse_vcpi(uint32_t dst,uint32_t src,uint32_t cpy);
-#endif
-
-int llmem_init() {
- if (!llmem_probed) {
- llmem_probed = 1;
- if (cpu_basic_level < 0) cpu_probe();
- if (cpu_basic_level < 4) {
- llmem_reason = "Requires a 486 or higher processor";
- return 0; /* 486 or higher */
- }
-
- if (!(cpu_flags & CPU_FLAG_CPUID)) {
- llmem_reason = "Requires CPUID";
- return 0; /* The CPU must support CPUID */
- }
-
- if (!(cpu_flags & CPU_FLAG_CPUID_EXT) || cpu_cpuid_ext_info == NULL)
- cpu_extended_cpuid_probe();
-
- probe_dos();
- detect_windows();
-#if TARGET_MSDOS == 32
- probe_dpmi();
-#endif
- probe_vcpi();
-
-#if TARGET_MSDOS == 32
- /* if we can't use the LTP library, then we can't do the trick */
- if (!dos_ltp_probe()) {
- llmem_reason = "Runtime environment does not permit knowing physical<->linear page table translation";
- return 0;
- }
-#endif
-
- /* if we're running under Windows, then we definitely can't do the trick */
- if (windows_mode != WINDOWS_NONE) {
- llmem_reason = "LLMEM cannot operate from within Windows";
- return 0;
- }
-
-#if TARGET_MSDOS == 16
- /* 16-bit real mode: If we're running in virtual 8086 mode, and VCPI is not available, then we can't do it */
- if (cpu_v86_active && !vcpi_present) {
- llmem_reason = "16-bit LLMEM cannot operate while virtual 8086 mode is active (no VCPI services available)";
- return 0;
- }
-#endif
-
- /* decide the PSE access limit. Older Pentium III systems are 36 bit limited.
- * Newer AMD64 systems allow up to 40 bits. */
- llmem_pse_limit = 0xFFFFFFFFFULL; /* 36 bits by default */
- if (cpu_cpuid_ext_info != NULL && cpu_cpuid_ext_info->features.a.raw[3] & (1UL << 29UL))
- llmem_pse_limit = 0xFFFFFFFFFFULL; /* 40 bits if CPU supports 64-bit long mode */
-
- /* by default, assume the physical limit is the PSE limit */
- llmem_phys_limit = llmem_pse_limit;
-
- /* but if CPUID provides more information, then use it.
- * this is important to know, modern CPUs will actually treat any attempt to read past it's physical memory limit as a fault (or at least Intel chips do).
- * it's not like the 386/486/Pentium systems of old that silently wrapped addresses */
- if (cpu_cpuid_ext_info_has_longmode) {
- unsigned char c = (unsigned char)(cpu_cpuid_ext_info->longmode.a.raw[0] & 0xFFUL);
- if (c < 32) c = 32;
- llmem_phys_limit = (1ULL << ((uint64_t)c)) - 1ULL;
- }
-
- /* PSE & PSE-36 support */
- if ( /*PSE*/(cpu_cpuid_features.a.raw[2/*EDX*/]&(1UL<<3UL)) &&
- /*PSE-36*/(cpu_cpuid_features.a.raw[2/*EDX*/]&(1UL<<17UL)))
- llmem_meth_pse = 1;
-
- /* PAE support */
- if (/*PAE*/(cpu_cpuid_features.a.raw[2/*EDX*/]&(1UL<<6UL)))
- llmem_meth_pae = 1;
-
- if (llmem_meth_pse || llmem_meth_pae) {
- llmem_available = 1;
- }
- else {
- llmem_reason = "LLMEM requires that the CPU support PSE or PAE";
- llmem_available = 0;
- }
- }
-
- return llmem_available;
-}
-
-/* returns 0xFFFFFFFFFFFFFFFF if unmappable */
-#if TARGET_MSDOS == 16
-uint64_t llmem_ptr2ofs(unsigned char far *ptr) {
- uint16_t seg = FP_SEG(ptr),ofs = FP_OFF(ptr);
-
- if (cpu_v86_active) {
- uint32_t vofs = ((uint32_t)seg << 4UL) + (uint32_t)ofs,pofs;
- if (vcpi_present) {
- pofs = dos_linear_to_phys_vcpi(vofs>>12UL);
- if (pofs != 0xFFFFFFFFUL) return pofs + (vofs & 0xFFFUL);
- }
- return (0xFFFFFFFFFFFFFFFFULL);
- }
-
- return (((uint64_t)seg << 4ULL) + (uint64_t)ofs);
-}
-
-/* if copying from your virtual address space (using llmem_ptr2ofs) the maximum
- * amount of data you should copy before translating again. */
-uint32_t llmem_virt_phys_recommended_copy_size() {
- if (cpu_v86_active)
- return 0x1000UL; /* Paging enabled. EMM386.EXE might remap some memory. Max copy 4KB */
-
- return 0x100000UL; /* 1MB */
-}
-#else
-uint64_t llmem_ptr2ofs(unsigned char *ptr) {
- if (dos_ltp_info.paging)
- return dos_linear_to_phys((uint32_t)ptr);
-
- return ((size_t)ptr);
-}
-
-/* if copying from your virtual address space (using llmem_ptr2ofs) the maximum
- * amount of data you should copy before translating again. */
-uint32_t llmem_virt_phys_recommended_copy_size() {
- if (dos_ltp_info.paging)
- return 0x1000UL; /* Paging enabled. Max copy 4KB */
-
- return 0x100000UL; /* 1MB */
-}
-#endif
-
-void llmemcpy_free() {
- if (llmemcpy_pagetables) {
-#if TARGET_MSDOS == 16
- _ffree((void FAR*)llmemcpy_pagetables_raw);
-#else
- free((void*)llmemcpy_pagetables_raw);
-#endif
- llmemcpy_pagetables_size = 0;
- llmemcpy_pagetables_raw = NULL;
- llmemcpy_pagetables = NULL;
- }
-#if TARGET_MSDOS == 16
- if (llmemcpy_gdt) {
- _ffree(llmemcpy_gdt);
- llmemcpy_gdt = NULL;
- }
-#endif
-}
-
-int llmemcpy_alloc(size_t len,unsigned char typ) {
- if (len == 0)
- return 0;
- if (llmemcpy_pagetables != NULL && len <= llmemcpy_pagetables_size && typ == llmemcpy_pagefmt)
- return 1;
-
- llmemcpy_free();
-
- llmemcpy_pagetables_size = (len + 0xFFFUL) & (~0xFFFUL);
-#if TARGET_MSDOS == 16
- llmemcpy_pagetables_raw = _fmalloc(llmemcpy_pagetables_size + 4096UL + 32UL);
-#else
- llmemcpy_pagetables_raw = malloc(llmemcpy_pagetables_size + 4096UL);
-#endif
- if (llmemcpy_pagetables_raw != NULL) {
- /* the table itself must be 4K aligned, so... */
-#if TARGET_MSDOS == 16
- unsigned int seg = FP_SEG(llmemcpy_pagetables_raw) + (FP_OFF(llmemcpy_pagetables_raw) >> 4UL);
- seg = (seg + 0xFFUL) & (~0xFFUL);
- llmemcpy_pagetables = MK_FP(seg,0);
-#else
- llmemcpy_pagetables = (void*)(((size_t)llmemcpy_pagetables_raw + 0xFFFUL) & (~0xFFFUL));
-#endif
- llmemcpy_pagefmt = typ;
- }
-
- return (llmemcpy_pagetables != NULL);
-}
-
-/* NTS: src and dst must be PHYSICAL addresses. the routine will deal with conversion if it has to */
-size_t llmemcpy(uint64_t dst,uint64_t src,size_t len) {
- if (!llmem_available || len == 0) return 0;
- if (dst == 0xFFFFFFFFFFFFFFFFULL) return 0;
- if (src == 0xFFFFFFFFFFFFFFFFULL) return 0;
-
- /* do not attempt to exceed the CPU's physical memory limits. doing so will (likely) trigger a fault */
- /* this prevents the 0-4GB boundary test from causing the Intel Atom processor (32-bit phys limit) to hard-reset */
- if (dst > llmem_phys_limit || (dst+(uint64_t)len) > llmem_phys_limit) return 0;
- if (src > llmem_phys_limit || (src+(uint64_t)len) > llmem_phys_limit) return 0;
-
-#if TARGET_MSDOS == 16
- if (cpu_v86_active) {
- if ((src|dst) < (1ULL << 52ULL) && llmem_meth_pae) { /* if both are below 52 bits, and PAE is an option */
- register uint32_t FAR *p32;
- register uint64_t FAR *p;
- uint32_t psrc,pdst;
- uint32_t cpy = (uint32_t)min(((1ULL << 52ULL) - max(src,dst)),0x1000000ULL),i,j; /* we have to max() it to ensure the result is < 4GB, something that will fit into size_t on 32-bit */
- if (cpy > len) cpy = len;
-
- /* limit memory copy to 2M or less */
- if (cpy > 0x200000UL) cpy = 0x200000UL;
-
- /* make temporary page tables, switch on PSE, switch to page tables, and do the copy operation.
- * This code takes advantage of the Page Size bit to make only the first level (4M pages)
- * and that modern processors interpret bits 16...13 as bits 35...32 of the physical address. */
- if (llmemcpy_pagetables == NULL || llmemcpy_pagefmt != LLMEMCPY_PF_PAE_2M_VCPI) {
- if (!llmemcpy_alloc(36*1024,LLMEMCPY_PF_PAE_2M_VCPI)) { /* 4KB PDPTE + 16KB Page directories + 8KB VCPI compat + 4KB 32-bit page0 32-bit + 4KB page dir 32-bit */
- llmem_reason = "llmemcpy: no memory available (36KB needed) for 2M PAE VCPI page table";
- return 0;
- }
-
- /* 32-bit page dir */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
- p32 = (uint32_t FAR*)((char FAR*)llmemcpy_pagetables + (28*1024));
- p32[0] = (psrc + 0x8000UL) | 1UL; /* first page directory -> second level is at the second 4KB block */
- for (i=1;i < 1024;i++) p32[i] = (i << 22UL) | (1 << 7UL) | 7UL; /* every other 4MB range is mapped 1:1 */
-
- /* level 1: PDPTE */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
- p = (uint64_t FAR*)llmemcpy_pagetables;
- for (i=0;i < 4;i++) p[i] = ((uint64_t)psrc + 0x1000UL + (i<<12UL)) | 1UL;
- for (;i < 512;i++) p[i] = 0;
-
- /* level 2: page directories */
- for (j=0;j < 4;j++) {
- p = (uint64_t FAR*)((char FAR*)llmemcpy_pagetables + 0x1000UL + (j<<12UL));
- for (i=0;i < 512;i++) p[i] = ((j << 30UL) | (i << 21UL)) | (1UL << 7UL) | 7UL;
- }
-
- /* page dir 0, page 0+1 need a 3rd level, for the (translated) copy of the VCPI server's page tables */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables)) + 0x1000UL + 0x4000UL;
- p = (uint64_t FAR*)((char FAR*)llmemcpy_pagetables + 0x1000UL);
- p[0] = ((uint32_t)psrc & 0xFFFFF000UL) | 1UL;
- p[1] = (((uint32_t)psrc + 0x1000UL) & 0xFFFFF000UL) | 1UL;
- }
-
- if (llmemcpy_gdt == NULL) {
- if ((llmemcpy_gdt = _fmalloc(8*(5+4))) == NULL) {
- llmem_reason = "llmemcpy: no memory available for GDT";
- return 0;
- }
- }
-
- __asm {
- .386
- xor eax,eax
- mov ax,cs
- shl eax,4
- mov psrc,eax
-
- xor eax,eax
- mov ax,ds
- shl eax,4
- mov pdst,eax
- }
-
- /* NULL selector */
- llmemcpy_gdt[0*2 + 0] = 0;
- llmemcpy_gdt[0*2 + 1] = 0;
- /* code (16-bit) limit=0xFFFF */
- llmemcpy_gdt[1*2 + 0] = 0xFFFFUL | (psrc << 16UL);
- llmemcpy_gdt[1*2 + 1] = ((psrc >> 16UL) & 0xFFUL) | (0x9AUL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[2*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[2*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFFFFFF base=0 */
- llmemcpy_gdt[3*2 + 0] = 0xFFFFUL;
- llmemcpy_gdt[3*2 + 1] = (0x92UL << 8UL) | (0x8FUL << 16UL);
-
- __asm {
- .386
- xor eax,eax
- mov ax,ss
- shl eax,4
- mov pdst,eax
- }
-
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[4*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[4*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
-
- /* 5, 6, and 7 are assigned to VCPI */
-
- /* TSS */
- pdst = ((uint32_t)FP_SEG(llmemcpy_vcpi_tss) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_vcpi_tss));
- llmemcpy_gdt[8*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[8*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x89UL << 8UL) | (0x0FUL << 16UL);
-
- psrc = (((uint32_t)FP_SEG(llmemcpy_gdt)) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_gdt));
- llmemcpy_gdtr[0] = ((5+4)*8) - 1;
- llmemcpy_gdtr[1] = psrc;
- llmemcpy_gdtr[2] = psrc >> 16UL;
- llmemcpy_gdtr[3] = 0;
-
- llmemcpy_idtr[0] = (8*256) - 1;
- llmemcpy_idtr[1] = 0;
- llmemcpy_idtr[2] = 0;
- llmemcpy_idtr[3] = 0;
-
- llmemcpy_vcpi_return[0] = 0;
- llmemcpy_vcpi_return[1] = (5 << 3);
-
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
-
- /* we want to point to the upper 4GB to remap it */
- p = (uint64_t FAR*)((char FAR*)llmemcpy_pagetables + 0x1000UL + (3UL<<12UL));
-
- /* modify the page entries for the topmost 2MB x 4 = 8MB of the 4GB range.
- * that is where we will map the source and destination buffers, each 2MB x 2.
- * Notice this is the reason we limit the memcpy to 2MB or less.
- *
- * The DOS extender might put our code anywhere within the 2GB, but it certaintly
- * wouldn't put us up there with the BIOS, not even in flat 32-bit mode with no paging,
- * on a system with >= 4GB of RAM.
- *
- * Starting from 4GB - 8MB:
- * [0,1] = source
- * [2,3] = dest */
- p[508] = (src & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[509] = ((src + 0x200000ULL) & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[510] = (dst & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[511] = ((dst + 0x200000ULL) & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
-
- /* compute flat addr of page tables.
- * we do this HERE because if done further down
- * we may get weird random values and crash, god damn Watcom optimizer */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
-
- /* compute flat addr of page tables.
- * we do this HERE because if done further down
- * we may get weird random values and crash, god damn Watcom optimizer */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
- llmemcpy_vcpi[0] = psrc + 0x7000;
-
- psrc = ((uint32_t)FP_SEG(llmemcpy_gdtr) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_gdtr));
- llmemcpy_vcpi[1] = psrc;
-
- psrc = ((uint32_t)FP_SEG(llmemcpy_idtr) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_idtr));
- llmemcpy_vcpi[2] = psrc;
-
- llmemcpy_vcpi[3] = ((8UL << 3UL) << 16UL); /* LDTR=0 TR=8 */
-
- llmemcpy_vcpi[4] = 0;
-
- llmemcpy_vcpi[5] = 1UL << 3UL;
-
- /* compute the 32-bit flat pointers we will use */
- psrc = (3UL << 30UL) + (508UL << 21UL) + ((uint32_t)src & 0x1FFFFFUL);
- pdst = (3UL << 30UL) + (510UL << 21UL) + ((uint32_t)dst & 0x1FFFFFUL);
-
- llmem_memcpy_16_inner_pae_vcpi(pdst,psrc,cpy);
-
- return cpy;
- }
- else if ((src|dst) < 0x1000000000ULL && llmem_meth_pse) { /* if both are below 64GB (36 bits) and PSE-36 is an option */
- uint32_t psrc,pdst;
- register uint32_t FAR *p;
- uint32_t cpy = (uint32_t)min((0x1000000000ULL - max(src,dst)),0x1000000ULL),i; /* we have to max() it to ensure the result is < 4GB, something that will fit into size_t on 32-bit */
- if (cpy > len) cpy = len;
-
- /* limit memory copy to 4M or less */
- if (cpy > 0x400000UL) cpy = 0x400000UL;
-
- /* switch to protected mode using VCPI. Let the VCPI server define it's page 0 in the second 4KB page,
- * and then we'll define paging that is mostly 4M pages except for the first 4M (in the first 4KB page).
- * everyone (including VCPI) is happy */
- if (llmemcpy_pagetables == NULL || llmemcpy_pagefmt != LLMEMCPY_PF_PSE_4M_VCPI) {
- if (!llmemcpy_alloc(8*1024,LLMEMCPY_PF_PSE_4M_VCPI)) {
- llmem_reason = "llmemcpy: no memory available (8KB needed) for 4M PSE VCPI page table";
- return 0;
- }
-
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
-
- /* generate the page table contents to map the entire space as 1:1 (so this code can
- * continue to execute properly) */
- /* base address i * 4MB, PS=1, U/W/P=1 */
- p = (uint32_t FAR*)llmemcpy_pagetables;
- p[0] = (psrc + 0x1000UL) | 1UL; /* first page directory -> second level is at the second 4KB block */
- for (i=1;i < 1024;i++) p[i] = (i << 22UL) | (1 << 7UL) | 7UL; /* every other 4MB range is mapped 1:1 */
- }
- else {
- p = (uint32_t FAR*)llmemcpy_pagetables;
- }
-
- if (llmemcpy_gdt == NULL) {
- if ((llmemcpy_gdt = _fmalloc(8*(5+4))) == NULL) {
- llmem_reason = "llmemcpy: no memory available for GDT";
- return 0;
- }
- }
-
- __asm {
- .386
- xor eax,eax
- mov ax,cs
- shl eax,4
- mov psrc,eax
-
- xor eax,eax
- mov ax,ds
- shl eax,4
- mov pdst,eax
- }
-
- /* NULL selector */
- llmemcpy_gdt[0*2 + 0] = 0;
- llmemcpy_gdt[0*2 + 1] = 0;
- /* code (16-bit) limit=0xFFFF */
- llmemcpy_gdt[1*2 + 0] = 0xFFFFUL | (psrc << 16UL);
- llmemcpy_gdt[1*2 + 1] = ((psrc >> 16UL) & 0xFFUL) | (0x9AUL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[2*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[2*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFFFFFF base=0 */
- llmemcpy_gdt[3*2 + 0] = 0xFFFFUL;
- llmemcpy_gdt[3*2 + 1] = (0x92UL << 8UL) | (0x8FUL << 16UL);
-
- __asm {
- .386
- xor eax,eax
- mov ax,ss
- shl eax,4
- mov pdst,eax
- }
-
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[4*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[4*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
-
- /* 5, 6, and 7 are assigned to VCPI */
-
- /* TSS */
- pdst = ((uint32_t)FP_SEG(llmemcpy_vcpi_tss) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_vcpi_tss));
- llmemcpy_gdt[8*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[8*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x89UL << 8UL) | (0x0FUL << 16UL);
-
- psrc = (((uint32_t)FP_SEG(llmemcpy_gdt)) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_gdt));
- llmemcpy_gdtr[0] = ((5+4)*8) - 1;
- llmemcpy_gdtr[1] = psrc;
- llmemcpy_gdtr[2] = psrc >> 16UL;
- llmemcpy_gdtr[3] = 0;
-
- llmemcpy_idtr[0] = (8*256) - 1;
- llmemcpy_idtr[1] = 0;
- llmemcpy_idtr[2] = 0;
- llmemcpy_idtr[3] = 0;
-
- llmemcpy_vcpi_return[0] = 0;
- llmemcpy_vcpi_return[1] = (5 << 3);
-
- /* modify the page entries for the topmost 4MB x 4 = 16MB of the 4GB range.
- * that is where we will map the source and destination buffers, each 4MB x 2.
- * Notice this is the reason we limit the memcpy to 4MB or less.
- *
- * The DOS extender might put our code anywhere within the 4GB, but it certaintly
- * wouldn't put us up there with the BIOS, not even in flat 32-bit mode with no paging,
- * on a system with >= 4GB of RAM.
- *
- * Starting from 4GB - 16MB:
- * [0,1] = source
- * [2,3] = dest */
- p[1020] = (uint32_t)(((uint32_t)src & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)(src >> 32ULL)) & 0xFUL) << 13UL));
- p[1021] = (uint32_t)(((uint32_t)(src+0x400000ULL) & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)((src+0x400000ULL) >> 32ULL)) & 0xFUL) << 13UL));
-
- p[1022] = (uint32_t)(((uint32_t)dst & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)(dst >> 32ULL)) & 0xFUL) << 13UL));
- p[1023] = (uint32_t)(((uint32_t)(dst+0x400000ULL) & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)((dst+0x400000ULL) >> 32ULL)) & 0xFUL) << 13UL));
-
- /* compute flat addr of page tables.
- * we do this HERE because if done further down
- * we may get weird random values and crash, god damn Watcom optimizer */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
- llmemcpy_vcpi[0] = psrc;
-
- psrc = ((uint32_t)FP_SEG(llmemcpy_gdtr) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_gdtr));
- llmemcpy_vcpi[1] = psrc;
-
- psrc = ((uint32_t)FP_SEG(llmemcpy_idtr) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_idtr));
- llmemcpy_vcpi[2] = psrc;
-
- llmemcpy_vcpi[3] = ((8UL << 3UL) << 16UL); /* LDTR=0 TR=8 */
-
- llmemcpy_vcpi[4] = 0;
-
- llmemcpy_vcpi[5] = 1UL << 3UL;
-
- /* compute the 32-bit flat pointers we will use */
- psrc = (1020UL << 22UL) + ((uint32_t)src & 0x3FFFFFUL);
- pdst = (1022UL << 22UL) + ((uint32_t)dst & 0x3FFFFFUL);
-
- llmem_memcpy_16_inner_pse_vcpi(pdst,psrc,cpy);
-
- return cpy;
- }
- }
- else if (src < 0x100000ULL && dst < 0x100000ULL) { /* aka both src and dst below < 1MB boundary (non v86) */
- size_t cpy = 0x100000UL - (size_t)max(src,dst),scpy;
- if (cpy > len) cpy = len;
- scpy = cpy;
-
- while (scpy >= 4096UL) {
- _fmemcpy(MK_FP(dst>>4,dst&0xFUL),MK_FP(src>>4,src&0xFUL),4096);
- scpy -= 4096UL;
- src += 4096ULL;
- dst += 4096ULL;
- }
- if (scpy > 0UL) {
- _fmemcpy(MK_FP(dst>>4,dst&0xFUL),MK_FP(src>>4,src&0xFUL),scpy);
- }
-
- return cpy;
- }
- /* this is the preferred option, especially for modern CPUs */
- else if ((src|dst) < (1ULL << 52ULL) && llmem_meth_pae) { /* if both are below 52 bits, and PAE is an option */
- register uint64_t FAR *p;
- uint32_t psrc,pdst;
- uint32_t cpy = (uint32_t)min(((1ULL << 52ULL) - max(src,dst)),0x1000000ULL),i,j; /* we have to max() it to ensure the result is < 4GB, something that will fit into size_t on 32-bit */
- if (cpy > len) cpy = len;
-
- /* limit memory copy to 2M or less */
- if (cpy > 0x200000UL) cpy = 0x200000UL;
-
- if (llmemcpy_gdt == NULL) {
- if ((llmemcpy_gdt = _fmalloc(8*5)) == NULL) {
- llmem_reason = "llmemcpy: no memory available for GDT";
- return 0;
- }
- }
-
- __asm {
- .386
- xor eax,eax
- mov ax,cs
- shl eax,4
- mov psrc,eax
-
- xor eax,eax
- mov ax,ds
- shl eax,4
- mov pdst,eax
- }
-
- /* NULL selector */
- llmemcpy_gdt[0*2 + 0] = 0;
- llmemcpy_gdt[0*2 + 1] = 0;
- /* code (16-bit) limit=0xFFFF */
- llmemcpy_gdt[1*2 + 0] = 0xFFFFUL | (psrc << 16UL);
- llmemcpy_gdt[1*2 + 1] = ((psrc >> 16UL) & 0xFFUL) | (0x9AUL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[2*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[2*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFFFFFF base=0 */
- llmemcpy_gdt[3*2 + 0] = 0xFFFFUL;
- llmemcpy_gdt[3*2 + 1] = (0x92UL << 8UL) | (0x8FUL << 16UL);
-
- __asm {
- .386
- xor eax,eax
- mov ax,ss
- shl eax,4
- mov pdst,eax
- }
-
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[4*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[4*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
-
- psrc = (((uint32_t)FP_SEG(llmemcpy_gdt)) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_gdt));
- llmemcpy_gdtr[0] = (5*8) - 1;
- llmemcpy_gdtr[1] = psrc;
- llmemcpy_gdtr[2] = psrc >> 16UL;
- llmemcpy_gdtr[3] = 0;
-
- /* make temporary page tables, switch on PSE, switch to page tables, and do the copy operation.
- * This code takes advantage of the Page Size bit to make only the first level (4M pages)
- * and that modern processors interpret bits 16...13 as bits 35...32 of the physical address. */
- if (llmemcpy_pagetables == NULL || llmemcpy_pagefmt != LLMEMCPY_PF_PAE_2M) {
- if (!llmemcpy_alloc(20*1024,LLMEMCPY_PF_PAE_2M)) { /* 4KB PDPTE + 16KB Page directories */
- llmem_reason = "llmemcpy: no memory available (20KB needed) for 2M PAE page table";
- return 0;
- }
-
- /* we need the phys addr of the table */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
-
- /* level 1: PDPTE */
- p = (uint64_t FAR*)llmemcpy_pagetables;
- for (i=0;i < 4;i++) p[i] = ((uint64_t)psrc + 0x1000UL + (i<<12UL)) | 1UL;
- for (;i < 512;i++) p[i] = 0;
-
- /* level 2: page directories */
- for (j=0;j < 4;j++) {
- p = (uint64_t FAR*)((char FAR*)llmemcpy_pagetables + 0x1000UL + (j<<12UL));
- for (i=0;i < 512;i++) p[i] = ((j << 30UL) | (i << 21UL)) | (1UL << 7UL) | 7UL;
- }
- }
-
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
-
- /* we want to point to the upper 4GB to remap it */
- p = (uint64_t FAR*)((char FAR*)llmemcpy_pagetables + 0x1000UL + (3UL<<12UL));
-
- /* modify the page entries for the topmost 2MB x 4 = 8MB of the 4GB range.
- * that is where we will map the source and destination buffers, each 2MB x 2.
- * Notice this is the reason we limit the memcpy to 2MB or less.
- *
- * The DOS extender might put our code anywhere within the 2GB, but it certaintly
- * wouldn't put us up there with the BIOS, not even in flat 32-bit mode with no paging,
- * on a system with >= 4GB of RAM.
- *
- * Starting from 4GB - 8MB:
- * [0,1] = source
- * [2,3] = dest */
- p[508] = (src & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[509] = ((src + 0x200000ULL) & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[510] = (dst & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[511] = ((dst + 0x200000ULL) & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
-
- /* compute flat addr of page tables.
- * we do this HERE because if done further down
- * we may get weird random values and crash, god damn Watcom optimizer */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
- __asm {
- .386p
-
- cli
-
- ; enable PSE
- mov eax,cr4
- or eax,0x30
- mov cr4,eax
-
- ; load CR3
- mov eax,psrc
- mov cr3,eax
- }
-
- /* load the GDTR here. again, the goddamn optimizer. */
- __asm {
- .386p
-
- push es
- mov ax,seg llmemcpy_gdtr
- mov es,ax
- lgdt fword ptr [es:llmemcpy_gdtr]
- pop es
- }
-
- /* compute the 32-bit flat pointers we will use */
- psrc = (3UL << 30UL) + (508UL << 21UL) + ((uint32_t)src & 0x1FFFFFUL);
- pdst = (3UL << 30UL) + (510UL << 21UL) + ((uint32_t)dst & 0x1FFFFFUL);
-
- __asm {
- .386p
-
- ; load the params we need NOW. we can't load variables during this brief
- ; hop into protected mode.
- mov ecx,cpy
- mov esi,psrc
- mov edi,pdst
-
- ; inner code
- call llmem_memcpy_16_inner_pae
-
- ; switch off PSE
- mov eax,cr4
- and eax,0xFFFFFFCF
- mov cr4,eax
-
- ; clear CR3
- xor eax,eax
- mov cr3,eax
- }
-
- llmemcpy_gdtr[0] = 0xFFFF;
- llmemcpy_gdtr[1] = 0;
- llmemcpy_gdtr[2] = 0;
-
- __asm {
- .386p
-
- push es
- mov ax,seg llmemcpy_gdtr
- mov es,ax
- lgdt fword ptr [es:llmemcpy_gdtr]
- pop es
- }
-
- __asm {
- sti
- }
-
- return cpy;
- }
- /* FIXME: Known bug:
- *
- * Build: 16-bit real mode (large model)
- * Run under: Oracle Virtual Box 4.1.8 configured for 64-bit guest and AMD VT-x acceleration
- * Bug: Though Virtual Box reports PSE and PAE extensions, the PSE-36 code here crashes and hangs the
- * virtual machine. Turning off 64-bit guest and AMD VT-x resolves the crash and both PSE-36 and PAE
- * code paths here (16-bit real mode) execute without problems. Perhaps Virtual Box has a problem
- * with PSE page tables and AMD VT-x?
- * Workaround: Don't use PSE mode, use PAE mode. or,
- * Switch off 64-bit guest and AMD VT-x in Virtual Box (which causes Virtual Box to report only PSE) */
- else if ((src|dst) <= llmem_pse_limit && llmem_meth_pse) { /* if both are below 64GB (36 bits) and PSE-36 is an option */
- uint32_t psrc,pdst;
- register uint32_t FAR *p;
- uint32_t cpy = (uint32_t)min(((llmem_pse_limit+1ULL) - max(src,dst)),0x1000000ULL),i; /* we have to max() it to ensure the result is < 4GB, something that will fit into size_t on 32-bit */
- if (cpy > len) cpy = len;
-
- /* limit memory copy to 4M or less */
- if (cpy > 0x400000UL) cpy = 0x400000UL;
-
- /* make temporary page tables, switch on PSE, switch to page tables, and do the copy operation.
- * This code takes advantage of the Page Size bit to make only the first level (4M pages)
- * and that modern processors interpret bits 16...13 as bits 35...32 of the physical address. */
- if (llmemcpy_pagetables == NULL || llmemcpy_pagefmt != LLMEMCPY_PF_PSE_4M) {
- if (!llmemcpy_alloc(4*1024,LLMEMCPY_PF_PSE_4M)) {
- llmem_reason = "llmemcpy: no memory available (4KB needed) for 4M PSE page table";
- return 0;
- }
-
- /* generate the page table contents to map the entire space as 1:1 (so this code can
- * continue to execute properly) */
- /* base address i * 4MB, PS=1, U/W/P=1 */
- p = (uint32_t FAR*)llmemcpy_pagetables;
- for (i=0;i < 1024;i++) p[i] = (i << 22UL) | (1 << 7UL) | 7UL;
- }
- else {
- p = (uint32_t FAR*)llmemcpy_pagetables;
- }
-
- if (llmemcpy_gdt == NULL) {
- if ((llmemcpy_gdt = _fmalloc(8*5)) == NULL) {
- llmem_reason = "llmemcpy: no memory available for GDT";
- return 0;
- }
- }
-
- __asm {
- .386
- xor eax,eax
- mov ax,cs
- shl eax,4
- mov psrc,eax
-
- xor eax,eax
- mov ax,ds
- shl eax,4
- mov pdst,eax
- }
-
- /* NULL selector */
- llmemcpy_gdt[0*2 + 0] = 0;
- llmemcpy_gdt[0*2 + 1] = 0;
- /* code (16-bit) limit=0xFFFF */
- llmemcpy_gdt[1*2 + 0] = 0xFFFFUL | (psrc << 16UL);
- llmemcpy_gdt[1*2 + 1] = ((psrc >> 16UL) & 0xFFUL) | (0x9AUL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[2*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[2*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
- /* data (16-bit) limit=0xFFFFFFFF base=0 */
- llmemcpy_gdt[3*2 + 0] = 0xFFFFUL;
- llmemcpy_gdt[3*2 + 1] = (0x92UL << 8UL) | (0x8FUL << 16UL);
-
- __asm {
- .386
- xor eax,eax
- mov ax,ss
- shl eax,4
- mov pdst,eax
- }
-
- /* data (16-bit) limit=0xFFFF */
- llmemcpy_gdt[4*2 + 0] = 0xFFFFUL | (pdst << 16UL);
- llmemcpy_gdt[4*2 + 1] = ((pdst >> 16UL) & 0xFFUL) | (0x92UL << 8UL) | (0x0FUL << 16UL);
-
- psrc = (((uint32_t)FP_SEG(llmemcpy_gdt)) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_gdt));
- llmemcpy_gdtr[0] = (5*8) - 1;
- llmemcpy_gdtr[1] = psrc;
- llmemcpy_gdtr[2] = psrc >> 16UL;
- llmemcpy_gdtr[3] = 0;
-
- /* modify the page entries for the topmost 4MB x 4 = 16MB of the 4GB range.
- * that is where we will map the source and destination buffers, each 4MB x 2.
- * Notice this is the reason we limit the memcpy to 4MB or less.
- *
- * The DOS extender might put our code anywhere within the 4GB, but it certaintly
- * wouldn't put us up there with the BIOS, not even in flat 32-bit mode with no paging,
- * on a system with >= 4GB of RAM.
- *
- * Starting from 4GB - 16MB:
- * [0,1] = source
- * [2,3] = dest */
- p[1020] = (uint32_t)(((uint32_t)src & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)(src >> 32ULL)) & 0xFUL) << 13UL));
- p[1021] = (uint32_t)(((uint32_t)(src+0x400000ULL) & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)((src+0x400000ULL) >> 32ULL)) & 0xFUL) << 13UL));
-
- p[1022] = (uint32_t)(((uint32_t)dst & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)(dst >> 32ULL)) & 0xFUL) << 13UL));
- p[1023] = (uint32_t)(((uint32_t)(dst+0x400000ULL) & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)((dst+0x400000ULL) >> 32ULL)) & 0xFUL) << 13UL));
-
- /* compute flat addr of page tables.
- * we do this HERE because if done further down
- * we may get weird random values and crash, god damn Watcom optimizer */
- psrc = ((uint32_t)FP_SEG(llmemcpy_pagetables) << 4UL) + ((uint32_t)FP_OFF(llmemcpy_pagetables));
- __asm {
- .386p
-
- cli
-
- ; enable PSE
- mov eax,cr4
- or eax,0x10
- mov cr4,eax
-
- ; load CR3
- mov eax,psrc
- mov cr3,eax
- }
-
- /* load the GDTR here. again, the goddamn optimizer. */
- __asm {
- .386p
-
- push es
- mov ax,seg llmemcpy_gdtr
- mov es,ax
- lgdt fword ptr [es:llmemcpy_gdtr]
- pop es
- }
-
- /* compute the 32-bit flat pointers we will use */
- psrc = (1020UL << 22UL) + ((uint32_t)src & 0x3FFFFFUL);
- pdst = (1022UL << 22UL) + ((uint32_t)dst & 0x3FFFFFUL);
-
- __asm {
- .386p
-
- ; load the params we need NOW. we can't load variables during this brief
- ; hop into protected mode.
- mov ecx,cpy
- mov esi,psrc
- mov edi,pdst
-
- ; inner code
- call llmem_memcpy_16_inner_pse
-
- ; switch off PSE
- mov eax,cr4
- and eax,0xFFFFFFEF
- mov cr4,eax
-
- ; clear CR3
- xor eax,eax
- mov cr3,eax
- }
-
- llmemcpy_gdtr[0] = 0xFFFF;
- llmemcpy_gdtr[1] = 0;
- llmemcpy_gdtr[2] = 0;
-
- __asm {
- .386p
-
- push es
- mov ax,seg llmemcpy_gdtr
- mov es,ax
- lgdt fword ptr [es:llmemcpy_gdtr]
- pop es
- }
-
- __asm {
- sti
- }
-
- return cpy;
- }
-#else /* TARGET_MSDOS == 32 */
- if (dos_ltp_info.paging) {
- /* TODO: If we're not running in Ring-0, then do VCPI jailbreak to get to Ring-0 */
-
- {
- uint16_t v=0;
- __asm {
- mov ax,cs
- mov v,ax
- }
-
- if ((v&3) != 0) {
- llmem_reason = "DPMI/VCPI server is running this code with paging, not at Ring 0";
- return 0;
- }
- }
-
- llmem_reason = "32-bit with paging already enabled under DPMI/VCPI not implemented";
- return 0;
- }
- else {
- /* paging is not enabled. if we're Ring 0 we may be able to play with the control registers */
- {
- uint16_t v=0;
- __asm {
- mov ax,cs
- mov v,ax
- }
-
- if ((v&3) != 0) {
- llmem_reason = "DPMI/VCPI server is running this code without paging, but not at Ring 0";
- return 0;
- }
- }
-
- if ((src|dst) < 0x100000000ULL) { /* if both are below 4GB (32 bits) */
- /* paging disabled, we can just memcpy() */
- size_t cpy = (size_t)(0x100000000ULL - max(src,dst));
- if (cpy > len) cpy = len;
-
- memcpy((void*)((uint32_t)dst),(void const*)((uint32_t)src),cpy);
- return cpy;
- }
- /* this is the preferred option, especially for modern CPUs */
- else if ((src|dst) < (1ULL << 52ULL) && llmem_meth_pae) { /* if both are below 52 bits, and PAE is an option */
- size_t old_cr4=0;
- register uint64_t *p;
- volatile unsigned char *psrc,*pdst;
- size_t cpy = (size_t)min(((1ULL << 52ULL) - max(src,dst)),0x1000000ULL),i,j; /* we have to max() it to ensure the result is < 4GB, something that will fit into size_t on 32-bit */
- if (cpy > len) cpy = len;
-
- /* limit memory copy to 2M or less */
- if (cpy > 0x200000UL) cpy = 0x200000UL;
-
- /* make temporary page tables, switch on PSE, switch to page tables, and do the copy operation.
- * This code takes advantage of the Page Size bit to make only the first level (4M pages)
- * and that modern processors interpret bits 16...13 as bits 35...32 of the physical address. */
- if (llmemcpy_pagetables == NULL || llmemcpy_pagefmt != LLMEMCPY_PF_PAE_2M) {
- if (!llmemcpy_alloc(20*1024,LLMEMCPY_PF_PAE_2M)) { /* 4KB PDPTE + 16KB Page directories */
- llmem_reason = "llmemcpy: no memory available (20KB needed) for 2M PAE page table";
- return 0;
- }
-
- /* level 1: PDPTE */
- p = (uint64_t*)llmemcpy_pagetables;
- for (i=0;i < 4;i++) p[i] = ((uint64_t)llmemcpy_pagetables + 0x1000UL + (i<<12UL)) | 1UL;
- for (;i < 512;i++) p[i] = 0;
-
- /* level 2: page directories */
- for (j=0;j < 4;j++) {
- p = (uint64_t*)((char*)llmemcpy_pagetables + 0x1000UL + (j<<12UL));
- for (i=0;i < 512;i++) p[i] = ((j << 30UL) | (i << 21UL)) | (1UL << 7UL) | 7UL;
- }
- }
-
- /* we want to point to the upper 4GB to remap it */
- p = (uint64_t*)((char*)llmemcpy_pagetables + 0x1000UL + (3UL<<12UL));
-
- /* modify the page entries for the topmost 2MB x 4 = 8MB of the 4GB range.
- * that is where we will map the source and destination buffers, each 2MB x 2.
- * Notice this is the reason we limit the memcpy to 2MB or less.
- *
- * The DOS extender might put our code anywhere within the 2GB, but it certaintly
- * wouldn't put us up there with the BIOS, not even in flat 32-bit mode with no paging,
- * on a system with >= 4GB of RAM.
- *
- * Starting from 4GB - 8MB:
- * [0,1] = source
- * [2,3] = dest */
- p[508] = (src & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[509] = ((src + 0x200000ULL) & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[510] = (dst & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
- p[511] = ((dst + 0x200000ULL) & 0xFFFFFFFE00000ULL) | (1ULL << 7ULL) | 7ULL;
-
- /* we're going to fuck with the page tables, we don't want interrupts to cause problems */
- _cli();
-
- /* save the old value of CR4, and then write to enable PSE. also read/write cr0 to enable paging */
- __asm {
- mov eax,cr4
- mov old_cr4,eax
- or eax,0x30 ; set bit 4 (PSE) and bit 5 (PAE)
- mov cr4,eax
-
- mov eax,llmemcpy_pagetables
- mov cr3,eax
-
- mov eax,cr0
- or eax,0x80000001 ; set bit 31 (paging)
- mov cr0,eax
- }
-
- /* commence the memcpy */
- {
- psrc = (volatile unsigned char*)((3UL << 30UL) + (508UL << 21UL) + ((size_t)src & 0x1FFFFFUL));
- pdst = (volatile unsigned char*)((3UL << 30UL) + (510UL << 21UL) + ((size_t)dst & 0x1FFFFFUL));
- memcpy((void*)pdst,(void*)psrc,cpy);
- }
-
- /* restore CR4, disable paging */
- __asm {
- mov eax,cr0
- and eax,0x7FFFFFFF ; clear bit 31 (paging)
- mov cr0,eax
-
- mov eax,old_cr4
- mov cr4,eax
-
- xor eax,eax
- mov cr3,eax ; erase CR3
- }
-
- _sti();
- return cpy;
- }
- else if ((src|dst) <= llmem_pse_limit && llmem_meth_pse) { /* if both are below 64GB (36 bits) and PSE-36 is an option */
- size_t old_cr4=0;
- register uint32_t *p;
- volatile unsigned char *psrc,*pdst;
- size_t cpy = (size_t)min(((llmem_pse_limit+1ULL) - max(src,dst)),0x1000000ULL),i; /* we have to max() it to ensure the result is < 4GB, something that will fit into size_t on 32-bit */
- if (cpy > len) cpy = len;
-
- /* limit memory copy to 4M or less */
- if (cpy > 0x400000UL) cpy = 0x400000UL;
-
- /* make temporary page tables, switch on PSE, switch to page tables, and do the copy operation.
- * This code takes advantage of the Page Size bit to make only the first level (4M pages)
- * and that modern processors interpret bits 16...13 as bits 35...32 of the physical address. */
- if (llmemcpy_pagetables == NULL || llmemcpy_pagefmt != LLMEMCPY_PF_PSE_4M) {
- if (!llmemcpy_alloc(4*1024,LLMEMCPY_PF_PSE_4M)) {
- llmem_reason = "llmemcpy: no memory available (4KB needed) for 4M PSE page table";
- return 0;
- }
-
- /* generate the page table contents to map the entire space as 1:1 (so this code can
- * continue to execute properly) */
- /* base address i * 4MB, PS=1, U/W/P=1 */
- p = (uint32_t*)llmemcpy_pagetables;
- for (i=0;i < 1024;i++) p[i] = (i << 22UL) | (1 << 7UL) | 7UL;
- }
- else {
- p = (uint32_t*)llmemcpy_pagetables;
- }
-
- /* modify the page entries for the topmost 4MB x 4 = 16MB of the 4GB range.
- * that is where we will map the source and destination buffers, each 4MB x 2.
- * Notice this is the reason we limit the memcpy to 4MB or less.
- *
- * The DOS extender might put our code anywhere within the 4GB, but it certaintly
- * wouldn't put us up there with the BIOS, not even in flat 32-bit mode with no paging,
- * on a system with >= 4GB of RAM.
- *
- * Starting from 4GB - 16MB:
- * [0,1] = source
- * [2,3] = dest */
- p[1020] = (uint32_t)(((uint32_t)src & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)(src >> 32ULL)) & 0xFUL) << 13UL));
- p[1021] = (uint32_t)(((uint32_t)(src+0x400000ULL) & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)((src+0x400000ULL) >> 32ULL)) & 0xFUL) << 13UL));
-
- p[1022] = (uint32_t)(((uint32_t)dst & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)(dst >> 32ULL)) & 0xFUL) << 13UL));
- p[1023] = (uint32_t)(((uint32_t)(dst+0x400000ULL) & 0xFFC00000ULL) | (1 << 7UL) | 7UL |
- ((((uint32_t)((dst+0x400000ULL) >> 32ULL)) & 0xFUL) << 13UL));
-
- /* we're going to fuck with the page tables, we don't want interrupts to cause problems */
- _cli();
-
- /* save the old value of CR4, and then write to enable PSE. also read/write cr0 to enable paging */
- __asm {
- mov eax,cr4
- mov old_cr4,eax
- or eax,0x10 ; set bit 4 (PSE)
- mov cr4,eax
-
- mov eax,llmemcpy_pagetables
- mov cr3,eax
-
- mov eax,cr0
- or eax,0x80000001 ; set bit 31 (paging)
- mov cr0,eax
- }
-
- /* commence the memcpy */
- {
- psrc = (volatile unsigned char*)((1020UL << 22UL) + ((size_t)src & 0x3FFFFFUL));
- pdst = (volatile unsigned char*)((1022UL << 22UL) + ((size_t)dst & 0x3FFFFFUL));
- memcpy((void*)pdst,(void*)psrc,cpy);
- }
-
- /* restore CR4, disable paging */
- __asm {
- mov eax,cr0
- and eax,0x7FFFFFFF ; clear bit 31 (paging)
- mov cr0,eax
-
- mov eax,old_cr4
- mov cr4,eax
-
- xor eax,eax
- mov cr3,eax ; erase CR3
- }
-
- _sti();
- return cpy;
- }
- }
-#endif
-
- /* pick a method, based on what is available */
-
- llmem_reason = "llmemcpy: no methods available";
- return 0;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-
-enum {
- LLMEMCPY_PF_NONE=0,
- LLMEMCPY_PF_386_4KB, /* 386-compatible two-level 4KB pages */
- LLMEMCPY_PF_PSE_4M, /* Pentium PSE style one-level 4M pages */
- LLMEMCPY_PF_PAE_2M, /* Modern PAE 64-bit pages 2M each */
- LLMEMCPY_PF_PSE_4M_VCPI, /* PSE 4M pages, with one 4KB page for VCPI server compatibility */
- LLMEMCPY_PF_PAE_2M_VCPI /* PAE 2M pages, with two 4KB pages for VCPI compat, and one extra page */
-};
-
-extern unsigned char llmem_probed;
-extern unsigned char llmem_meth_pse;
-extern unsigned char llmem_meth_pae;
-extern unsigned char llmem_available;
-extern uint64_t llmem_phys_limit;
-extern uint64_t llmem_pse_limit;
-extern const char* llmem_reason;
-
-extern volatile void FAR* llmemcpy_pagetables;
-extern volatile void FAR* llmemcpy_pagetables_raw;
-extern size_t llmemcpy_pagetables_size;
-extern unsigned char llmemcpy_pagefmt;
-#if TARGET_MSDOS == 16
-extern uint32_t far* llmemcpy_gdt;
-extern uint16_t llmemcpy_gdtr[4];
-extern uint16_t llmemcpy_idtr[4];
-extern uint32_t llmemcpy_vcpi[0x20];
-extern uint32_t llmemcpy_vcpi_return[2];
-extern uint8_t llmemcpy_vcpi_tss[108];
-#endif
-
-/* returns 0xFFFFFFFFFFFFFFFF if unmappable */
-#if TARGET_MSDOS == 16
-uint64_t llmem_ptr2ofs(unsigned char far *ptr);
-#else
-uint64_t llmem_ptr2ofs(unsigned char *ptr);
-#endif
-
-int llmem_init();
-void llmemcpy_free();
-int llmemcpy_alloc(size_t len,unsigned char typ);
-uint32_t llmem_virt_phys_recommended_copy_size();
-size_t llmemcpy(uint64_t dst,uint64_t src,size_t len);
-
+++ /dev/null
-
-; NTS: We use NASM to achieve our goals here because WASM sucks donkey balls
-; Maybe when they bother to implement a proper conditional macro system, I'll consider it...
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- %ifidni MMODE,l
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %ifidni MMODE,m
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-; NTS: Associate our data with Watcom's data segment
-segment .data public align=4 class=data
-
-%if TARGET_MSDOS == 16
-; ext vars
-; uint32_t far* near llmemcpy_gdt = NULL;
-extern _llmemcpy_gdt
-; uint16_t near llmemcpy_gdtr[4];
-extern _llmemcpy_gdtr
-; uint16_t near llmemcpy_idtr[4];
-extern _llmemcpy_idtr
-; uint32_t near llmemcpy_vcpi[0x20];
-extern _llmemcpy_vcpi
-; uint32_t near llmemcpy_vcpi_return[2];
-extern _llmemcpy_vcpi_return
-; volatile void FAR* llmemcpy_pagetables = NULL;
-extern _llmemcpy_pagetables
-%endif
-
-; NTS: Help NASM put the code segment in the right place for Watcom to link it in properly
-segment text public align=1 class=code
-
-%if TARGET_MSDOS == 16
-
-global llmem_memcpy_16_inner_pae_
-llmem_memcpy_16_inner_pae_:
- ; save sregs
- push es
- push ds
- push ss
-
- ; patch exit jmp
- mov ax,cs
- mov word [cs:exit_pae_patch+1+2],ax
-
- ; jump into protected mode, with paging
- mov eax,cr0
- or eax,0x80000001
- mov cr0,eax
- jmp 0x08:entry_pae
-entry_pae:
-
- ; load the data selectors
- mov ax,0x10
- mov ds,ax
- mov ax,0x18
- mov es,ax
- mov ax,0x20
- mov ss,ax
-
- ; do the memcpy
- mov edx,ecx
- and edx,3
- shr ecx,2
- cld
-
- es rep a32 movsd
-
- mov ecx,edx
- es rep a32 movsb
-
- ; get out of protected mode
- mov eax,cr0
- and eax,0x7FFFFFFE
- mov cr0,eax
-exit_pae_patch:
- jmp 0:exit_pae
-exit_pae:
-
- ; restore sregs
- pop ss
- pop ds
- pop es
-
- retnative
-
-global llmem_memcpy_16_inner_pse_
-llmem_memcpy_16_inner_pse_:
- ; save sregs
- push es
- push ds
- push ss
-
- ; patch exit jmp
- mov ax,cs
- mov word [cs:exit_pse_patch+1+2],ax
-
- ; jump into protected mode, with paging
- mov eax,cr0
- or eax,0x80000001
- mov cr0,eax
- jmp 0x08:entry_pse
-entry_pse:
-
- ; load the data selectors
- mov ax,0x10
- mov ds,ax
- mov ax,0x18
- mov es,ax
- mov ax,0x20
- mov ss,ax
-
- ; do the memcpy
- mov edx,ecx
- and edx,3
- shr ecx,2
- cld
-
- es rep a32 movsd
-
- mov ecx,edx
- es rep a32 movsb
-
- ; get out of protected mode
- mov eax,cr0
- and eax,0x7FFFFFFE
- mov cr0,eax
-exit_pse_patch:
- jmp 0:exit_pse
-exit_pse:
-
- ; restore sregs
- pop ss
- pop ds
- pop es
-
- retnative
-
-; alternate version to do PSE llmemcpy when VCPI/EMM386.EXE is active.
-; void __cdecl llmem_memcpy_16_inner_pse_vcpi(uint32_t dst,uint32_t src,uint32_t cpy);
-global _llmem_memcpy_16_inner_pse_vcpi
-_llmem_memcpy_16_inner_pse_vcpi:
- push bp
-; extra vars
- push cs ; +14
- push ds ; +12
- push es ; +10
- push ss ; +8
-
-; we need to store _llmemcpy_vcpi_return on the stack. once we're in protected mode
-; the FAR pointers given by Watcom are not usable.
- mov si,seg _llmemcpy_vcpi_return
- mov fs,si
- mov si,_llmemcpy_vcpi_return
- mov eax,[fs:si+4] ; segment
- push eax ; +4
- xor eax,eax
- push eax ; +0
-
-%define extra 16 ; +16
-; end extra
- mov bp,sp
-
- mov ax,seg _llmemcpy_pagetables
- mov fs,ax
- xor edi,edi
- les di,[fs:_llmemcpy_pagetables]
- add edi,0x1000
-
- mov ax,seg _llmemcpy_gdt
- mov fs,ax
- xor esi,esi
- lds si,[fs:_llmemcpy_gdt]
- add esi,5 << 3
-
- ; so: DS:SI = First GDT available to VCPI server
- ; ES:DI = Page dir 0 page 0 4KB page
- mov ax,0xDE01
- int 67h
- cmp ah,0
- jz .info_ok
-; ==ERROR==
- mov eax,0xAABBCC01
- jmp short $
-; ==END ERROR==
-.info_ok: ; we need EBX, the return entry point offset
- mov [bp+0],ebx
-
- ; now enter VCPI protected mode
- mov bx,seg _llmemcpy_vcpi
- mov fs,bx
- mov dword [fs:_llmemcpy_vcpi+0x10],.vcpi_entry
-
- xor esi,esi
- mov si,seg _llmemcpy_vcpi
- shl esi,4
- add esi,_llmemcpy_vcpi
-
- mov ax,0xDE0C
- int 67h
- hlt ; <- BRICK WALL in case of errant VCPI server
-
-.vcpi_entry: mov ax,2 << 3
- mov ds,ax
-
- mov ax,3 << 3
- mov es,ax
- mov fs,ax
- mov gs,ax
-
- mov ax,4 << 3
- mov ss,ax
-
- ; switch on PSE. note we couldn't do this from the real-mode side
- ; since the v86 monitor would likely not allow that
- mov eax,cr4
- or eax,0x10
- mov cr4,eax
-
- mov ecx,[bp+cdecl_param_offset+extra+8] ; cpy
- mov esi,[bp+cdecl_param_offset+extra+4] ; src
- mov edi,[bp+cdecl_param_offset+extra+0] ; dst
-
- cld
- push ecx
- shr ecx,2
- a32 rep es movsd
- pop ecx
- and ecx,3
- a32 rep es movsb
-
- ; switch off PSE. once we're back in v86 mode we can't touch control regs
- mov eax,cr4
- and eax,~0x10
- mov cr4,eax
-
- ; set up return to v86 mode
- and esp,0xFFFF ; <--- THIS IS VERY IMPORTANT ON RETURN FROM VCPI, UPPER BITS OF ESP CAN BE NONZERO
- xor eax,eax
- mov ax,[bp+12] ; DS
- push eax ; SS:ESP+0x28 GS
- push eax ; SS:ESP+0x24 FS
- push eax ; SS:ESP+0x20 DS
- mov ax,[bp+10]
- push eax ; SS:ESP+0x1C ES
- mov ax,[bp+8]
- push eax ; SS:ESP+0x18 SS
- mov eax,ebp
- push eax ; SS:ESP+0x14 ESP
- pushfd ; SS:ESP+0x10 EFLAGS
- mov ax,[bp+14]
- push eax ; SS:ESP+0x0C CS
- push dword .vcpi_exit; SS:ESP+0x08 EIP
- mov eax,[bp+4] ; VCPI code segment
- push eax ; SS:ESP+0x04 VCPI code segment
- mov eax,[bp+0] ; VCPI offset
- push eax
- mov eax,0xDE0C ; switch back to v86
- jmp far dword [esp] ; <--- 32-bit address mode required for direct use of SP, but only if we refer to ESP
-.vcpi_exit:
-
- add sp,extra
- pop bp
- retnative
-%undef extra
-
-; alternate version to do PAE llmemcpy when VCPI/EMM386.EXE is active.
-; void __cdecl llmem_memcpy_16_inner_pae_vcpi(uint32_t dst,uint32_t src,uint32_t cpy);
-global _llmem_memcpy_16_inner_pae_vcpi
-_llmem_memcpy_16_inner_pae_vcpi:
- push bp
-; extra vars
-
- xor esi,esi
- xor edi,edi
- mov si,seg _llmemcpy_pagetables
- mov fs,si
- mov si,[fs:_llmemcpy_pagetables+2]
- shl esi,4
- mov di,[fs:_llmemcpy_pagetables]
- add esi,edi
- push esi ; +16
-
- push cs ; +14
- push ds ; +12
- push es ; +10
- push ss ; +8
-
-; we need to store _llmemcpy_vcpi_return on the stack. once we're in protected mode
-; the FAR pointers given by Watcom are not usable.
- mov si,seg _llmemcpy_vcpi_return
- mov fs,si
- mov si,_llmemcpy_vcpi_return
- mov eax,[fs:si+4] ; segment
- push eax ; +4
- xor eax,eax
- push eax ; +0
-
-%define extra 20 ; +20
-; end extra
- mov bp,sp
-
- ; we're going to give the VCPI server the last 4KB page in the 36KB
- ; buffer allocated by the function, set aside for that purpose.
- ; what we're then going to do is copy and translate that page table
- ; to the 64-bit form required by PAE, initially starting from the
- ; 32-bit form in the last 8KB
- mov ax,seg _llmemcpy_pagetables
- mov fs,ax
- xor edi,edi
- les di,[fs:_llmemcpy_pagetables]
- add edi,0x8000 ; +32KB
-
- mov ax,seg _llmemcpy_gdt
- mov fs,ax
- xor esi,esi
- lds si,[fs:_llmemcpy_gdt]
- add esi,5 << 3
-
- ; so: DS:SI = First GDT available to VCPI server
- ; ES:DI = Page dir 0 page 0 4KB page
- mov ax,0xDE01
- int 67h
- cmp ah,0
- jz .info_ok
-; ==ERROR==
- mov eax,0xAABBCC01
- jmp short $
-; ==END ERROR==
-.info_ok: ; we need EBX, the return entry point offset
- mov [bp+0],ebx
-
- ; now enter VCPI protected mode
- mov bx,seg _llmemcpy_vcpi
- mov fs,bx
- mov dword [fs:_llmemcpy_vcpi+0x10],.vcpi_entry
-
- xor esi,esi
- mov si,seg _llmemcpy_vcpi
- shl esi,4
- add esi,_llmemcpy_vcpi
-
- mov ax,0xDE0C
- int 67h
- hlt ; <- BRICK WALL in case of errant VCPI server
-
-.vcpi_entry: mov ax,2 << 3
- mov ds,ax
-
- mov ax,3 << 3
- mov es,ax
- mov fs,ax
- mov gs,ax
-
- mov ax,4 << 3
- mov ss,ax
-
- ; switch on PSE. note we couldn't do this from the real-mode side
- ; since the v86 monitor would likely not allow that
- mov eax,cr4
- or eax,0x10
- mov cr4,eax
-
- ; copy the first 4MB of 32-bit page tables and translate to 64-bit
- mov eax,[bp+16] ; _llmemcpy_pagetables
- lea esi,[eax+0x8000] ; source: 32-bit VCPI page zero
- lea edi,[eax+0x5000] ; dest: 64-bit page zero and one
- mov ecx,1024 ; 1024 x 32-bit -> 1024 x 64-bit (4KB -> 8KB)
- cld
-.xlate_loop: a32 es movsd ; lower 32 bits -> 64 bits with upper bits zero
- xor eax,eax
- a32 stosd
- loop .xlate_loop
-
- ; switch on PAE, reload CR3. Temporarily shut down paging to accomplish that.
- ; most likely: as a DOS program in the 1MB area we're not remapped and it won't affect us.
- mov ecx,cr0
- and ecx,0x7FFFFFFF
- mov cr0,ecx ; CR0=Disable PE
- mov ebx,[bp+16] ; _llmemcpy_pagetables
- mov cr3,ebx ; CR3=new 64-bit page table
- mov eax,cr4
- or eax,0x30
- mov cr4,eax ; CR4=PSE and PAE
- or ecx,0x80000000
- mov cr0,ecx ; CR0=Enable PE
-
- mov ecx,[bp+cdecl_param_offset+extra+8] ; cpy
- mov esi,[bp+cdecl_param_offset+extra+4] ; src
- mov edi,[bp+cdecl_param_offset+extra+0] ; dst
-
- cld
- push ecx
- shr ecx,2
- a32 rep es movsd
- pop ecx
- and ecx,3
- a32 rep es movsb
-
- ; switch on PAE, reload CR3. Temporarily shut down paging to accomplish that.
- ; most likely: as a DOS program in the 1MB area we're not remapped and it won't affect us.
- mov ecx,cr0
- and ecx,0x7FFFFFFF
- mov cr0,ecx ; CR0=Disable PE
- mov ebx,[bp+16] ; _llmemcpy_pagetables
- add ebx,0x7000 ; point at 32-bit tables
- mov cr3,ebx ; CR3=new 64-bit page table
- mov eax,cr4
- and eax,~0x30
- mov cr4,eax ; CR4=Disable PSE and PAE
- or ecx,0x80000000
- mov cr0,ecx ; CR0=Enable PE
-
- ; set up return to v86 mode
- and esp,0xFFFF ; <--- THIS IS VERY IMPORTANT ON RETURN FROM VCPI, UPPER BITS OF ESP CAN BE NONZERO
- xor eax,eax
- mov ax,[bp+12] ; DS
- push eax ; SS:ESP+0x28 GS
- push eax ; SS:ESP+0x24 FS
- push eax ; SS:ESP+0x20 DS
- mov ax,[bp+10]
- push eax ; SS:ESP+0x1C ES
- mov ax,[bp+8]
- push eax ; SS:ESP+0x18 SS
- mov eax,ebp
- push eax ; SS:ESP+0x14 ESP
- pushfd ; SS:ESP+0x10 EFLAGS
- mov ax,[bp+14]
- push eax ; SS:ESP+0x0C CS
- push dword .vcpi_exit; SS:ESP+0x08 EIP
- mov eax,[bp+4] ; VCPI code segment
- push eax ; SS:ESP+0x04 VCPI code segment
- mov eax,[bp+0] ; VCPI offset
- push eax
- mov eax,0xDE0C ; switch back to v86
- jmp far dword [esp] ; <--- 32-bit address mode required for direct use of SP, but only if we refer to ESP
-.vcpi_exit:
-
- add sp,extra
- pop bp
- retnative
-%undef extra
-
-%endif
+++ /dev/null
-/* NOTES:
- * This code works perfectly on most test systems I have.
- * Some systems do provide interesting insight though when they do fail.
- *
- * Test: Oracle VirtualBox 4.1.8 with 64-bit guest and AMD VT-X acceleration:
- * Result: VirtualBox reports PAE and PSE, and 32-bit test program works perfectly.
- * The 16-bit real mode builds however, cause the virtual machine to hang
- * when attempting to use the PSE method. This hang does not occur when
- * AMD VT-x is disabled.
- *
- * Test: Dell netbook with Intel Atom processor
- * Result: Processor reports via CPUID that it has 32-bit linear and 32-bit physical
- * address space. And it means it. The minute this program steps beyond 4GB,
- * the CPU faults and the system resets. This is true regardless of whether
- * the 16-bit real mode or the 32-bit protected mode version is used. This is
- * true whether you use PSE-36 or PAE.
- *
- * So apparently, they don't do what 386/486/pentium systems USED to do and just
- * silently wrap the addresses, eh?
- *
- * That means this code should make use of the "extended CPUID" to read those
- * limits and then llmemcpy() should enforce them. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/llmem/llmem.h>
-#include <hw/cpu/cpuidext.h>
-
-static unsigned char temp1[256],temp2[256];
-
-static void print_contents(unsigned char *t,unsigned int len) {
- unsigned int x;
-
- len = (len + 15U) >> 4U;
- while (len-- > 0) {
- printf(" ");
- for (x=0;x < 16;x++) printf("%02X ",t[x]);
- t += 16;
- printf("\n");
- }
-}
-
-static void help() {
- fprintf(stderr,"Long-Long memory copy test program\n");
- fprintf(stderr,"llmem [options]\n");
- fprintf(stderr," /PAE Prefer PAE if both are available\n");
- fprintf(stderr," /PSE Prefer PSE if both are available\n");
-}
-
-int main(int argc,char **argv) {
- int i,pref_pse=0,pref_pae=0;
- char *a;
-
- for (i=1;i < argc;) {
- a = argv[i++];
-
- if (*a == '/' || *a == '-') {
- do { a++; } while (*a == '/' || *a == '-');
-
- if (!strcmp(a,"h") || !strcmp(a,"help")) {
- help();
- return 1;
- }
- else if (!strcmp(a,"pse")) {
- pref_pse=1;
- }
- else if (!strcmp(a,"pae")) {
- pref_pae=1;
- }
- else {
- help();
- return 1;
- }
- }
- else {
- fprintf(stderr,"Unknown arg '%s'\n",a);
- return 1;
- }
- }
-
- if (!llmem_init()) {
- printf("Your system is not suitable to use with the Long-Long memory access library\n");
- printf("Reason: %s\n",llmem_reason);
- return 1;
- }
-
- if (pref_pse && llmem_meth_pse)
- llmem_meth_pae = 0;
- if (pref_pae && llmem_meth_pae)
- llmem_meth_pse = 0;
-
- printf("Long-Long memory access is usable on this machine.\n");
- printf(" - PSE method: %d\n",llmem_meth_pse);
- printf(" - PAE method: %d\n",llmem_meth_pae);
-
- memset(temp1,0xAA,sizeof(temp1));
- if (llmemcpy(llmem_ptr2ofs(temp1),0x000000000UL,256UL)) { /* At lowest address */
- printf("Memory @ 0MB:\n");
- print_contents(temp1,256);
- }
- else {
- printf("! Cannot read memory @ 0MB: '%s'\n",llmem_reason);
- }
- while (getch() != 13);
-
- memset(temp1,0xAA,sizeof(temp1));
- if (llmemcpy(llmem_ptr2ofs(temp1),0xFFFFFF00UL,256UL)) { /* Just below the 4GB boundary */
- printf("Memory @ 4096MB-256b:\n");
- print_contents(temp1,256);
- }
- else {
- printf("! Cannot read memory @ 4096MB-256B: '%s'\n",llmem_reason);
- }
- while (getch() != 13);
-
- memset(temp2,0xAA,sizeof(temp2));
- if (llmemcpy(llmem_ptr2ofs(temp2),0x100000000UL,256UL)) { /* At the 4GB boundary */
- printf("Memory @ 4096MB:\n");
- print_contents(temp2,256);
- }
- else {
- printf("! Cannot read memory @ 4096MB: '%s'\n",llmem_reason);
- }
- while (getch() != 13);
-
- memset(temp2,0xAA,sizeof(temp2));
- if (llmemcpy(llmem_ptr2ofs(temp2),0x200000000UL,256UL)) { /* At the 8GB boundary */
- printf("Memory @ 8192MB:\n");
- print_contents(temp2,256);
- }
- else {
- printf("! Cannot read memory @ 8192MB: '%s'\n",llmem_reason);
- }
- while (getch() != 13);
-
- llmemcpy_free();
- cpu_extended_cpuid_info_free();
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-set WHAT=make\r
-if "%1" == "clean" set WHAT=clean\r
-\r
-echo Building: intel\r
-cd intel\r
-call buildall.bat %WHAT%\r
-cd ..\r
-\r
-echo All done\r
+++ /dev/null
-@echo off\r
-if exist *.map del *.map\r
-if exist *.obj del *.obj\r
-if exist *.sym del *.sym\r
-if exist *.exe del *.exe\r
+++ /dev/null
-@echo off\r
-\r
-set WHAT=make\r
-if "%1" == "clean" set WHAT=clean\r
-\r
-echo Building: piix3\r
-cd piix3\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo All done\r
+++ /dev/null
-@echo off\r
-if exist *.map del *.map\r
-if exist *.obj del *.obj\r
-if exist *.sym del *.sym\r
-if exist *.exe del *.exe\r
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\..\..\mak\dos86c.mak HPS=\ all REL=..\..\..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\..\..\mak\dos86l.mak HPS=\ all REL=..\..\..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\..\..\mak\dos86m.mak HPS=\ all REL=..\..\..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\..\..\mak\dos86s.mak HPS=\ all REL=..\..\..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\..\..\mak\dos386f.mak HPS=\ all REL=..\..\..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_MB_INTEL_PIIX3_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..$(HPS)..$(HPS)..
-
-C_SOURCE = piix3.c
-OBJS = $(SUBDIR)$(HPS)piix3.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_MB_INTEL_PIIX3_LIB): $(OBJS)
- wlib -q -b -c $(HW_MB_INTEL_PIIX3_LIB) -+$(SUBDIR)$(HPS)piix3.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_MB_INTEL_PIIX3_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_MB_INTEL_PIIX3_LIB) $(HW_MB_INTEL_PIIX3_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_PCI_LIB) $(HW_PCI_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_MB_INTEL_PIIX3_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_PCI_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_MB_INTEL_PIIX3_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/adlib/adlib.h>
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
+++ /dev/null
-Motherboard toy for motherboards based on the Intel "Triton" PIIX3
-PCIset chipsets (82371SB)
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/pci/pci.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-
-struct pci_ref {
- uint8_t bus,dev,func;
- uint16_t vendor,device;
-};
-
-struct pci_ref pci_isa_bridge={0xFF,0xFF,0xFF};
-
-enum {
- CMD_DUMPRAW=0,
- CMD_DUMP
-};
-
-static void help() {
- fprintf(stderr,"test [options]\n");
- fprintf(stderr," Motherboard toy for Intel PIIX3 based motherboards\n");
- fprintf(stderr,"\n");
- fprintf(stderr,"WARNING: This program allows you to play with the PIIX3 chipset\n");
- fprintf(stderr," on your motherboard, even in ways that can crash or hang\n");
- fprintf(stderr," your system and necessitate pushing the reset button.\n");
- fprintf(stderr," The responsibility is yours to use this wisely!\n");
- fprintf(stderr,"\n");
- fprintf(stderr," /d Dump PCI configuration space\n");
- fprintf(stderr," /dr Dump PCI configuration space, raw\n");
- fprintf(stderr," /ch List switches to change parameters\n");
-}
-
-void pause() {
- while (getch() != 13);
-}
-
-#define PAGEME {\
- if (++lines >= 23) {\
- lines = 0;\
- pause();\
- }\
-}
-
-static void ch_help() {
- int lines=0;
-
- fprintf(stderr,"Changeable params, PCI-ISA bridge\n"); PAGEME;
- fprintf(stderr," [!] = The command may disrupt your ability to use the normal\n");
- fprintf(stderr," DOS environment and/or cause a crash.\n");
- fprintf(stderr," /pi:dma-alias=<1|0> Enable/disable DMA Reserved Page Reg Alias\n"); PAGEME;
- fprintf(stderr," /pi:io8r=<N> 8-bit I/O recovery time (0 to disable)\n"); PAGEME;
- fprintf(stderr," /pi:io16r=<N> 16-bit I/O recovery time (0 to disable)\n"); PAGEME;
- fprintf(stderr," /pi:apic-cs=<1|0> Enable/disable APIC Chip Select\n");
- fprintf(stderr," /pi:extbios=<1|0> Enable/disable Extended BIOS\n");
- fprintf(stderr," /pi:lowbios=<1|0> Enable/disable lower BIOS [!]\n");
- fprintf(stderr," /pi:copren=<1|0> Enable/disable coprocessor error on IRQ 13\n");
- fprintf(stderr," /pi:ps2irq=<1|0> Enable/disable PS/2 mouse on IRQ 12\n");
- fprintf(stderr," /pi:bioswrite=<1|0> Enable/disable asserting BIOSCS# on write\n");
- fprintf(stderr," /pi:keyio=<1|0> Enable/disable chipset I/O of Keyboard [!]\n");
- fprintf(stderr," /pi:rtio=<1|0> Enable/disable chipset I/O of RTC\n");
- fprintf(stderr," /pi:pci-irq-<x>=<N> Route PCI IRQ x to IRQ N where 'x' is A,B,C or D\n");
- fprintf(stderr," and N is 1...15, or 0 to disable/assign to ISA [!]\n");
-}
-
-static const char *s_yesno(int b) {
- return b ? "Yes" : "No";
-}
-
-#define PI_MAX 8
-static int pi_args=0;
-static const char *pi_arg[PI_MAX];
-
-int main(int argc,char **argv) {
- int cmd = -1,i,val,lines=0;
-
- if (argc < 2) {
- help();
- return 1;
- }
-
- for (i=1;i < argc;) {
- const char *a = argv[i++];
-
- if (*a == '-' || *a == '/') {
- do { a++; } while (*a == '-' || *a == '/');
-
- if (!strcmp(a,"dr")) {
- cmd = CMD_DUMPRAW;
- }
- else if (!strcmp(a,"d")) {
- cmd = CMD_DUMP;
- }
- else if (!strcmp(a,"ch")) {
- ch_help();
- return 1;
- }
- else if (!strncmp(a,"pi:",3)) {
- if (pi_args < PI_MAX) {
- pi_arg[pi_args++] = a+3;
- }
- else {
- fprintf(stderr,"Too many /pi: args\n");
- return 1;
- }
- }
- else {
- help();
- return 1;
- }
- }
- else {
- help();
- return 1;
- }
- }
-
- printf("Intel PIIX3 motherboard toy\n");
- if (cmd < 0) cmd = CMD_DUMP;
-
- cpu_probe();
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!pci_probe(-1)) {
- printf("Cannot init library\n");
- return 1;
- }
- if (pci_bios_last_bus == -1) {
- printf(" Autodetecting PCI bus count...\n"); PAGEME;
- pci_probe_for_last_bus();
- }
- printf(" Last bus: %d\n",pci_bios_last_bus); PAGEME;
- printf(" Bus decode bits: %d\n",pci_bus_decode_bits); PAGEME;
-
- /* then enumerate the bus */
- {
- uint8_t bus,dev,func;
- for (bus=0;bus <= pci_bios_last_bus;bus++) {
- for (dev=0;dev < 32;dev++) {
- uint8_t functions = pci_probe_device_functions(bus,dev);
- for (func=0;func < functions;func++) {
- /* make sure something is there before announcing it */
- uint16_t vendor,device,subsystem,subvendor_id;
- uint32_t class_code;
- uint8_t revision_id;
-
- vendor = pci_read_cfgw(bus,dev,func,0x00); if (vendor == 0xFFFF) continue;
- device = pci_read_cfgw(bus,dev,func,0x02); if (device == 0xFFFF) continue;
- subvendor_id = pci_read_cfgw(bus,dev,func,0x2C);
- subsystem = pci_read_cfgw(bus,dev,func,0x2E);
- class_code = pci_read_cfgl(bus,dev,func,0x08);
- revision_id = class_code & 0xFF;
- class_code >>= 8UL;
-
- if (vendor == 0x8086 && device == 0x7000 && class_code == 0x060100UL) {
- if (pci_isa_bridge.bus == 0xFF) {
- pci_isa_bridge.bus = bus;
- pci_isa_bridge.dev = dev;
- pci_isa_bridge.func = func;
- pci_isa_bridge.vendor = vendor;
- pci_isa_bridge.device = device;
- }
- }
- }
- }
- }
- }
-
- if (pci_isa_bridge.bus != 0xFF) {
- unsigned char b;
- unsigned long l;
- unsigned short w;
-
- printf("PCI-ISA bridge device: B/D/F %X:%X:%X V/D %X:%X\n",
- pci_isa_bridge.bus, pci_isa_bridge.dev,
- pci_isa_bridge.func, pci_isa_bridge.vendor,
- pci_isa_bridge.device); PAGEME;
-
- for (i=0;i < pi_args;i++) {
- const char *a = pi_arg[i];
-
- if (!strncmp(a,"dma-alias=",10)) {
- val = atoi(a+10);
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4C);
- b = (b & 0x7F) | (((val^1)&1) << 7);
- pci_write_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4C,b);
- }
- else if (!strncmp(a,"io8r=",5)) {
- val = atoi(a+5);
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4C);
- if (val == 0) { /* disable */
- b &= ~(1 << 6);
- b &= ~(7 << 3);
- b |= (1 << 3);
- }
- else { /* enable */
- b |= (1 << 6);
- b &= ~(7 << 3);
- b |= ((val&7) << 3);
- }
- pci_write_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4C,b);
- }
- else if (!strncmp(a,"io16r=",6)) {
- val = atoi(a+6);
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4C);
- if (val == 0) { /* disable */
- b &= ~(1 << 2);
- b &= ~(3 << 0);
- b |= (1 << 0);
- }
- else { /* enable */
- b |= (1 << 2);
- b &= ~(3 << 0);
- b |= ((val&3) << 0);
- }
- pci_write_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4C,b);
- }
- else if (!strncmp(a,"apic-cs=",8)) {
- val = atoi(a+8);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 8)) | ((val&1) << 8);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"extbios=",8)) {
- val = atoi(a+8);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 7)) | ((val&1) << 7);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"lowbios=",8)) {
- val = atoi(a+8);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 6)) | ((val&1) << 6);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"copren=",7)) {
- val = atoi(a+7);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 5)) | ((val&1) << 5);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"ps2irq=",7)) {
- val = atoi(a+7);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 4)) | ((val&1) << 4);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"bioswrite=",10)) {
- val = atoi(a+10);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 2)) | ((val&1) << 2);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"keyio=",6)) {
- val = atoi(a+6);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 1)) | ((val&1) << 1);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"rtio=",5)) {
- val = atoi(a+5);
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
- w = (w & ~(1 << 0)) | ((val&1) << 0);
- pci_write_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E,w);
- }
- else if (!strncmp(a,"pci-irq-",8) && a[9] == '=') {
- int which = (tolower(a[8]) - 'a')&3;
- val = atoi(a+10);
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x60+which);
- if (val > 0) {
- b &= ~0x80;
- b |= val&15;
- }
- else {
- b &= ~15;
- b |= 0x80;
- }
- pci_write_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x60+which,b);
- }
- }
-
- if (cmd == CMD_DUMPRAW) {
- printf(" * RAW DUMP\n");
- printf(" ");
- for (i=0;i < 0x10;i++) {
- if ((i&0xF) == 0x8) printf(" ");
- printf("%X ",i);
- }
- printf("\n");
- for (i=0;i < 0x100;i++) {
- unsigned char c = pci_read_cfgb(
- pci_isa_bridge.bus,
- pci_isa_bridge.dev,
- pci_isa_bridge.func,i);
- if ((i&0xF) == 0x0) printf("%02X: ",i);
- if ((i&0xF) == 0x8) printf(" ");
- printf("%02X ",c);
- if ((i&0xF) == 0xF) printf("\n");
- }
- }
- else if (cmd == CMD_DUMP) {
- /* @0x4C: IORT ISA I/O RECOVERY TIMER REGISTER (R/W)
- DEFAULT: 0x4C
-
- bit 7: DMA Reserved Page Register Aliasing Control
- 1=disable aliasing for 80h, 84h-86h, 88h,
- and 8Ch-8Eh and forward I/O to the ISA BUS
- 0=enable aliasing
-
- bit 6: 8-bit I/O Recovery Enable
- 1=Enable the recovery time in bits[5:3]
- 0=Disable recovery time, insert 3.5 SYSCLK time instead (Is that what the datasheet means?)
-
- bits 5-3: 8-bit I/O Recovery Time
- When bit 6 set, this defines the recovery time for 8-bit I/O
-
- 001..111 = 1 to 7 SYSCLKs respectively
- 000 = 8 SYSCLKs
-
- bit 2: 16-bit I/O Recovery Enable
- 1=Enable the recovery time in bits[1:0]
- 0=Disable recovery time and (insert 3.5 SYSCLK recovery?)
-
- bits 1-0: 16-bit I/O Recovery Time
-
- 01-11 = 1 to 3 SYSCLKs respectively
- 00 = 4 SYSCLKs */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4C);
-
- printf("ISA I/O RECOVERY TIMER:\n"); PAGEME;
- printf(" DMA Reserved Page Register Alias: %s\n",s_yesno((b&0x80)==0)); PAGEME;
- printf(" 8-Bit I/O Recovery Enable: %s\n",s_yesno((b&0x40)!=0)); PAGEME;
- printf(" 8-Bit Recovery: %u SYSCLKs\n",(b&0x38) == 0 ? 8 : (b>>3)&7); PAGEME;
- printf(" 16-Bit I/O Recovery Enable: %s\n",s_yesno((b&0x04)!=0)); PAGEME;
- printf(" 16-Bit Recovery: %u SYSCLKs\n",(b&3) == 0 ? 4 : (b&3)); PAGEME;
-
- /* 0x4E-0x4F XBCS X-BUS CHIP SELECT REGISTER (Func 0) (R/W)
- PIIX: 0x4E only */
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x4E);
-
- printf("XBCS X-BUS CHIP SELECT:\n"); PAGEME;
- printf(" APIC Chip Select: %s\n",s_yesno((w&0x100)!=0)); PAGEME;
- printf(" Extended BIOS Enable: %s\n",s_yesno((w&0x080)!=0)); PAGEME;
- /* ^ Whether to assert BIOSCS# for 0xFFF80000-0xFFDFFFFF if the BIOS is that large! */
- printf(" Lower BIOS Enable: %s\n",s_yesno((w&0x040)!=0)); PAGEME;
- /* ^ Whether to assert BIOSCS# for 0xFFFE0000-0xFFFEFFFF i.e. the lower 64KB of the traditional 128KB BIOS.
- Also affects the legacy real-mode alias 0xE0000-0xEFFFF */
- printf(" Coprocessor Enable (FERR# -> IRQ13): %s\n",s_yesno((w&0x020)!=0)); PAGEME;
- /* ^ Whether the coprocessor error signal causes IRQ 13 to happen */
- printf(" PS/2 IRQ Mouse on IRQ Enable: %s\n",s_yesno((w&0x010)!=0)); PAGEME;
- /* ^ Whether to internally link IRQ 12 to the PS/2 mouse, or allow IRQ 12 by other devices */
- printf(" Enable BIOSCS# on write: %s\n",s_yesno((w&0x004)!=0)); PAGEME;
- printf(" Keyboard I/O Enable (KBCS#+XOE#): %s\n",s_yesno((w&0x002)!=0)); PAGEME;
- printf(" RT Clock I/O Enable (RTCCS#+XOE#): %s\n",s_yesno((w&0x001)!=0)); PAGEME;
-
- /* 0x60...0x63 PIRQx ROUTING CONTROL REGISTERS (R/W)
- Each register controls routing for PCI interrupts A, B, C, and D.
-
- Bit 7: Interrupt Routing Enable (0=enable 1=disable)
- Bits[3:0]: IRQ to route to.
-
- NOTE: IRQ assignment to PCI means the corresponding ISA IRQ signal
- is ignored. */
- for (i=0;i < 4;i++) {
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x60+i);
- printf("PCI IRQ %c ROUTING: ",i+'A');
- if (b&0x80) printf("DISABLED/ASSIGNED TO ISA");
- else printf("IRQ %u",b&15);
- printf("\n"); PAGEME;
- }
-
- /* 0x69: TOP OF MEMORY (Func 0) (R/W)
- This allows the BIOS to declare where RAM is so
- the chipset knows whether to forward ISA/DMA cycles
- to PCI (and RAM) or not.
-
- bits[7:4]: Top of memory (1-16MB) in 1MB increments.
- 0...15 represents 1-16MB respectively.
- If you ever wondered how BIOSes of the 1995-ish
- era are able to offer the "ISA memory hole" option in
- Setup, this is how: just set the TOM to 15MB and
- further regs to represent 16MB on up if any, and the
- chipset will forward the unclaimed memory to ISA.
- bit 3: ISA/DMA lower BIOS forwarding enable.
- Whether ISA or DMA access to BIOS regions is
- forwarded to the PCI bus and chipset
- bit 2: A,B Segment forward enable.
- Whether ISA/DMA access to 0xA0000-0xBFFFF
- is forwarded to PCI bus and chipset
- bit 1: ISA 512-640KB region forward enable.
- Whether ISA/DMA access to the 512KB-640KB region
- is forwarded to PCI bus and chipset */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x69);
-
-/* TODO: /pi:xxxx=N options for these values */
- printf("TOP OF MEMORY:\n"); PAGEME;
- printf(" Top of (lower 16MB) memory: %uMB\n",(b>>4)+1); PAGEME;
- printf(" ISA/DMA Lower BIOS forward to PCI: %s\n",s_yesno((b&0x08)!=0)); PAGEME;
- printf(" ISA/DMA A0000-BFFFF forward to PCI: %s\n",s_yesno((b&0x04)!=0)); PAGEME;
- printf(" ISA/DMA 512-640KB forward to PCI: %s\n",s_yesno((b&0x02)!=0)); PAGEME;
-
- /* 0x6A-0x6B: MSTAT MISCELLANEOUS STATUS REGISTER
- bit 15: SERR# Generation Due to Delayed Transaction (PIIX3).
- Clear by writing a 1 to this.
- bit 7: NB Retry Enable (PIIX3)
- bit 6: EXTSMI# Mode Enable (PIIX3)
- bit 4: USB Enable (PIIX3)
- bit 2: PCI Header Type Bit Enable (PIIX)
- bit 1: Internal ISA DMA or External DMA Mode Status (PIIX)
- bit 0: ISA Clock Divisor (R/O on PIIX)
- 1=divide by 3 0=divide by 4 */
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x6A);
-
-/* TODO: /pi:xxxx=N options for these values */
- printf("MISC STATUS REGISTER:\n"); PAGEME;
- printf(" SERR# Generation/Delayed Transact Err: %s\n",s_yesno((w&0x8000)!=0)); PAGEME;
- printf(" NB Retry Enable: %s\n",s_yesno((w&0x0080)!=0)); PAGEME;
- printf(" EXTSMI# Mode Enable: %s\n",s_yesno((w&0x0040)!=0)); PAGEME;
- printf(" USB Enable (PIIX3): %s\n",s_yesno((w&0x0010)!=0)); PAGEME;
- printf(" PCI Header Type Bit Enable (PIIX): %s\n",s_yesno((w&0x0004)!=0)); PAGEME;
- printf(" Internal ISA DMA/Ext DMA Mode Status: %s\n",s_yesno((w&0x0002)!=0)); PAGEME;
- printf(" PCI clock divider -> ISA clock: Divide by %u\n",(w&1)?3:4); PAGEME;
-
- /* 0x70: MOTHERBOARD DEVICE IRQ ROUTE CONTROL (R/W) */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x70);
-
-/* TODO: /pi:xxxx=N options for these values */
- printf("MOTHERBOARD DEVICE IRQ ROUTE (MBIRQ0):\n"); PAGEME;
- printf(" Interrupt Routine Enable: %s\n",s_yesno((b&0x80)!=0)); PAGEME;
- printf(" MIRQ/IRQ sharing enable: %s\n",s_yesno((b&0x40)!=0)); PAGEME;
- printf(" PIIX3 IRQ0 Enable: %s\n",s_yesno((b&0x20)!=0)); PAGEME;
- printf(" Routed to: IRQ %u\n",b&0xF); PAGEME;
-
- /* 0x76, 0x77: MOTHERBOARD DEVICE DMA CONTROL (R/W) */
- for (i=0;i < 2;i++) {
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x76+i);
-
-/* TODO: /pi:xxxx=N options for these values */
- printf("MOTHERBOARD DEVICE DMA CONTROL (MBDMA%u#):\n",i); PAGEME;
- printf(" Type F and DMA Buffer Enable: %s\n",s_yesno((b&0x80)!=0)); PAGEME;
- printf(" Channel: ");
- if ((b&7) == 4) printf("DISABLED");
- else printf("%u",b&7);
- printf("\n"); PAGEME;
- }
-
- /* 0x78-0x79: PROGRAMMABLE CHIP SELECT CONTROL
- If enabled, I/O access to this range triggers the PCS#
- signal which motherboard manufacturers can then use for
- whatever purpose. */
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x78);
-
- printf("PROGRAMMABLE CHIP SELECT:\n"); PAGEME;
- if ((w & 3) == 2) {
- printf(" DISABLED\n");
- }
- else {
- printf(" Base address: 0x%03X\n",w & 0xFFFC); PAGEME;
- printf(" Range: %u ports\n",
- (w&3)==3 ? 16 : (4 << (w&3)));
- }
-
- /* 0x80: APIC BASE ADDRESS RELOCATION REGISTER (PIIX3) */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x80);
-
- printf("APIC BASE ADDRESS:\n"); PAGEME;
- printf(" A12 mask: %s\n",s_yesno((b&0x40)!=0)); PAGEME;
- printf(" X AD[15:12]: %X\n",(b>>2)&0xF); PAGEME;
- printf(" Y AD[11:10]: %X\n",b&3); PAGEME;
-
- /* 0x82: DETERMINISTIC LATENCY CONTROL (PIIX3) */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0x82);
-
- printf("DETERMINISTIC LATENCY CONTROL:\n"); PAGEME;
- printf(" SERR# Generation/Delayed Trans. en: %s\n",s_yesno((b&0x08)!=0)); PAGEME;
- printf(" USB Passive Release: %s\n",s_yesno((b&0x04)!=0)); PAGEME;
- printf(" Passive Release enable: %s\n",s_yesno((b&0x02)!=0)); PAGEME;
- printf(" Delayed Transaction enable: %s\n",s_yesno((b&0x01)!=0)); PAGEME;
-
- /* 0xA0: SMI CONTROL REGISTER */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0xA0);
-
- printf("SMI CONTROL REGISTER:\n"); PAGEME;
- printf(" Fast Off Timer Freeze: ");
- if ((b&0x18) == 0x08)
- printf("DISABLED");
- else if ((b&0x18) == 0x10)
- printf("1 PCICLK");
- else
- printf("1/1.1/1.32 %s",(b&0x18)==0x18?"msec":"min");
- printf("\n"); PAGEME;
- printf(" ...(with PCI clock @ 33/30/25MHz)\n"); PAGEME;
- printf(" STPCLK# Scale enable: %s\n",s_yesno((b&0x04)!=0)); PAGEME;
- printf(" STPCLK# Signal enable: %s\n",s_yesno((b&0x02)!=0)); PAGEME;
- printf(" SMI# Gate: %s\n",s_yesno((b&0x01)!=0)); PAGEME;
-
- /* 0xA2-0xA3: SMI ENABLE REGISTER */
- w = pci_read_cfgw(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0xA2);
-
- printf("SMI ENABLE REGISTER:\n"); PAGEME;
- printf(" Legacy USB SMI Enable: %s\n",s_yesno((w&0x100)!=0)); PAGEME;
- printf(" APMC Write SMI Enable: %s\n",s_yesno((w&0x080)!=0)); PAGEME;
- printf(" EXTSMI# SMI Enable: %s\n",s_yesno((w&0x040)!=0)); PAGEME;
- printf(" Fast Off Timer SMI Enable: %s\n",s_yesno((w&0x020)!=0)); PAGEME;
- printf(" IRQ 12 SMI Enable (PS/2 Mouse): %s\n",s_yesno((w&0x010)!=0)); PAGEME;
- printf(" IRQ 8 SMI Enable (RTC Alarm): %s\n",s_yesno((w&0x008)!=0)); PAGEME;
- printf(" IRQ 4 SMI Enable (COM2/COM4): %s\n",s_yesno((w&0x004)!=0)); PAGEME;
- printf(" IRQ 3 SMI Enable (COM1/COM3): %s\n",s_yesno((w&0x002)!=0)); PAGEME;
- printf(" IRQ 1 SMI Enable (Keyboard): %s\n",s_yesno((w&0x001)!=0)); PAGEME;
-
- /* 0xA4-0xA7: SYSTEM EVENT ENABLE */
- l = pci_read_cfgl(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0xA4);
-
- printf("SYSTEM EVENT ENABLE:\n"); PAGEME;
- printf(" Fast Off SMI Enable: %s\n",s_yesno((l&0x80000000UL)!=0UL)); PAGEME;
- printf(" INTR Enable: %s\n",s_yesno((l&0x40000000UL)!=0UL)); PAGEME;
- printf(" Fast Off NMI Enable: %s\n",s_yesno((l&0x20000000UL)!=0UL)); PAGEME;
- printf(" Fast Off APIC Enable: %s\n",s_yesno((l&0x10000000UL)!=0UL)); PAGEME;
- printf(" Fast Off for IRQ: ");
- for (i=0;i < 16;i++) {
- if (i == 2) continue;
- if (l & (1UL << ((unsigned long)i) )) printf("%u ",i);
- }
- printf("\n"); PAGEME;
-
- /* 0xA8: FAST OFF TIMER REGISTER */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0xA8);
-
- printf("FAST OFF TIMER: %u\n",(unsigned int)b + 1U); PAGEME;
-
- /* 0xAC: CLOCK SCALE STPCLK# LOW TIMER */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0xAC);
-
- printf("CLOCK SCALE STPCLK# LOW TIMER: %u\n",b); PAGEME;
-
- /* 0xAE: CLOCK SCALE STPCLK# HIGH TIMER */
- b = pci_read_cfgb(pci_isa_bridge.bus,pci_isa_bridge.dev,pci_isa_bridge.func,0xAE);
-
- printf("CLOCK SCALE STPCLK# HIGH TIMER: %u\n",b); PAGEME;
- }
- }
-
- return 0;
-}
+++ /dev/null
-Assorted code, specific to each motherboard chipset.
-
-intel ............ Intel chipsets
- piix3 .......... PIIX3 (82371SB)
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_PARPORT_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = parport.c
-OBJS = $(SUBDIR)$(HPS)parport.obj
-OBJSPNP = $(SUBDIR)$(HPS)parpnp.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-TESTPNP_EXE = $(SUBDIR)$(HPS)testpnp.exe
-PRNT_EXE = $(SUBDIR)$(HPS)prnt.exe
-PRNTPNP_EXE = $(SUBDIR)$(HPS)prntpnp.exe
-SAMPTEST_EXE =$(SUBDIR)$(HPS)samptest.exe
-
-$(HW_PARPORT_LIB): $(OBJS)
- wlib -q -b -c $(HW_PARPORT_LIB) -+$(SUBDIR)$(HPS)parport.obj
-
-$(HW_PARPNP_LIB): $(OBJSPNP)
- wlib -q -b -c $(HW_PARPNP_LIB) -+$(SUBDIR)$(HPS)parpnp.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_PARPORT_LIB) $(HW_PARPNP_LIB) .symbolic
-
-exe: $(TEST_EXE) $(TESTPNP_EXE) $(PRNT_EXE) $(PRNTPNP_EXE) $(SAMPTEST_EXE) .symbolic
-
-$(SAMPTEST_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)samptest.obj
- %write tmp1.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)samptest.obj $(HW_PARPORT_LIB_WLINK_LIBRARIES) $(HW_PARPNP_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_ISAPNP_LIB_WLINK_LIBRARIES) name $(SAMPTEST_EXE)
- @wlink @tmp1.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(TEST_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp1.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_PARPORT_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp1.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(TESTPNP_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(SUBDIR)$(HPS)testpnp.obj
- %write tmp2.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)testpnp.obj $(HW_PARPORT_LIB_WLINK_LIBRARIES) $(HW_PARPNP_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_ISAPNP_LIB_WLINK_LIBRARIES) name $(TESTPNP_EXE)
- @wlink @tmp2.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(PRNT_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)prnt.obj
- %write tmp1.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)prnt.obj $(HW_PARPORT_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(PRNT_EXE)
- @wlink @tmp1.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(PRNTPNP_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)prntpnp.obj
- %write tmp2.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)prntpnp.obj $(HW_PARPORT_LIB_WLINK_LIBRARIES) $(HW_PARPNP_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_ISAPNP_LIB_WLINK_LIBRARIES) name $(PRNTPNP_EXE)
- @wlink @tmp2.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_PARPORT_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8250/8250.h>
-#include <hw/isapnp/isapnp.h>
-#include <hw/parport/parport.h>
-
-static unsigned char devnode_raw[4096];
-
-int is_parport_or_compat_pnp_device(struct isa_pnp_device_node far *devn) {
- if (devn->type_code[0] == 7 && devn->type_code[1] == 1)
- return 1;
-
- return 0;
-}
-
-void pnp_parport_scan() {
- /* most of the time the serial ports are BIOS controlled and on the motherboard.
- * they usually don't even show up in a PnP isolation scan. so we have to use
- * the "get device nodes" functions of the PnP BIOS. */
- {
- struct isa_pnp_device_node far *devn;
- unsigned int ret_ax,nodesize=0xFFFF;
- unsigned char numnodes=0xFF;
- struct isapnp_tag tag;
- unsigned char node;
-
- printf("Enumerating PnP system device nodes...\n");
-
- ret_ax = isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize);
- if (ret_ax == 0 && numnodes != 0xFF && nodesize < sizeof(devnode_raw)) {
- /* NTS: How nodes are enumerated in the PnP BIOS: set node = 0, pass address of node
- * to BIOS. BIOS, if it returns node information, will also overwrite node with
- * the node number of the next node, or with 0xFF if this is the last one.
- * On the last one, stop enumerating. */
- for (node=0;node != 0xFF;) {
- unsigned char far *rsc;
- int eport = -1; /* ECP port */
- int eplen = -1;
- int port = -1;
- int plen = -1;
- int type = -1;
- int irq = -1;
- int dma = -1;
-
- /* apparently, start with 0. call updates node to
- * next node number, or 0xFF to signify end */
- ret_ax = isa_pnp_bios_get_sysdev_node(&node,devnode_raw,
- ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW);
-
- if (ret_ax != 0)
- break;
-
- devn = (struct isa_pnp_device_node far*)devnode_raw;
- if (!is_parport_or_compat_pnp_device(devn))
- continue;
-
- /* there are three config blocks, one after the other.
- * [allocated]
- * [possible]
- * [??]
- * since we're not a configuration utility, we only care about the first one */
- rsc = devnode_raw + sizeof(*devn);
- if (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag)) {
- do {
- if (tag.tag == ISAPNP_TAG_END) /* end tag */
- break;
-
- switch (tag.tag) {
-/* NTS: This code will NOT match I/O ports if they are above 0x400 because some BIOSes
- * have ECP compliant ports and announce both the base I/O and the ECP (+0x400) I/O.
- * We only want the base I/O */
-/*---------------------------------------------------------------------------------*/
-case ISAPNP_TAG_IRQ_FORMAT: {
- struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
- unsigned int i;
- for (i=0;i < 16 && irq < 0;i++) {
- if (x->irq_mask & (1U << (unsigned int)i))
- irq = i;
- }
-} break;
-case ISAPNP_TAG_IO_PORT: {
- struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
- if (x->length >= 3) {
- if (port < 0) {
- port = x->min_range;
- plen = x->length;
- }
- else if (eport < 0) {
- eport = x->min_range;
- eplen = x->length;
- }
- }
-} break;
-case ISAPNP_TAG_FIXED_IO_PORT: {
- struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
- if (x->length >= 3) {
- if (port < 0) {
- port = x->base;
- plen = x->length;
- }
- else if (eport < 0) {
- eport = x->base;
- eplen = x->length;
- }
- }
-} break;
-case ISAPNP_TAG_DMA_FORMAT: {
- struct isapnp_tag_dma_format far *x = (struct isapnp_tag_dma_format far*)tag.data;
- unsigned int i;
- for (i=0;i < 8;i++) {
- if (x->dma_mask & (1U << (unsigned int)i))
- dma = i;
- }
-} break;
-/*---------------------------------------------------------------------------------*/
- };
- } while (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag));
- }
-
- if (port < 0)
- continue;
-
- if (eport > 0) {
- if (eport < port) {
- int x;
- x = port; port = eport; eport = x;
- x = plen; plen = eplen; eplen = x;
- }
- }
-
- if (eport > 0) {
- if ((port+0x400) == eport)
- type = PARPORT_ECP;
- }
- else if (dma >= 0) {
- /* ECP ports use a DMA channel */
- type = PARPORT_ECP;
- }
-
- if (plen >= 8) { /* if the I/O range is 8 long, then it might be EPP */
- if (type == PARPORT_ECP)
- type = PARPORT_ECP_AND_EPP;
- else
- type = PARPORT_EPP;
- }
-
- if (add_pnp_parport(port,irq,dma,type))
- printf("Found PnP port @ 0x%03x IRQ %d DMA %d assume '%s'\n",port,irq,dma,type >= 0 ? parport_type_str[type] : "?");
- }
- }
- }
-}
-
+++ /dev/null
-
-#include <hw/isapnp/isapnp.h>
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-#include <conio.h>
-
-int is_parport_or_compat_pnp_device(struct isa_pnp_device_node far *devn);
-void pnp_parport_scan();
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/parport/parport.h>
-
-const char *parport_type_str[PARPORT_MAX] = {
- "Standard",
- "Bi-directional",
- "ECP",
- "EPP",
- "ECP+EPP"
-};
-
-int init_parports = 0;
-int bios_parports = 0;
-uint16_t standard_parport_ports[STANDARD_PARPORT_PORTS] = {0x3BC,0x378,0x278};
-struct info_parport info_parport[MAX_PARPORTS];
-int info_parports=0;
-
-int already_got_parport(uint16_t port) {
- unsigned int i;
-
- for (i=0;i < (unsigned int)info_parports;i++) {
- if (info_parport[i].port == port)
- return 1;
- }
-
- return 0;
-}
-
-uint16_t get_bios_parport(unsigned int index) {
- if (index >= (unsigned int)bios_parports)
- return 0;
-
-#if TARGET_MSDOS == 32
- return *((uint16_t*)(0x400 + 8 + (index*2)));
-#else
- return *((uint16_t far*)MK_FP(0x40,8 + (index*2)));
-#endif
-}
-
-int init_parport() {
- if (!init_parports) {
- uint16_t eqw;
-
- bios_parports = 0;
- info_parports = 0;
- init_parports = 1;
-
- memset(info_parport,0,sizeof(info_parport));
-
- /* read the BIOS equipment word[11-9]. how many serial ports? */
-#if TARGET_MSDOS == 32
- eqw = *((uint16_t*)(0x400 + 0x10));
-#else
- eqw = *((uint16_t far*)MK_FP(0x40,0x10));
-#endif
- bios_parports = (eqw >> 14) & 3;
-
- }
- return 1;
-}
-
-/* TODO: Add code where if caller guesses by PnP info the port is ECP or EPP (or both) we
- * omit some tests and assume it's correct.
- *
- * Example: If the BIOS reports two I/O ports and they are 0x400 apart, then the port
- * is an ECP type and ECP type tests are unnecessary. If PnP data lists the I/O range
- * as being 8 ports long, then it's probably an EPP type port too and we can omit
- * those tests. */
-int add_pnp_parport(uint16_t port,int irq,int dma,int type) {
- struct info_parport *prt;
- char bit10 = 0;
-
- if (port == 0)
- return 0;
- if (already_got_parport(port))
- return 0;
- if (info_parports >= MAX_PARPORTS)
- return 0;
- prt = &info_parport[info_parports];
- prt->bit10 = 0;
- prt->max_xfer_size = 1;
- prt->port = port;
- prt->output_mode = PARPORT_MODE_STANDARD_STROBE_ACK;
- prt->type = PARPORT_STANDARD;
- prt->irq = irq;
- prt->dma = dma;
-
- if (type >= 0) {
- /* if the caller knows better than us, then take his word for it */
- prt->type = type;
-
- if (PARPORT_SUPPORTS_ECP(prt->type)) {
- unsigned char a,b;
-
- /* detect ECP by attempting to enable the configuration mode */
- outp(prt->port+PARPORT_IO_ECP_CONTROL,7 << 5);
- a = inp(prt->port+PARPORT_IO_ECP_REG_A);
- b = inp(prt->port+PARPORT_IO_ECP_REG_B);
-
- if (a != 0xFF && b != 0xFF) {
- prt->type = PARPORT_ECP;
-
- switch ((a >> 4) & 7) {
- case 0: prt->max_xfer_size = 2; break;
- case 1: prt->max_xfer_size = 1; break;
- case 2: prt->max_xfer_size = 4; break;
- }
-
- if (prt->irq < 0) {
- switch ((b >> 3) & 7) {
- case 1: prt->irq = 7; break;
- case 2: prt->irq = 9; break;
- case 3: prt->irq = 10; break;
- case 4: prt->irq = 11; break;
- case 5: prt->irq = 14; break;
- case 6: prt->irq = 15; break;
- case 7: prt->irq = 5; break;
- }
- }
-
- if (prt->dma < 0) {
- switch (b&7) {
- case 1: prt->dma = 1; break;
- case 2: prt->dma = 2; break;
- case 3: prt->dma = 3; break;
- case 5: prt->dma = 5; break;
- case 6: prt->dma = 6; break;
- case 7: prt->dma = 7; break;
- }
- }
- }
-
- /* switch to EPP mode for the test below if the ECP port supports it */
- if (prt->type == PARPORT_ECP)
- outp(prt->port+PARPORT_IO_ECP_CONTROL,4 << 5);
- }
- }
- else {
- /* this might be one of those EPP/ECP ports, set it to "standard byte mode" to enable the below test to find the port.
- * documentation mentions that "in ECP mode the SPP ports may disappear" so to successfully probe ports left in ECP
- * mode we have to write to the control register to bring it back.
- *
- * The (minimal) documentation I have doesn't say whether this port can be read back.
- * On older 10-bit decode hardware, this will probably only end up writing over the control bits (0x77A -> 0x37A)
- * and should be safe to carry out. On newer hardware (mid 90's) it's highly unlikely anything would be assigned
- * to I/O ports 0x778-0x77F. On newer PCI hardware, it's even less likely. */
- outp(prt->port+PARPORT_IO_ECP_CONTROL,1 << 5); /* mode=byte (bi-directional) ecpint=0 dma=0 ecpserv=0 */
-
- /* put it back into Standard mode, disable bi-directional */
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 */
- /* control ports are usually readable. if what we wrote didn't take then this is probably not a parallel port */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & 0xF) != 0x4) return 0;
-
- /* write to the control port again. if this is ancient 10-bit decode hardware, then it is probably NOT ECP/EPP
- * compliant. we detect this by whether this IO write corrupts the control register.
- * note control = port+2 and extended control = port+0x402 */
- outp(prt->port+PARPORT_IO_ECP_CONTROL,(1 << 5) | 0xC); /* CONTROL = sets bidirectional, and two control lines. EXTCTRL = maintains byte mode and turns on ECP interrupt+DMA */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & 0xF) == 0xC) /* if the +0x402 IO write changed the control register, then it's 10-bit decode and not EPP/ECP */
- bit10 = 1;
-
- outp(prt->port+PARPORT_IO_ECP_CONTROL,(1 << 5) | 0x0); /* regain sane extended control */
- outp(prt->port+PARPORT_IO_CONTROL,0x04);
-
- /* the data port is write only, though you are always allowed to read it back.
- * on bidirectional ports this is how you read back data.
- * we do not attempt to write to the status port. it is read only. worse, on modern
- * systems it can conflict with the ISA Plug & Play protocol (0x279) */
- outp(prt->port,0x55); if (inp(prt->port) != 0x55) return 0;
- outp(prt->port,0xAA); if (inp(prt->port) != 0xAA) return 0;
- outp(prt->port,0xFF); if (inp(prt->port) != 0xFF) return 0;
- outp(prt->port,0x00); if (inp(prt->port) != 0x00) return 0;
-
- /* do a parport init printer */
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 */
- if ((inp(prt->port+PARPORT_IO_CONTROL)&0xF) != 0x4) return 0;
-
- /* try to toggle bit 5 (bi-directional enable) */
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 bidir=0 */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & (1 << 5)) == 0) {
- outp(prt->port+PARPORT_IO_CONTROL,0x24); /* select=0 init=1 autolinefeed=0 strobe=0 bidir=1 */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & (1 << 5)) != 0)
- prt->type = PARPORT_BIDIRECTIONAL;
-
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 bidir=0 */
- }
-
- /* standard I/O locations have standard IRQ assignments, apparently */
- prt->bit10 = bit10;
- if (!bit10) { /* if not 10-bit decode, then check for ECP control registers */
- unsigned char a,b;
-
- /* detect ECP by attempting to enable the configuration mode */
- outp(prt->port+PARPORT_IO_ECP_CONTROL,7 << 5);
- a = inp(prt->port+PARPORT_IO_ECP_REG_A);
- b = inp(prt->port+PARPORT_IO_ECP_REG_B);
-
- if (a != 0xFF && b != 0xFF) {
- prt->type = PARPORT_ECP;
-
- switch ((a >> 4) & 7) {
- case 0: prt->max_xfer_size = 2; break;
- case 1: prt->max_xfer_size = 1; break;
- case 2: prt->max_xfer_size = 4; break;
- }
-
- if (prt->irq < 0) {
- switch ((b >> 3) & 7) {
- case 1: prt->irq = 7; break;
- case 2: prt->irq = 9; break;
- case 3: prt->irq = 10; break;
- case 4: prt->irq = 11; break;
- case 5: prt->irq = 14; break;
- case 6: prt->irq = 15; break;
- case 7: prt->irq = 5; break;
- }
- }
-
- if (prt->dma < 0) {
- switch (b&7) {
- case 1: prt->dma = 1; break;
- case 2: prt->dma = 2; break;
- case 3: prt->dma = 3; break;
- case 5: prt->dma = 5; break;
- case 6: prt->dma = 6; break;
- case 7: prt->dma = 7; break;
- }
- }
- }
-
- /* switch to EPP mode for the test below if the ECP port supports it */
- if (prt->type == PARPORT_ECP)
- outp(prt->port+PARPORT_IO_ECP_CONTROL,4 << 5);
- }
- }
-
- if (type < 0 || PARPORT_SUPPORTS_EPP(type)) {
- /* the caller might be autodetecting EPP based on the I/O length.
- * we double-check to be sure, it might be some bullshit BIOS
- * reporting 8 ports long for a device that only responds to the
- * first three */
-
- /* an EPP port could conceivably exist on a 10-bit decode ISA card */
- /* NOTES: Toshiba laptops do NOT support EPP mode, only ECP. There appears to be a hardware
- * bug in decoding the 0x778-0x77F I/O region where port 0x77A is repeated on 0x77B,
- * 0x77C, etc.
- *
- * The Compaq LTE Elite supports EPP and ECP. It follows the standard in ignoring
- * the bidir bit when setting mode 0, but does not disable EPP registers when
- * mode is not EPP.
- * ... erm, well, at least I think the extra registers are EPP. The address port
- * always returns 0x00 and the data port always returns 0x25 (this is with nothing
- * attached to the parallel port). The problem is we can only detect if something
- * is there, we can't tell if it's an EPP port or just some ancient ISA card that
- * responds to 0x3FB-0x3FF with it's own weirdness. A Google search for Compaq LTE
- * Elite and parallel port suggests that there are tools to configure the port as
- * EPP, so obviously at some level it speaks EPP mode. */
- if (inp(prt->port+PARPORT_IO_EPP_ADDRESS) != 0xFF && inp(prt->port+PARPORT_IO_EPP_DATA) != 0xFF) {
- if (prt->type == PARPORT_ECP)
- prt->type = PARPORT_ECP_AND_EPP;
- else
- prt->type = PARPORT_EPP;
- }
- }
-
- /* return the port to standard bidir mode */
- if (PARPORT_SUPPORTS_ECP(prt->type))
- outp(prt->port+PARPORT_IO_ECP_CONTROL,1 << 5);
-
- /* shut off the lines */
- outp(prt->port+PARPORT_IO_CONTROL,0x00); /* select=0 init=1 autolinefeed=0 strobe=0 bidir=0 */
- outp(prt->port+PARPORT_IO_DATA,0x00);
-
- info_parports++;
- return 1;
-}
-
-int probe_parport(uint16_t port) {
- struct info_parport *prt;
- char bit10 = 0;
-
- if (port == 0)
- return 0;
- if (already_got_parport(port))
- return 0;
- if (info_parports >= MAX_PARPORTS)
- return 0;
- prt = &info_parport[info_parports];
- prt->bit10 = 0;
- prt->max_xfer_size = 1;
- prt->port = port;
- prt->output_mode = PARPORT_MODE_STANDARD_STROBE_ACK;
- prt->type = PARPORT_STANDARD;
- prt->irq = -1;
- prt->dma = -1;
-
- /* this might be one of those EPP/ECP ports, set it to "standard byte mode" to enable the below test to find the port.
- * documentation mentions that "in ECP mode the SPP ports may disappear" so to successfully probe ports left in ECP
- * mode we have to write to the control register to bring it back.
- *
- * The (minimal) documentation I have doesn't say whether this port can be read back.
- * On older 10-bit decode hardware, this will probably only end up writing over the control bits (0x77A -> 0x37A)
- * and should be safe to carry out. On newer hardware (mid 90's) it's highly unlikely anything would be assigned
- * to I/O ports 0x778-0x77F. On newer PCI hardware, it's even less likely. */
- outp(prt->port+PARPORT_IO_ECP_CONTROL,1 << 5); /* mode=byte (bi-directional) ecpint=0 dma=0 ecpserv=0 */
-
- /* put it back into Standard mode, disable bi-directional */
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 */
- /* control ports are usually readable. if what we wrote didn't take then this is probably not a parallel port */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & 0xF) != 0x4) return 0;
-
- /* write to the control port again. if this is ancient 10-bit decode hardware, then it is probably NOT ECP/EPP
- * compliant. we detect this by whether this IO write corrupts the control register.
- * note control = port+2 and extended control = port+0x402 */
- outp(prt->port+PARPORT_IO_ECP_CONTROL,(1 << 5) | 0xC); /* CONTROL = sets bidirectional, and two control lines. EXTCTRL = maintains byte mode and turns on ECP interrupt+DMA */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & 0xF) == 0xC) /* if the +0x402 IO write changed the control register, then it's 10-bit decode and not EPP/ECP */
- bit10 = 1;
-
- outp(prt->port+PARPORT_IO_ECP_CONTROL,(1 << 5) | 0x0); /* regain sane extended control */
- outp(prt->port+PARPORT_IO_CONTROL,0x04);
-
- /* the data port is write only, though you are always allowed to read it back.
- * on bidirectional ports this is how you read back data.
- * we do not attempt to write to the status port. it is read only. worse, on modern
- * systems it can conflict with the ISA Plug & Play protocol (0x279) */
- outp(prt->port,0x55); if (inp(prt->port) != 0x55) return 0;
- outp(prt->port,0xAA); if (inp(prt->port) != 0xAA) return 0;
- outp(prt->port,0xFF); if (inp(prt->port) != 0xFF) return 0;
- outp(prt->port,0x00); if (inp(prt->port) != 0x00) return 0;
-
- /* do a parport init printer */
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 */
- if ((inp(prt->port+PARPORT_IO_CONTROL)&0xF) != 0x4) return 0;
-
- /* try to toggle bit 5 (bi-directional enable) */
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 bidir=0 */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & (1 << 5)) == 0) {
- outp(prt->port+PARPORT_IO_CONTROL,0x24); /* select=0 init=1 autolinefeed=0 strobe=0 bidir=1 */
- if ((inp(prt->port+PARPORT_IO_CONTROL) & (1 << 5)) != 0)
- prt->type = PARPORT_BIDIRECTIONAL;
-
- outp(prt->port+PARPORT_IO_CONTROL,0x04); /* select=0 init=1 autolinefeed=0 strobe=0 bidir=0 */
- }
-
- /* standard I/O locations have standard IRQ assignments, apparently */
- prt->bit10 = bit10;
- if (prt->port == 0x3BC)
- prt->irq = 2;
- else if (prt->port == 0x378)
- prt->irq = 7;
- else if (prt->port == 0x278)
- prt->irq = 5;
-
- if (!bit10) { /* if not 10-bit decode, then check for ECP control registers */
- unsigned char a,b;
-
- /* detect ECP by attempting to enable the configuration mode */
- outp(prt->port+PARPORT_IO_ECP_CONTROL,7 << 5);
- a = inp(prt->port+PARPORT_IO_ECP_REG_A);
- b = inp(prt->port+PARPORT_IO_ECP_REG_B);
-
- if (a != 0xFF && b != 0xFF) {
- prt->type = PARPORT_ECP;
-
- switch ((a >> 4) & 7) {
- case 0: prt->max_xfer_size = 2; break;
- case 1: prt->max_xfer_size = 1; break;
- case 2: prt->max_xfer_size = 4; break;
- }
-
- switch ((b >> 3) & 7) {
- case 1: prt->irq = 7; break;
- case 2: prt->irq = 9; break;
- case 3: prt->irq = 10; break;
- case 4: prt->irq = 11; break;
- case 5: prt->irq = 14; break;
- case 6: prt->irq = 15; break;
- case 7: prt->irq = 5; break;
- }
-
- switch (b&7) {
- case 1: prt->dma = 1; break;
- case 2: prt->dma = 2; break;
- case 3: prt->dma = 3; break;
- case 5: prt->dma = 5; break;
- case 6: prt->dma = 6; break;
- case 7: prt->dma = 7; break;
- }
- }
-
- /* switch to EPP mode for the test below if the ECP port supports it */
- if (prt->type == PARPORT_ECP)
- outp(prt->port+PARPORT_IO_ECP_CONTROL,4 << 5);
- }
-
- /* an EPP port could conceivably exist on a 10-bit decode ISA card */
- /* NOTES: Toshiba laptops do NOT support EPP mode, only ECP. There appears to be a hardware
- * bug in decoding the 0x778-0x77F I/O region where port 0x77A is repeated on 0x77B,
- * 0x77C, etc.
- *
- * The Compaq LTE Elite supports EPP and ECP. It follows the standard in ignoring
- * the bidir bit when setting mode 0, but does not disable EPP registers when
- * mode is not EPP.
- * ... erm, well, at least I think the extra registers are EPP. The address port
- * always returns 0x00 and the data port always returns 0x25 (this is with nothing
- * attached to the parallel port). The problem is we can only detect if something
- * is there, we can't tell if it's an EPP port or just some ancient ISA card that
- * responds to 0x3FB-0x3FF with it's own weirdness. A Google search for Compaq LTE
- * Elite and parallel port suggests that there are tools to configure the port as
- * EPP, so obviously at some level it speaks EPP mode. */
- if (inp(prt->port+PARPORT_IO_EPP_ADDRESS) != 0xFF && inp(prt->port+PARPORT_IO_EPP_DATA) != 0xFF) {
- if (prt->type == PARPORT_ECP)
- prt->type = PARPORT_ECP_AND_EPP;
- else
- prt->type = PARPORT_EPP;
- }
-
- /* return the port to standard bidir mode */
- if (PARPORT_SUPPORTS_ECP(prt->type))
- outp(prt->port+PARPORT_IO_ECP_CONTROL,1 << 5);
-
- /* shut off the lines */
- outp(prt->port+PARPORT_IO_CONTROL,0x00); /* select=0 init=0 autolinefeed=0 strobe=0 bidir=0 */
- outp(prt->port+PARPORT_IO_DATA,0x00);
-
- info_parports++;
- return 1;
-}
-
+++ /dev/null
-/* WARNING: As usual for performance reasons this library generally does not
- * enable/disable interrupts (cli/sti). To avoid contention with
- * interrupt handlers the calling program should do that. */
-
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* parallel port types */
-enum {
- PARPORT_STANDARD=0,
- PARPORT_BIDIRECTIONAL,
- PARPORT_ECP,
- PARPORT_EPP,
- PARPORT_ECP_AND_EPP,
- PARPORT_MAX
-};
-
-/* modes modes */
-enum {
- PARPORT_MODE_STANDARD_STROBE_ACK=0, /* not on busy, pulse, wait for ack */
- PARPORT_MODE_STANDARD_STROBE, /* not on busy, pulse, don't wait for ack */
- PARPORT_MODE_FIFO, /* switch into FIFO mode, let h/w do handshaking */
- PARPORT_MODE_ECP, /* switch to ECP mode */
- PARPORT_MODE_EPP /* switch to EPP mode */
-};
-
-#define MAX_PARPORTS 4
-
-#define PARPORT_SUPPORTS_EPP(x) ((x) == PARPORT_EPP || (x) == PARPORT_ECP_AND_EPP)
-#define PARPORT_SUPPORTS_ECP(x) ((x) == PARPORT_ECP || (x) == PARPORT_ECP_AND_EPP)
-
-#define PARPORT_IO_DATA 0
-#define PARPORT_IO_STATUS 1
-#define PARPORT_IO_CONTROL 2
-#define PARPORT_IO_EPP_ADDRESS 3
-#define PARPORT_IO_EPP_DATA 4
-
-#define PARPORT_IO_ECP_REG_A 0x400
-#define PARPORT_IO_ECP_REG_B 0x401
-#define PARPORT_IO_ECP_CONTROL 0x402
-
-#define PARPORT_STATUS_nBUSY (1 << 7)
-#define PARPORT_STATUS_nACK (1 << 6)
-#define PARPORT_STATUS_PAPER_OUT (1 << 5)
-#define PARPORT_STATUS_SELECT (1 << 4)
-#define PARPORT_STATUS_nERROR (1 << 3)
-
-#define PARPORT_CTL_ENABLE_BIDIR (1 << 5)
-#define PARPORT_CTL_ENABLE_IRQ (1 << 4)
-#define PARPORT_CTL_SELECT_PRINTER (1 << 3)
-#define PARPORT_CTL_nINIT (1 << 2)
-#define PARPORT_CTL_LINEFEED (1 << 1)
-#define PARPORT_CTL_STROBE (1 << 0)
-
-#define STANDARD_PARPORT_PORTS 3
-
-struct info_parport {
- uint16_t port;
- /* 8 bits { */
- uint8_t type:4;
- uint8_t bit10:1;
- uint8_t max_xfer_size:3; /* in bytes */
- /* } */
- int8_t irq;
- int8_t dma;
- /* mode */
- uint8_t output_mode:3;
- uint8_t reserved:5;
-};
-
-extern const char * parport_type_str[PARPORT_MAX];
-extern int init_parports;
-extern int bios_parports;
-extern uint16_t standard_parport_ports[STANDARD_PARPORT_PORTS];
-extern struct info_parport info_parport[MAX_PARPORTS];
-extern int info_parports;
-
-uint16_t get_bios_parport(unsigned int index);
-int already_got_parport(uint16_t port);
-int probe_parport(uint16_t port);
-int add_pnp_parport(uint16_t port,int irq,int dma,int type);
-int init_parport();
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h>
-#include <hw/8259/8259.h>
-#include <hw/dos/doswin.h>
-#include <hw/parport/parport.h>
-
-#if defined(ISAPNP)
-#include <hw/isapnp/isapnp.h>
-#include <hw/parport/parpnp.h>
-#endif
-
-static struct info_parport *sprt = NULL;
-
-/* MODE: Standard unidirectional Parallel Port
- * USE: IBM compatible parallel port printer
- * SPEED: 150 KB/sec
- * COMPATIBLE: All parallel ports */
-int std_printer_write_parport(struct info_parport *prt,
-#if TARGET_MSDOS == 32
-const char *buf
-#else
-const char far *buf
-#endif
-,size_t len) {
- const signed long onesec = t8254_us2ticks(1000000UL); /* 1 second's worth of timer ticks */
- const signed long timeout_sec_init = onesec * 10L; /* 10 seconds */
- const unsigned long ms1 = t8254_us2ticks(10); /* I laugh at OSDev wiki for suggesting I wait 10ms! Most sources say at least 0.5uS */
- signed long timeout_sec = timeout_sec_init;
- t8254_time_t timer,ctimer;
- unsigned char ctl,st;
- int ret = 0;
-
- errno = 0;
- if (len == 0U)
- return 0;
-
- /* NTS: remember the timer return value counts DOWN, not UP */
- /* NTS: counting code borrowed from 8254 wait function */
-#define TMTRK ctimer = read_8254(0);\
- if (ctimer < timer) timeout_sec -= (signed long)(timer - ctimer);\
- else timeout_sec -= (signed long)(((uint16_t)timer + (uint16_t)t8254_counter[0] - (uint16_t)ctimer) & (uint16_t)0xFFFFU);\
- timer = ctimer
-
- timer = read_8254(0);
- ctl = inp(prt->port+PARPORT_IO_CONTROL) & ~(PARPORT_CTL_STROBE);
- outp(prt->port+PARPORT_IO_CONTROL,ctl);
-
- do {
- /* wait for not busy */
- do {
- st = inp(prt->port+PARPORT_IO_STATUS);
- if (st & PARPORT_STATUS_nBUSY) break; /* NTS: Various docs will confuse the fuck out of you over this, but what this bit really means is that when set the printer is NOT busy */
- TMTRK;
- if (timeout_sec < (signed long)(0L)) goto timeout;
- } while (1);
-
- /* write data */
- outp(prt->port+PARPORT_IO_DATA,*buf++);
- ret++;
-
- /* strobe for at least 1us */
- outp(prt->port+PARPORT_IO_CONTROL,ctl | PARPORT_CTL_STROBE);
- TMTRK;
- t8254_wait(ms1); timer = read_8254(0);
- outp(prt->port+PARPORT_IO_CONTROL,ctl);
-
- /* now: some sources say it is done when BUSY goes low, and some
- * say that the printer might hold BUSY high but signal ACK.
- * whatever, we'll break out when either is true.
- *
- * if neither happens, then it counts as a timeout. */
- do {
- st = inp(prt->port+PARPORT_IO_STATUS);
- if (st & PARPORT_STATUS_nBUSY) break; /* NTS: Various docs will confuse the fuck out of you over this, but what this bit really means is that when set the printer is NOT busy */
- else if (!(st & PARPORT_STATUS_nACK)) break; /* Likewise, when this bit is NOT set the printer has acknowledged the byte */
- TMTRK;
- if (timeout_sec < (signed long)(0L)) goto timeout;
- } while (1);
-
- if (!(st & PARPORT_STATUS_nERROR)) goto error; /* NTS: Again.... if NOT set the printer reports an error. Nice of them to invert certain bits, eh? */
- } while (--len != 0U);
-
-#undef TMTRK
- return ret > 0 ? ret : -1;
-timeout:
- errno = EBUSY;
- return ret > 0 ? ret : -1;
-error:
- errno = EIO;
- return ret > 0 ? ret : -1;
-}
-
-int init_select_printer_parport(struct info_parport *sprt) {
- /* reset the printer */
- outp(sprt->port+PARPORT_IO_CONTROL,PARPORT_CTL_SELECT_PRINTER); /* select printer, init (bit 2 == 0) */
- t8254_wait(t8254_us2ticks(100000UL)); /* 100ms */
- outp(sprt->port+PARPORT_IO_CONTROL,PARPORT_CTL_SELECT_PRINTER | PARPORT_CTL_nINIT); /* select printer, not init */
- t8254_wait(t8254_us2ticks(10000UL)); /* 10ms */
- return (inp(sprt->port+PARPORT_IO_STATUS) & PARPORT_STATUS_SELECT);
-}
-
-int main() {
- char buf[1024],c;
- int i,rd,x;
-
- printf("PC parallel printer port test program (print)\n");
-#ifdef ISAPNP
- printf("ISA Plug & Play version\n");
-#endif
-
- cpu_probe(); /* ..for the DOS probe routine */
- probe_dos(); /* ..for the Windows detection code */
- detect_windows(); /* Windows virtualizes the LPT ports, and we don't want probing to occur to avoid any disruption */
-
- if (!probe_8254()) {
- printf("8254 not found (I need this for time-sensitive portions of the driver)\n");
- return 1;
- }
-
- if (!probe_8259()) {
- printf("8259 not found (I need this for portions of the test involving serial interrupts)\n");
- return 1;
- }
-
- if (!init_parport()) {
- printf("Cannot init parport library\n");
- return 1;
- }
-
-#ifdef ISAPNP
- if (!init_isa_pnp_bios()) {
- printf("Cannot init ISA PnP\n");
- return 1;
- }
- if (find_isa_pnp_bios()) pnp_parport_scan();
- else printf("Warning, ISA PnP BIOS not found\n");
-#else
- printf("Probing BIOS-listed locations ");
- for (i=0;i < bios_parports;i++) {
- uint16_t port = get_bios_parport(i);
- printf("%03x ",port);
- if (probe_parport(port)) printf("[OK] ");
- fflush(stdout);
- }
- printf("\n");
-
- printf("Probing standard port locations ");
- for (i=0;i < STANDARD_PARPORT_PORTS;i++) {
- uint16_t port = standard_parport_ports[i];
- printf("%03x ",port);
- if (probe_parport(port)) printf("[OK] ");
- fflush(stdout);
- }
- printf("\n");
-#endif
-
- printf("Found parallel ports:\n");
- for (i=0;i < info_parports;i++) {
- struct info_parport *prt = &info_parport[i];
- printf(" [%u] port=0x%04x IRQ=%d DMA=%d 10-bit=%u max-xfer-size=%u type='%s'\n",i+1,prt->port,prt->irq,prt->dma,prt->bit10,prt->max_xfer_size,parport_type_str[prt->type]);
- }
-
- printf("Choice? "); fflush(stdout);
- i = 1; scanf("%d",&i); i--;
- if (i < 0 || i >= info_parports) return 1;
- sprt = &info_parport[i];
-
- /* this function will return zero if the SELECT line does not raise, usually the sign
- * a printer is not attached or some non-printer thing is connected */
- if (!init_select_printer_parport(sprt)) {
- fprintf(stderr,"WARNING: I don't see the printer raising the SELECT line in return.\n");
- fprintf(stderr," Usually this means the device is a non-printer, or nothing is\n");
- fprintf(stderr," attached to the port.\n");
- }
-
- while (1) {
- printf("1. print test message 2. print user input 3. Reinitialize 4. Formfeed\n");
- c = getch();
- if (c == 27)
- break;
- else if (c == '1') {
- const char *msg = "Testing testing 1 2 3.\r\n" "The quick brown fox jumps over the fence\r\n" "\x0C"; /* page feed */
- printf("Sending...\n");
- rd = strlen(msg);
- x = std_printer_write_parport(sprt,msg,rd);
- if (x < rd) printf("Timeout writing message. Len=%u wrote=%d\n",rd,x);
- }
- else if (c == '2') {
- printf("What do you want to send? (type below %u max)\n",sizeof(buf)-1);
- buf[0] = 0; fgets(buf,sizeof(buf)-1,stdin);
- printf("Sending '%s'\n",buf);
- rd = strlen(buf);
- x = std_printer_write_parport(sprt,buf,rd);
- if (x < rd) printf("Timeout writing message. Len=%u wrote=%d\n",rd,x);
- }
- else if (c == '3') {
- if (!init_select_printer_parport(sprt)) {
- fprintf(stderr,"WARNING: I don't see the printer raising the SELECT line in return.\n");
- fprintf(stderr," Usually this means the device is a non-printer, or nothing is\n");
- fprintf(stderr," attached to the port.\n");
- }
- }
- else if (c == '4') {
- const char *msg = "\x0C"; /* page feed */
- printf("Sending...\n");
- rd = strlen(msg);
- x = std_printer_write_parport(sprt,msg,rd);
- if (x < rd) printf("Timeout writing message. Len=%u wrote=%d\n",rd,x);
- }
- }
-
- outp(sprt->port+PARPORT_IO_CONTROL,PARPORT_CTL_nINIT); /* unselect printer, not init */
-
- return 0;
-}
-
+++ /dev/null
-/* I'm sorry */
-#define ISAPNP
-#include "prnt.c"
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h>
-#include <hw/8259/8259.h>
-#include <hw/dos/doswin.h>
-#include <hw/parport/parport.h>
-
-#include <hw/isapnp/isapnp.h>
-#include <hw/parport/parpnp.h>
-
-static struct info_parport *sprt = NULL;
-
-/* NTS: Not suitable for reads that take longer than 1/18.2th of a second.
- * this function is better suited to establishing a baseline speed from small
- * read tests that are very likely to fall within the 18.2Hz tick rate of the
- * system timer. also, bytecount is 16-bit on real-mode builds and cannot
- * count beyond 64KB.
- *
- * WARNING: do not call with bytecount == 0! */
-unsigned int tight_read_test(unsigned int bytecount,unsigned int io_port) {
- unsigned int b_tim,e_tim;
-
- b_tim = read_8254(0);
-#if TARGET_MSDOS == 32
- __asm {
- cli
- push ecx
- push edx
- mov ecx,bytecount
- mov edx,io_port
-l1: in al,dx ; tight loop: read as FAST as you can!
- loop l1
- pop edx
- pop ecx
- sti
- }
-#else
- __asm {
- cli
- push cx
- push dx
- mov cx,bytecount
- mov dx,io_port
-l1: in al,dx ; tight loop: read as FAST as you can!
- loop l1
- pop dx
- pop cx
- sti
- }
-#endif
- e_tim = read_8254(0);
-
- /* elapsed time? remember the timer counts downward! and wraps around within 16 bits */
- b_tim = (b_tim - e_tim) & 0xFFFF;
-
- return b_tim;
-}
-
-/* NTS: Not suitable for reads that take longer than 1/18.2th of a second.
- * this function is better suited to establishing a baseline speed from small
- * read tests that are very likely to fall within the 18.2Hz tick rate of the
- * system timer. also, bytecount is 16-bit on real-mode builds and cannot
- * count beyond 64KB.
- *
- * WARNING: do not call with bytecount == 0! */
-unsigned int tight_memstore_read_test(unsigned int bytecount,unsigned int io_port) {
- unsigned int b_tim,e_tim;
- unsigned char c=0xFF;
-
- b_tim = read_8254(0);
-#if TARGET_MSDOS == 32
- __asm {
- cli
- push esi
- push ecx
- push edx
- mov ecx,bytecount
- mov edx,io_port
-l1: in al,dx ; tight loop: read as FAST as you can!
- mov c,al
- inc esi
- loop l1
- pop edx
- pop ecx
- pop esi
- sti
- }
-#else
- __asm {
- cli
- push si
- push cx
- push dx
- mov cx,bytecount
- mov dx,io_port
-l1: in al,dx ; tight loop: read as FAST as you can!
- mov c,al
- inc si
- loop l1
- pop dx
- pop cx
- pop si
- sti
- }
-#endif
- e_tim = read_8254(0);
-
- /* elapsed time? remember the timer counts downward! and wraps around within 16 bits */
- b_tim = (b_tim - e_tim) & 0xFFFF;
-
- return b_tim;
-}
-
-static unsigned int statr_test_reads[] = {512,1024,2048,4096,6000,8192,12000,16384,23000,32768,46000,65500};
-
-int main() {
- unsigned long time_tc,time_rb; /* time passed, in tc */
- double statr_rate,statr_time;
- int i,avgcount=0;
- double avgsum=0;
-
- printf("PC parallel printer port test program (print)\n");
-
- cpu_probe(); /* ..for the DOS probe routine */
- probe_dos(); /* ..for the Windows detection code */
- detect_windows(); /* Windows virtualizes the LPT ports, and we don't want probing to occur to avoid any disruption */
-
- if (!probe_8254()) {
- printf("8254 not found (I need this for time-sensitive portions of the driver)\n");
- return 1;
- }
-
- if (!probe_8259()) {
- printf("8259 not found (I need this for portions of the test involving serial interrupts)\n");
- return 1;
- }
-
- if (!init_parport()) {
- printf("Cannot init parport library\n");
- return 1;
- }
-
- if (init_isa_pnp_bios()) {
- if (find_isa_pnp_bios()) {
- printf("ISA PnP BIOS found, probing for PnP ports\n");
- pnp_parport_scan();
- }
- }
-
- printf("Probing BIOS-listed locations ");
- for (i=0;i < bios_parports;i++) {
- uint16_t port = get_bios_parport(i);
- printf("%03x ",port);
- if (probe_parport(port)) printf("[OK] ");
- fflush(stdout);
- }
- printf("\n");
-
- printf("Probing standard port locations ");
- for (i=0;i < STANDARD_PARPORT_PORTS;i++) {
- uint16_t port = standard_parport_ports[i];
- printf("%03x ",port);
- if (probe_parport(port)) printf("[OK] ");
- fflush(stdout);
- }
- printf("\n");
-
- printf("Found parallel ports:\n");
- for (i=0;i < info_parports;i++) {
- struct info_parport *prt = &info_parport[i];
- printf(" [%u] port=0x%04x IRQ=%d DMA=%d 10-bit=%u max-xfer-size=%u type='%s'\n",i+1,prt->port,prt->irq,prt->dma,prt->bit10,prt->max_xfer_size,parport_type_str[prt->type]);
- }
-
- printf("Choice? "); fflush(stdout);
- i = 1; scanf("%d",&i); i--;
- if (i < 0 || i >= info_parports) return 1;
- sprt = &info_parport[i];
-
- write_8254_system_timer(0); /* make sure the timer is in rate generator mode, full counter */
-
- avgsum = 0; avgcount = 0;
- printf("Timing test: tight loop (no memory store) reading status port:\n");
- for (i=0;i < (int)(sizeof(statr_test_reads)/sizeof(statr_test_reads[0]));i++) {
- time_rb = statr_test_reads[i];
- if (i != 0) {
- /* compute how long this iteration will take. if we estimate the test
- * will take longer than 1/25 seconds, stop now. if the test takes
- * longer than the full countdown interval of the 8254 we cannot time
- * it properly. */
- double et = (double)time_rb / (avgsum / avgcount);
- if (et > (1.0 / 25)) break;
- }
-
- time_tc = tight_read_test(time_rb,sprt->port+PARPORT_IO_STATUS);
- statr_time = ((double)time_tc * 1000) / T8254_REF_CLOCK_HZ;
- statr_rate = ((double)1000 * time_rb) / statr_time;
- printf(" ... %lu bytes: %.6f ms (%.1f samp/sec)\n",time_rb,statr_time,statr_rate);
- avgsum += statr_rate; avgcount++;
- }
- avgsum /= avgcount;
- printf(" result >> %.1f samples/sec\n",avgsum);
-
- avgsum = 0; avgcount = 0;
- printf("Timing test: tight loop (no memory store) reading data port:\n");
- for (i=0;i < (int)(sizeof(statr_test_reads)/sizeof(statr_test_reads[0]));i++) {
- time_rb = statr_test_reads[i];
- if (i != 0) {
- /* compute how long this iteration will take. if we estimate the test
- * will take longer than 1/25 seconds, stop now. if the test takes
- * longer than the full countdown interval of the 8254 we cannot time
- * it properly. */
- double et = (double)time_rb / (avgsum / avgcount);
- if (et > (1.0 / 25)) break;
- }
-
- time_tc = tight_read_test(time_rb,sprt->port+PARPORT_IO_DATA);
- statr_time = ((double)time_tc * 1000) / T8254_REF_CLOCK_HZ;
- statr_rate = ((double)1000 * time_rb) / statr_time;
- printf(" ... %lu bytes: %.6f ms (%.1f samp/sec)\n",time_rb,statr_time,statr_rate);
- avgsum += statr_rate; avgcount++;
- }
- avgsum /= avgcount;
- printf(" result >> %.1f samples/sec\n",avgsum);
-
-
- avgsum = 0; avgcount = 0;
- printf("Timing test: tight loop with memory store reading status port:\n");
- for (i=0;i < (int)(sizeof(statr_test_reads)/sizeof(statr_test_reads[0]));i++) {
- time_rb = statr_test_reads[i];
- if (i != 0) {
- /* compute how long this iteration will take. if we estimate the test
- * will take longer than 1/25 seconds, stop now. if the test takes
- * longer than the full countdown interval of the 8254 we cannot time
- * it properly. */
- double et = (double)time_rb / (avgsum / avgcount);
- if (et > (1.0 / 25)) break;
- }
-
- time_tc = tight_memstore_read_test(time_rb,sprt->port+PARPORT_IO_STATUS);
- statr_time = ((double)time_tc * 1000) / T8254_REF_CLOCK_HZ;
- statr_rate = ((double)1000 * time_rb) / statr_time;
- printf(" ... %lu bytes: %.6f ms (%.1f samp/sec)\n",time_rb,statr_time,statr_rate);
- avgsum += statr_rate; avgcount++;
- }
- avgsum /= avgcount;
- printf(" result >> %.1f samples/sec\n",avgsum);
-
- avgsum = 0; avgcount = 0;
- printf("Timing test: tight loop with memory store reading data port:\n");
- for (i=0;i < (int)(sizeof(statr_test_reads)/sizeof(statr_test_reads[0]));i++) {
- time_rb = statr_test_reads[i];
- if (i != 0) {
- /* compute how long this iteration will take. if we estimate the test
- * will take longer than 1/25 seconds, stop now. if the test takes
- * longer than the full countdown interval of the 8254 we cannot time
- * it properly. */
- double et = (double)time_rb / (avgsum / avgcount);
- if (et > (1.0 / 25)) break;
- }
-
- time_tc = tight_memstore_read_test(time_rb,sprt->port+PARPORT_IO_DATA);
- statr_time = ((double)time_tc * 1000) / T8254_REF_CLOCK_HZ;
- statr_rate = ((double)1000 * time_rb) / statr_time;
- printf(" ... %lu bytes: %.6f ms (%.1f samp/sec)\n",time_rb,statr_time,statr_rate);
- avgsum += statr_rate; avgcount++;
- }
- avgsum /= avgcount;
- printf(" result >> %.1f samples/sec\n",avgsum);
-
- return 0;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h>
-#include <hw/8259/8259.h>
-#include <hw/dos/doswin.h>
-#include <hw/parport/parport.h>
-
-#if defined(ISAPNP)
-#include <hw/isapnp/isapnp.h>
-#include <hw/parport/parpnp.h>
-#endif
-
-int main() {
- int i;
-
- printf("PC parallel printer port test program\n");
-#ifdef ISAPNP
- printf("ISA Plug & Play version\n");
-#endif
-
- cpu_probe(); /* ..for the DOS probe routine */
- probe_dos(); /* ..for the Windows detection code */
- detect_windows(); /* Windows virtualizes the LPT ports, and we don't want probing to occur to avoid any disruption */
-
- if (!probe_8254()) {
- printf("8254 not found (I need this for time-sensitive portions of the driver)\n");
- return 1;
- }
-
- if (!probe_8259()) {
- printf("8259 not found (I need this for portions of the test involving serial interrupts)\n");
- return 1;
- }
-
- if (!init_parport()) {
- printf("Cannot init parport library\n");
- return 1;
- }
-
-#ifdef ISAPNP
- if (!init_isa_pnp_bios()) {
- printf("Cannot init ISA PnP\n");
- return 1;
- }
- if (find_isa_pnp_bios()) pnp_parport_scan();
- else printf("Warning, ISA PnP BIOS not found\n");
-#else
- printf("Probing BIOS-listed locations ");
- for (i=0;i < bios_parports;i++) {
- uint16_t port = get_bios_parport(i);
- printf("%03x ",port);
- if (probe_parport(port)) printf("[OK] ");
- fflush(stdout);
- }
- printf("\n");
-
- printf("Probing standard port locations ");
- for (i=0;i < STANDARD_PARPORT_PORTS;i++) {
- uint16_t port = standard_parport_ports[i];
- printf("%03x ",port);
- if (probe_parport(port)) printf("[OK] ");
- fflush(stdout);
- }
- printf("\n");
-#endif
-
- printf("Found parallel ports:\n");
- for (i=0;i < info_parports;i++) {
- struct info_parport *prt = &info_parport[i];
- printf(" [%u] port=0x%04x IRQ=%d DMA=%d 10-bit=%u max-xfer-size=%u type='%s'\n",i+1,prt->port,prt->irq,prt->dma,prt->bit10,prt->max_xfer_size,parport_type_str[prt->type]);
- }
-
- return 0;
-}
-
+++ /dev/null
-/* I'm sorry */
-#define ISAPNP
-#include "test.c"
-
+++ /dev/null
-Parallel port:
-
- Write function for "fast centronics" output mode.
- Experiment with bidirectional mode.
- ECP programming practice.
- EPP mode?
- Disney Sound Source example (SELECT=0 and send data according to FIFO).
- Covox Speech Thing example (just write data at fixed rate).
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_PCI_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-AFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NASMFLAGS_THIS =
-
-# NTS: CPU functions here are to be moved at some point to the cpu library!
-C_SOURCE = pci.c
-OBJS = $(SUBDIR)$(HPS)pci.obj $(SUBDIR)$(HPS)pcibios1.obj
-HW_PCI_LIB = $(SUBDIR)$(HPS)pci.lib
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_PCI_LIB): $(OBJS)
- wlib -q -b -c $(HW_PCI_LIB) -+$(SUBDIR)$(HPS)pci.obj
- wlib -q -b -c $(HW_PCI_LIB) -+$(SUBDIR)$(HPS)pcibios1.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-lib: $(HW_PCI_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_PCI_LIB) $(HW_PCI_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_PCI_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_PCI_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-/* NTS: It's not required in the DOS environment, but in the unlikely event that
- * interrupt handlers are mucking around with PCI configuration space you
- * may want to bracket your PCI operations with CLI/STI. Again for performance
- * reasons, this code will NOT do it for you */
-/* NTS: Additional research suggests that on legacy systems with 10-bit decoding
- * I/O ports 0xCF8-0xCFF are unlikely to collide with 287/387 legacy I/O
- * ports 0xF0-0xF7 (as I initially thought), therefore probing 0xCF8 on
- * ancient systems should do no harm and not cause any problems. */
-
-/* This library enables programming the PCI bus that may be available to DOS level
- * programs on Pentium and higher systems (where PCI slots were first common on
- * home desktop PCs)
- *
- * This code is designed to compile 16-bit and 32-bit versions. The 16-bit real
- * mode versions are designed with DOS programs in mind that might want the ability
- * to fiddle with the PCI bus and program registers while maintaining downlevel
- * compatability with older hardware, perhaps all the way down to the 8086. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/pci/pci.h>
-#include <hw/cpu/cpu.h>
-
-unsigned char pci_cfg_probed = 0;
-unsigned char pci_cfg = PCI_CFG_NONE;
-uint32_t pci_bios_protmode_entry_point = 0;
-uint8_t pci_bios_hw_characteristics = 0;
-uint16_t pci_bios_interface_level = 0;
-uint8_t pci_bus_decode_bits = 0; /* which bus bits the hardware actually bothers to compare against */
-int16_t pci_bios_last_bus = 0;
-
-/* external assembly language functions */
-int try_pci_bios2();
-int try_pci_bios1();
-#if TARGET_MSDOS == 16
-uint32_t __cdecl pci_bios_read_dword_16(uint16_t bx,uint16_t di);
-void __cdecl pci_bios_write_dword_16(uint16_t bx,uint16_t di,uint32_t data);
-#endif
-
-/* NTS: Programming experience tells me that depite what this bitfield arrangement
- * suggests, most PCI devices ignore bits 0-1 of the register number and expect
- * you to offset the read from the 0xCFC register instead. */
-void pci_type1_select(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg) {
- outpd(0xCF8,0x80000000UL |
- (((uint32_t)bus) << 16UL) |
- (((uint32_t)card) << 11UL) |
- (((uint32_t)func) << 8UL) |
- ((uint32_t)(reg & 0xFC)));
-}
-
-void pci_type2_select(uint8_t bus,uint8_t func) {
- /* FIXME: Is this right? Documentation is sparse and hard to come by... */
- outp(0xCF8,0x80 | (func << 1));
- outp(0xCFA,bus);
-}
-
-uint32_t pci_read_cfg_TYPE1(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size) {
- pci_type1_select(bus,card,func,reg);
- switch (size) {
- case 2: return inpd(0xCFC);
- case 1: return inpw(0xCFC+(reg&3));
- case 0: return inp(0xCFC+(reg&3));
- }
-
- return ~0UL;
-}
-
-/* WARNING: I have no hardware to verify this works */
-uint32_t pci_read_cfg_TYPE2(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size) {
- const uint16_t pt = 0xC000 + (card << 8) + reg;
- pci_type2_select(bus,func);
- switch (size) {
- case 2: return inpd(pt);
- case 1: return inpw(pt);
- case 0: return inp(pt);
- }
-
- return ~0UL;
-}
-
-uint32_t pci_read_cfg_BIOS(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size) {
- static const uint32_t msks[3] = {0xFFUL,0xFFFFUL,0xFFFFFFFFUL};
- union REGS regs;
-
- if (size > 2) return ~0UL;
-#if TARGET_MSDOS == 16
- if (size == 2) { /* 32-bit DWORD read in real mode when Watcom won't let me use 386 style registers or int386() */
- return pci_bios_read_dword_16(
- /* BH=bus BL(7-3)=card BL(2-0)=func */
- (bus << 8) | (card << 3) | func,
- /* DI=reg */
- reg);
- return ~0UL;
- }
-#endif
-
- regs.w.ax = 0xB108 + size;
- regs.w.bx = (bus << 8) | (card << 3) | func;
- regs.w.di = reg;
-#if TARGET_MSDOS == 32
- int386(0x1A,®s,®s);
-#else
- int86(0x1A,®s,®s);
-#endif
- if (regs.w.cflag & 1) /* carry flag set on error */
- return ~0UL;
- if (regs.h.ah != 0x00) /* AH=0x00 if success */
- return ~0UL;
-
-#if TARGET_MSDOS == 32
- return regs.x.ecx & msks[size];
-#else
- return regs.w.cx & msks[size];
-#endif
-}
-
-uint32_t pci_read_cfg_NOTIMPL(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size) {
- return ~0UL;
-}
-
-void pci_write_cfg_TYPE1(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size) {
- pci_type1_select(bus,card,func,reg);
- switch (size) {
- case 2: outpd(0xCFC,data);
- case 1: outpw(0xCFC+(reg&3),data);
- case 0: outp(0xCFC+(reg&3),data);
- }
-}
-
-/* WARNING: I have no hardware to verify this works */
-void pci_write_cfg_TYPE2(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size) {
- const uint16_t pt = 0xC000 + (card << 8) + reg;
- pci_type2_select(bus,func);
- switch (size) {
- case 2: outpd(pt,data);
- case 1: outpw(pt,data);
- case 0: outp(pt,data);
- }
-}
-
-void pci_write_cfg_BIOS(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size) {
- union REGS regs;
-
- if (size > 2) return;
-#if TARGET_MSDOS == 16
- if (size == 2) { /* 32-bit DWORD read in real mode when Watcom won't let me use 386 style registers or int386() */
- pci_bios_write_dword_16(
- /* BH=bus BL(7-3)=card BL(2-0)=func */
- (bus << 8) | (card << 3) | func,
- /* DI=reg */
- reg,
- /* data */
- data);
- return;
- }
-#endif
-
- regs.w.ax = 0xB10B + size;
- regs.w.bx = (bus << 8) | (card << 3) | func;
- regs.w.di = reg;
-#if TARGET_MSDOS == 32
- regs.x.ecx = data;
- int386(0x1A,®s,®s);
-#else
- regs.w.cx = (uint16_t)data;
- int86(0x1A,®s,®s);
-#endif
-}
-
-void pci_write_cfg_NOTIMPL(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size) {
-}
-
-void pci_probe_for_last_bus() {
- /* scan backwards until we find a root PCI device that doesn't return 0xFFFF for ID.
- * but also keep track of the IDs because some PCI busses (especially ancient Pentium
- * based laptops) don't bother decoding the bus field. If we're not careful, we could
- * erroneously come up with 16 busses attached, each having the same device list 16
- * times */
- uint32_t id[16],bar[16],sub[16];
- uint8_t bus;
-
- for (bus=0;bus < 16;bus++) {
- id[bus] = pci_read_cfgl(bus,0,0,0x00);
- bar[bus] = pci_read_cfgl(bus,0,0,0x10);
- sub[bus] = pci_read_cfgl(bus,0,0,0x2C);
- }
-
- /* check for cheap PCI busses that don't decode the BUS field of the PCI configuration register */
- bus = 3;
- pci_bus_decode_bits = bus + 1;
- do {
- uint8_t pm = 1 << bus;
- if (id[pm] == id[0] && bar[pm] == bar[0] && sub[pm] == sub[0]) {
- uint8_t ii;
-
- /* looks like a mirror image to me. rub it out */
- pci_bus_decode_bits = bus;
- for (ii=pm;ii < (2 << bus);ii++) {
- id[ii] = bar[ii] = sub[ii] = ~0UL;
- }
- }
- else {
- /* not a match, so it's probably not wise to check further */
- break;
- }
- } while (bus-- != 0);
-
- /* now check for the last working root device, and mark that */
- for (bus=0xF;bus != 0 && id[bus] == ~0UL;) bus--;
- pci_bios_last_bus = bus;
-}
-
-int try_pci_type2() {
- int ret = 0;
- outp(0xCF8,0);
- outp(0xCFA,0);
- if (inp(0xCF8) == 0 && inp(0xCFA) == 0) ret = 1;
- return ret;
-}
-
-int try_pci_type1() {
- int ret = 0;
- uint32_t tmp = inpd(0xCF8);
- outpd(0xCF8,0x80000000);
- if (inpd(0xCF8) == 0x80000000 && inpd(0xCFC) != 0xFFFFFFFFUL) ret=1; /* might be type 2 reflecting written data */
- outpd(0xCF8,tmp);
- return ret;
-}
-
-/* WARNING: Uses 32-bit I/O. The caller is expected to have first called the CPU library to determine we are a 386 or higher */
-int pci_probe(int preference) {
- if (pci_cfg_probed)
- return pci_cfg;
-
-#if TARGET_MSDOS == 16
- /* This code won't even run on pre-386 if compiled 32-bit, so this check is limited only to 16-bit real mode builds that might be run on such hardware */
- if (cpu_basic_level < 3) /* NTS: I'm aware this variable is initialized to ~0 (255) first */
- return PCI_CFG_NONE; /* if the programmer is not checking the CPU he either doesn't care about pre-386 systems or he is stupid, so go ahead and do it anyway */
-#endif
-
- pci_bios_protmode_entry_point = 0;
- pci_bios_hw_characteristics = 0;
- pci_bios_interface_level = 0;
- pci_cfg = PCI_CFG_NONE;
- pci_bios_last_bus = -1; /* -1 means "I don't know" */
- pci_bus_decode_bits = 4;
-
- switch (preference) {
- case PCI_CFG_TYPE1:
- if (try_pci_type1()) pci_cfg = PCI_CFG_TYPE1;
- break;
- case PCI_CFG_BIOS:
- if (try_pci_bios2()) pci_cfg = PCI_CFG_BIOS;
- break;
- case PCI_CFG_TYPE2:
- if (try_pci_type2()) pci_cfg = PCI_CFG_TYPE2;
- break;
- case PCI_CFG_BIOS1:
- if (try_pci_bios1()) pci_cfg = PCI_CFG_BIOS1;
- break;
- default:
- if (pci_cfg == PCI_CFG_NONE) { /* Type 1? This is most common, and widely supported */
- if (try_pci_type1()) pci_cfg = PCI_CFG_TYPE1;
- }
- if (pci_cfg == PCI_CFG_NONE) {
- if (try_pci_bios2()) pci_cfg = PCI_CFG_BIOS;
- }
- if (pci_cfg == PCI_CFG_NONE) { /* Type 2? This is rare, I have no hardware that supports this... */
- if (try_pci_type2()) pci_cfg = PCI_CFG_TYPE2;
- }
- if (pci_cfg == PCI_CFG_NONE) {
- if (try_pci_bios1()) pci_cfg = PCI_CFG_BIOS1;
- }
- break;
- }
-
- pci_cfg_probed = 1;
- return pci_cfg;
-}
-
-uint32_t (*pci_read_cfg_array[PCI_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size) = {
- pci_read_cfg_NOTIMPL, /* NONE */
- pci_read_cfg_TYPE1, /* TYPE1 */
- pci_read_cfg_BIOS, /* BIOS */
- pci_read_cfg_NOTIMPL, /* BIOS1 */
- pci_read_cfg_TYPE2 /* TYPE2 */
-};
-
-void (*pci_write_cfg_array[PCI_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size) = {
- pci_write_cfg_NOTIMPL, /* NONE */
- pci_write_cfg_TYPE1, /* TYPE1 */
- pci_write_cfg_BIOS, /* BIOS */
- pci_write_cfg_NOTIMPL, /* BIOS1 */
- pci_write_cfg_TYPE2 /* TYPE2 */
-};
-
-uint8_t pci_probe_device_functions(uint8_t bus,uint8_t dev) {
- uint8_t funcs=8,f;
- uint32_t id[8],bar[8],sub[8];
-
- /* some laptop PCI chipsets, believe it or not, decode bus and device numbers but ignore the function index.
- * if we're not careful, we could end up with the misconception that there were 8 of each PCI device present. */
-
- for (f=0;f < 8;f++) {
- id[f] = pci_read_cfgl(bus,dev,f,0x00);
- bar[f] = pci_read_cfgl(bus,dev,f,0x10);
- sub[f] = pci_read_cfgl(bus,dev,f,0x2C);
- if (f == 0 && id[f] == 0xFFFFFFFFUL) return 0;
- }
-
- while (funcs > 1) {
- f = funcs >> 1;
- if (id[0] == id[f] && bar[0] == bar[f] && sub[0] == sub[f])
- funcs = f;
- else
- break;
- }
-
- return funcs;
-}
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* there are 3 methods supported by this library
- * (FIXME: Well, I don't have code to support Configuration Type 2 because I don't have hardware that speaks that...) */
-enum {
- PCI_CFG_NONE=0,
- PCI_CFG_TYPE1, /* Configuration Type 1 (most common) */
- PCI_CFG_BIOS, /* Use the BIOS (PCI 2.0c interface) */
- PCI_CFG_BIOS1, /* Use the BIOS (PCI 1.x interface) (FIXME: I don't have any hardware who's BIOS implements this) */
- PCI_CFG_TYPE2, /* Configuration Type 2 (FIXME: I don't have any hardware that emulates or supports this method) */
- PCI_CFG_MAX
-};
-
-#define pci_read_cfgl(b,c,f,r) pci_read_cfg_array[pci_cfg](b,c,f,r,2)
-#define pci_read_cfgw(b,c,f,r) pci_read_cfg_array[pci_cfg](b,c,f,r,1)
-#define pci_read_cfgb(b,c,f,r) pci_read_cfg_array[pci_cfg](b,c,f,r,0)
-
-#define pci_write_cfgl(b,c,f,r,d) pci_write_cfg_array[pci_cfg](b,c,f,r,d,2)
-#define pci_write_cfgw(b,c,f,r,d) pci_write_cfg_array[pci_cfg](b,c,f,r,d,1)
-#define pci_write_cfgb(b,c,f,r,d) pci_write_cfg_array[pci_cfg](b,c,f,r,d,0)
-
-extern unsigned char pci_cfg;
-extern unsigned char pci_cfg_probed;
-extern uint32_t pci_bios_protmode_entry_point;
-extern uint8_t pci_bios_hw_characteristics;
-extern uint16_t pci_bios_interface_level;
-extern uint8_t pci_bus_decode_bits;
-extern int16_t pci_bios_last_bus;
-
-void pci_type1_select(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg);
-void pci_type2_select(uint8_t bus,uint8_t func);
-uint32_t pci_read_cfg_TYPE1(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size);
-uint32_t pci_read_cfg_TYPE2(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size);
-uint32_t pci_read_cfg_BIOS(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size);
-uint32_t pci_read_cfg_NOTIMPL(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size);
-void pci_write_cfg_TYPE1(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size);
-void pci_write_cfg_TYPE2(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size);
-void pci_write_cfg_BIOS(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size);
-void pci_write_cfg_NOTIMPL(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size);
-uint8_t pci_probe_device_functions(uint8_t bus,uint8_t dev);
-void pci_probe_for_last_bus();
-int pci_probe(int preference);
-
-extern uint32_t (*pci_read_cfg_array[PCI_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint8_t size);
-extern void (*pci_write_cfg_array[PCI_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint8_t reg,uint32_t data,uint8_t size);
-
-
+++ /dev/null
-
-; NTS: We use NASM to achieve our goals here because WASM sucks donkey balls
-; Maybe when they bother to implement a proper conditional macro system, I'll consider it...
-
-global try_pci_bios1_
-global try_pci_bios2_
-global _pci_bios_read_dword_16
-global _pci_bios_write_dword_16
-extern _pci_bios_protmode_entry_point ; 32-bit
-extern _pci_bios_hw_characteristics ; 8-bit
-extern _pci_bios_last_bus ; 16-bit
-extern _pci_bios_interface_level ; 16-bit
-
-section .text
-
-%if TARGET_MSDOS == 32
-%define point_s esi
-%define result eax
-%define pushan pushad
-%define popan popad
-%define pushfn pushfd
-%define popfn popfd
-use32
-%else
-%define point_s si
-%define result ax
-%define pushan pusha
-%define popan popa
-%define pushfn pushf
-%define popfn popf
-use16
-%endif
-
-%if TARGET_MSDOS == 16
- %ifndef MMODE
- %error You must specify MMODE variable (memory model) for 16-bit real mode code
- %endif
-%endif
-
-%if TARGET_MSDOS == 16
- ; large & medium memory models have far pointers for code segments
- %ifidni MMODE,l
- %define MMODE_FAR_CALL
- %endif
- %ifidni MMODE,m
- %define MMODE_FAR_CALL
- %endif
-
- %ifdef MMODE_FAR_CALL
- %define retnative retf
- %define cdecl_param_offset 6 ; RETF addr + PUSH BP
- %else
- %define retnative ret
- %define cdecl_param_offset 4 ; RET addr + PUSH BP
- %endif
-%else
- %define retnative ret
- %define cdecl_param_offset 8 ; RET addr + PUSH EBP
-%endif
-
-; int try_pci_bios2();
-try_pci_bios2_:
- pushan
- mov ax,0xB101
- xor edi,edi ; BUGFIX: Some BIOSes don't set EDI so the "entry point" address we get is whatever Watcom left on the stack.
- ; This fix resolves the weird erratic values seen when running under Microsoft Virtual PC 2007.
- xor edx,edx
- xor ebx,ebx
- xor ecx,edx
- int 0x1A
- jnc @1 ; CF=0?
- jmp fail
-@1: cmp ah,0 ; AH=0?
- jz @2
- jmp fail
-@2: cmp edx,0x20494350 ; EDX = 'PCI '?
- jz @3
- jmp fail
-@3: mov dword [_pci_bios_protmode_entry_point],edi
- mov byte [_pci_bios_hw_characteristics],al
- mov byte [_pci_bios_interface_level],bl
- mov byte [_pci_bios_interface_level+1],bh
- xor ch,ch
- mov word [_pci_bios_last_bus],cx
-
- popan
- mov result,1
- retnative
-fail: popan
- xor result,result
- retnative
-
-; int try_pci_bios1();
-try_pci_bios1_:
- pushan
- mov ax,0xB001
- int 0x1A
- jc fail2 ; CF=0?
- cmp dx,0x4350 ; DX:CX should spell out 'PCI '
- jnz fail2
- cmp cx,0x2049
- jnz fail2
- popan
- mov result,1
- retnative
-fail2: popan
- xor result,result
- retnative
-
-%if TARGET_MSDOS == 16
-; uint32_t __cdecl pci_bios_read_dword_16(uint16_t bx,uint16_t di)
-_pci_bios_read_dword_16:
- push bp
- mov bp,sp
-
- push cx
- push bx
- push di
- mov bx,[bp+cdecl_param_offset]
- mov di,[bp+cdecl_param_offset+2]
- mov ax,0xB10A
- int 0x1A
- jc @2r ; CF=1 means failure
- cmp ah,0x00
- jz @1r ; AH!=0 means failure
-@2r: xor ecx,ecx
- dec ecx
-@1r: pop di
- pop bx
- mov ax,cx
- shr ecx,16
- mov dx,cx
- pop cx
-
- pop bp
- retnative
-
-; void __cdecl pci_bios_write_dword_16(uint16_t bx,uint16_t di,uint32_t data);
-_pci_bios_write_dword_16:
- push bp
- mov bp,sp
-
- push cx
- push bx
- push di
- mov bx,[bp+cdecl_param_offset]
- mov di,[bp+cdecl_param_offset+2]
- mov ecx,[bp+cdecl_param_offset+4]
- mov ax,0xB10D
- int 0x1A
- pop di
- pop bx
- pop cx
-
- pop bp
- retnative
-%endif
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/pci/pci.h>
-#include <hw/cpu/cpu.h>
-
-static void help() {
- printf("test [options]\n");
- printf("Test PCI access library\n");
- printf(" /? this help\n");
- printf(" /b Prefer BIOS access\n");
- printf(" /b1 Prefer BIOS 1.x access\n");
- printf(" /t1 Prefer Type 1 (0xCF8-0xCFF) access\n");
- printf(" /t2 Prefer Type 2 (0xCxxx) access\n");
-}
-
-int main(int argc,char **argv) {
- int pref = -1,i;
-
- for (i=1;i < argc;) {
- char *a = argv[i++];
-
- if (*a == '-' || *a == '/') {
- do { a++; } while (*a == '-' || *a == '/');
-
- if (!strcmp(a,"h") || !strcmp(a,"help") || !strcmp(a,"?")) {
- help();
- return 1;
- }
- else if (!strcmp(a,"b")) {
- pref = PCI_CFG_BIOS;
- }
- else if (!strcmp(a,"b1")) {
- pref = PCI_CFG_BIOS1;
- }
- else if (!strcmp(a,"t1")) {
- pref = PCI_CFG_TYPE1;
- }
- else if (!strcmp(a,"t2")) {
- pref = PCI_CFG_TYPE2;
- }
- else {
- printf("Unknown switch '%s'\n",a);
- help();
- return 1;
- }
- }
- else {
- printf("Unknown arg '%s'\n",a);
- return 1;
- }
- }
-
- printf("PCI bus test code\n");
-
- cpu_probe();
- assert(pref == -1 || (pref >= 0 && pref < PCI_CFG_MAX)); /* CHECK: Bugfix for register corruption because cpu_probe() didn't save registers */
- if (cpu_basic_level < CPU_386) {
- printf("PCI programming requires a 386 or higher\n");
- return 1;
- }
-
- if (pci_probe(pref) == PCI_CFG_NONE) {
- printf("PCI bus not found\n");
- return 1;
- }
- printf("Found PCI BUS, code %d\n",pci_cfg);
- if (pci_cfg == PCI_CFG_BIOS) {
- printf(" 32-bit entry point: 0x%08lx\n",(unsigned long)pci_bios_protmode_entry_point);
- printf(" Hardware charactistics: 0x%02x\n",(unsigned int)pci_bios_hw_characteristics);
- printf(" Interface level: %x.%x\n",pci_bios_interface_level>>8,pci_bios_interface_level&0xFF);
- }
- if (pci_cfg == PCI_CFG_BIOS1) {
- printf(" PCI BIOS 1.xx interface\n");
- }
- if (pci_bios_last_bus == -1) {
- printf(" Autodetecting PCI bus count...\n");
- pci_probe_for_last_bus();
- }
- printf(" Last bus: %d\n",pci_bios_last_bus);
- printf(" Bus decode bits: %d\n",pci_bus_decode_bits);
-
- { /* prove readability by dumping 0,0,0 config space */
- unsigned int reg;
- uint32_t val;
-
- printf("PCI BUS/DEV/FUNC 0/0/0 config space: [DWORD]\n");
- for (reg=0;reg < (8*4);reg += 4) {
- val = pci_read_cfgl(0,0,0,reg);
- printf("%08lX ",(unsigned long)val);
- }
- printf("\n");
-
- for (reg=0;reg < (15*2);reg += 2) {
- val = pci_read_cfgw(0,0,0,reg);
- printf("%04X ",(unsigned int)val);
- }
- printf("\n");
-
- for (reg=0;reg < 25;reg++) {
- val = pci_read_cfgb(0,0,0,reg);
- printf("%02X ",(unsigned int)val & 0xFF);
- }
- printf("\n");
- while (getch() != 13);
- }
-
- /* then enumerate the bus */
- {
- int line=0;
- uint8_t bus,dev,func;
- uint32_t t32a,t32b,t32c;
- for (bus=0;bus <= pci_bios_last_bus;bus++) {
- for (dev=0;dev < 32;dev++) {
- uint8_t functions = pci_probe_device_functions(bus,dev);
- for (func=0;func < functions;func++) {
- /* make sure something is there before announcing it */
- uint16_t vendor,device,subsystem,subvendor_id;
- uint32_t class_code;
- uint8_t revision_id;
- vendor = pci_read_cfgw(bus,dev,func,0x00); if (vendor == 0xFFFF) continue;
- device = pci_read_cfgw(bus,dev,func,0x02); if (device == 0xFFFF) continue;
- subvendor_id = pci_read_cfgw(bus,dev,func,0x2C);
- subsystem = pci_read_cfgw(bus,dev,func,0x2E);
-
- class_code = pci_read_cfgl(bus,dev,func,0x08);
- revision_id = class_code & 0xFF;
- class_code >>= 8UL;
-
- /* show it Linux sysfs style */
- printf(" %04x:%02x:%02x.%x: Vendor %04x Device %04x Sub %04x Vnd %04x Class %06lx rev %02x\n",
- 0,bus,dev,func,
- vendor,device,subsystem,subvendor_id,
- class_code,revision_id);
-
- /* any interrupt? */
- {
- uint8_t l = pci_read_cfgb(bus,dev,func,0x3C);
- uint8_t p = pci_read_cfgb(bus,dev,func,0x3D);
- if (p != 0)
- printf(" IRQ: %u (pin %c (%02Xh))\n",l,p-1+'A',p);
- }
-
- /* show resources too. note that to figure out how large the BARs are we have to
- * write to them and see which bits toggle. finally, remember that changing BARs
- * affects any resources that TSRs or other functions might be trying to use at
- * the same time, so we must disable interrupts while doing this */
- {
- uint8_t bar;
-
- for (bar=0;bar < 6;bar++) {
- uint8_t io=0;
- uint32_t lower=0,higher=0;
- uint8_t reg = 0x10+(bar*4);
-
- _cli();
- t32a = pci_read_cfgl(bus,dev,func,reg);
- if (t32a == 0xFFFFFFFFUL) continue;
- io = t32a & 1;
- if (io) lower = t32a & 0xFFFFFFFCUL;
- else lower = t32a & 0xFFFFFFF0UL;
- pci_write_cfgl(bus,dev,func,reg,0);
- t32b = pci_read_cfgl(bus,dev,func,reg);
- pci_write_cfgl(bus,dev,func,reg,~0UL);
- t32c = pci_read_cfgl(bus,dev,func,reg);
- pci_write_cfgl(bus,dev,func,reg,t32a); /* restore prior contents */
- if (t32a == t32b && t32b == t32c) {
- /* hm, can't change it? */
- }
- else {
- uint32_t size = ~(t32c & ~(io ? 3UL : 15UL));
- if (io) size &= 0xFFFFUL;
- if ((size+1UL) == 0UL) continue;
- higher = lower + size;
- }
-
- if (higher == lower) continue;
-
- _sti();
- line++;
- if (io) printf(" IO: 0x%04lx-0x%04lx\n",lower,higher);
- else printf(" MEM: 0x%08lx-0x%08lx %s\n",lower,higher,
- t32a & 8 ? "Prefetch" : "Non-prefetch");
- }
- _sti();
- }
-
- if (++line >= 20) {
- while (getch() != 13);
- line -= 20;
- }
- }
- }
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_PCIE_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-AFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NASMFLAGS_THIS =
-
-# NTS: CPU functions here are to be moved at some point to the cpu library!
-C_SOURCE = pcie.c
-OBJS = $(SUBDIR)$(HPS)pcie.obj
-HW_PCIE_LIB = $(SUBDIR)$(HPS)pcie.lib
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_PCIE_LIB): $(OBJS)
- wlib -q -b -c $(HW_PCIE_LIB) -+$(SUBDIR)$(HPS)pcie.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-lib: $(HW_PCIE_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_PCIE_LIB) $(HW_PCIE_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_PCIE_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_PCIE_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-/* NTS: It's not required in the DOS environment, but in the unlikely event that
- * interrupt handlers are mucking around with PCI configuration space you
- * may want to bracket your PCI operations with CLI/STI. Again for performance
- * reasons, this code will NOT do it for you */
-/* NTS: Additional research suggests that on legacy systems with 10-bit decoding
- * I/O ports 0xCF8-0xCFF are unlikely to collide with 287/387 legacy I/O
- * ports 0xF0-0xF7 (as I initially thought), therefore probing 0xCF8 on
- * ancient systems should do no harm and not cause any problems. */
-
-/* This library enables programming the PCI bus that may be available to DOS level
- * programs on Pentium and higher systems (where PCI slots were first common on
- * home desktop PCs)
- *
- * This code is designed to compile 16-bit and 32-bit versions. The 16-bit real
- * mode versions are designed with DOS programs in mind that might want the ability
- * to fiddle with the PCI bus and program registers while maintaining downlevel
- * compatability with older hardware, perhaps all the way down to the 8086. */
-
-/* TODO: Need 64-bit I/O functions (using Pentium MMX MOVQ) for 16-bit flat real mode */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/flatreal/flatreal.h>
-#include <hw/llmem/llmem.h>
-#include <hw/acpi/acpi.h> /* on x86 systems you need the ACPI BIOS to locate PCI Express MMIO space */
-#include <hw/pcie/pcie.h>
-#include <hw/cpu/cpu.h>
-#include <hw/dos/doswin.h>
-
-unsigned char pcie_cfg_probed = 0;
-unsigned char pcie_cfg = PCIE_CFG_NONE;
-uint8_t pcie_bus_decode_bits = 0; /* which bus bits the hardware actually bothers to compare against */
-uint8_t pcie_bios_last_bus = 0;
-uint64_t pcie_acpi_mcfg_table = 0;
-uint64_t pcie_bus_mmio_base[256]={0ULL};
-
-uint32_t pcie_read_cfg_NOTIMPL(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint8_t size) {
- return ~0UL;
-}
-
-uint32_t pcie_read_cfg_FLATREAL(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint8_t size) {
-#if TARGET_MSDOS == 16
- /* we're in 16-bit real mode and we're using the Flat Real Mode library */
- if (pcie_bus_mmio_base[bus] != 0ULL) {
- uint32_t addr = pci_express_bdfero_to_offset(0,card,func,reg>>2,reg&3) + (uint32_t)pcie_bus_mmio_base[bus];
-
- if (!flatrealmode_allowed())
- return ~0UL;
- if (!flatrealmode_ok()) {
- if (!flatrealmode_setup(FLATREALMODE_4GB))
- return ~0UL;
- }
-
- switch (size) {
- case 0: return flatrealmode_readb(addr);
- case 1: return flatrealmode_readw(addr);
- case 2: return flatrealmode_readd(addr);
- };
- }
-#endif
- return ~0UL;
-}
-
-uint32_t pcie_read_cfg_PTR(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint8_t size) {
-#if TARGET_MSDOS == 32
- /* we're in flat 32-bit protected mode and the DOS extender left off paging */
- if (pcie_bus_mmio_base[bus] != 0ULL) {
- uint32_t addr = pci_express_bdfero_to_offset(0,card,func,reg>>2,reg&3) + (uint32_t)pcie_bus_mmio_base[bus];
- switch (size) {
- case 0: return *((uint8_t*)addr);
- case 1: return *((uint16_t*)addr);
- case 2: return *((uint32_t*)addr);
- };
- }
-#endif
- return ~0UL;
-}
-
-uint64_t pcie_read_cfg_NOTIMPLq(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg) {
- return ~0ULL;
-}
-
-uint64_t pcie_read_cfg_PTRq(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg) {
-#if TARGET_MSDOS == 32
- /* we're in flat 32-bit protected mode and the DOS extender left off paging */
- if (pcie_bus_mmio_base[bus] != 0ULL) {
- /* use MOVQ to guarantee 64-bit memory I/O. Hope your CPU is a Pentium MMX or higher! */
- uint32_t addr = pci_express_bdfero_to_offset(0,card,func,reg>>2,reg&3) + (uint32_t)pcie_bus_mmio_base[bus];
- uint64_t retv = 0;
- __asm {
- .686p
- .mmx
- push esi
- mov esi,addr
- movq mm0,[esi]
- movq retv,mm0
- emms
- pop esi
- }
-
- return retv;
- }
-#endif
- return ~0ULL;
-}
-
-void pcie_write_cfg_NOTIMPL(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint32_t data,uint8_t size) {
-}
-
-void pcie_write_cfg_FLATREAL(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint32_t data,uint8_t size) {
-#if TARGET_MSDOS == 16
- /* we're in 16-bit real mode and we're using the Flat Real Mode library */
- if (pcie_bus_mmio_base[bus] != 0ULL) {
- uint32_t addr = pci_express_bdfero_to_offset(0,card,func,reg>>2,reg&3) + (uint32_t)pcie_bus_mmio_base[bus];
-
- if (!flatrealmode_allowed())
- return;
- if (!flatrealmode_ok()) {
- if (!flatrealmode_setup(FLATREALMODE_4GB))
- return;
- }
-
- switch (size) {
- case 0: flatrealmode_writeb(addr,(uint8_t)data); return;
- case 1: flatrealmode_writew(addr,(uint16_t)data); return;
- case 2: flatrealmode_writed(addr,(uint32_t)data); return;
- };
- }
-#endif
-}
-
-void pcie_write_cfg_PTR(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint32_t data,uint8_t size) {
-#if TARGET_MSDOS == 32
- /* we're in flat 32-bit protected mode and the DOS extender left off paging */
- if (pcie_bus_mmio_base[bus] != 0ULL) {
- uint32_t addr = pci_express_bdfero_to_offset(0,card,func,reg>>2,reg&3) + (uint32_t)pcie_bus_mmio_base[bus];
- switch (size) {
- case 0: *((uint8_t*)addr) = (uint8_t)data; return;
- case 1: *((uint16_t*)addr) = (uint16_t)data; return;
- case 2: *((uint32_t*)addr) = (uint32_t)data; return;
- };
- }
-#endif
-}
-
-void pcie_write_cfg_NOTIMPLq(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint64_t data) {
-}
-
-void pcie_write_cfg_PTRq(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint64_t data) {
-#if TARGET_MSDOS == 32
- /* we're in flat 32-bit protected mode and the DOS extender left off paging */
- if (pcie_bus_mmio_base[bus] != 0ULL) {
- /* use MOVQ to guarantee 64-bit memory I/O. Hope your CPU is a Pentium MMX or higher! */
- uint32_t addr = pci_express_bdfero_to_offset(0,card,func,reg>>2,reg&3) + (uint32_t)pcie_bus_mmio_base[bus];
- __asm {
- .686p
- .mmx
- push esi
- mov esi,addr
- movq mm0,data
- movq [esi],mm0
- emms
- pop esi
- }
- }
-#endif
-}
-
-void pcie_probe_for_last_bus() {
- /* FIXME: This probe function was needed in the PCI library because I found several
- 1995-1996 era Pentium systems with cheap PCI controllers that don't decode all
- the bus bits. In today's world the motherboard manufacturers are better about
- that kind of thing and I don't expect to see device aliasing when enumerating
- all 256 busses reported by the ACPI BIOS... but if I do catch such a system I
- will add code here to deal with it */
-}
-
-/* PCI Express uses a memory-mapped region rather than I/O, so our access methods are more
- concerned with how 16-bit apps can reach into extended memory or how 32-bit apps can
- reach above 4GB */
-int pcie_probe(int preference) {
- unsigned char above4gb=0;
- uint32_t tmp32,tmplen;
- unsigned int i,max;
- uint64_t addr;
- char tmp[32];
-
- if (pcie_cfg_probed)
- return pcie_cfg;
-
- /* Require a Pentium MMX or higher, because the 64-bit I/O function uses the MOVQ instruction */
- /* Remove this restriction if there are 486-class embedded boxes with PCI Express */
- if (cpu_basic_level < 5)
- return PCIE_CFG_NONE;
-
- /* it must have CPUID because... */
- if (!(cpu_flags & CPU_FLAG_CPUID))
- return PCIE_CFG_NONE;
-
- /* we require MMX for our 64-bit I/O function */
- if (!(cpu_cpuid_features.a.raw[2] & (1UL << 23UL)))
- return PCIE_CFG_NONE;
-
- /* locating PCI Express on x86 systems requires the use of ACPI BIOS tables */
- if (!acpi_probe() || acpi_rsdp == NULL || acpi_rsdt == NULL)
- return PCIE_CFG_NONE;
-
- /* OK, locate the MCFG table */
- pcie_cfg_probed = 1;
- pcie_bios_last_bus = 0;
- pcie_cfg = PCIE_CFG_NONE;
- pcie_acpi_mcfg_table = 0;
- pcie_bus_decode_bits = 8; /* modern systems don't have the cheap comparison logic that mid 1990's hardware used to have */
- max = acpi_rsdt_entries();
- for (i=0;pcie_acpi_mcfg_table == 0ULL && i < max;i++) {
- addr = acpi_rsdt_entry(i);
- if (addr == 0ULL) continue;
-
- tmp32 = acpi_mem_readd(addr); tmplen = 0;
- memcpy(tmp,&tmp32,4); tmp[4] = 0;
- if (acpi_probe_rsdt_check(addr,tmp32,&tmplen)) {
- struct acpi_rsdt_header sdth;
-
- memset(&sdth,0,sizeof(sdth));
- acpi_memcpy_from_phys(&sdth,addr,sizeof(struct acpi_rsdt_header));
- if (!memcmp(sdth.signature,"MCFG",4)) {
- struct acpi_mcfg_entry entry;
- uint64_t o = addr + 44ULL;
- unsigned int count;
- unsigned int bus;
-
- pcie_acpi_mcfg_table = addr;
- assert(sizeof(struct acpi_mcfg_entry) == 16);
- count = (unsigned int)(tmplen / sizeof(struct acpi_mcfg_entry));
- while (count != 0) {
- memset(&entry,0,sizeof(entry));
- acpi_memcpy_from_phys(&entry,o,sizeof(struct acpi_mcfg_entry));
- o += sizeof(struct acpi_mcfg_entry);
-
- /* Some bioses I test against seem to return enough for 3 but fill in only 1? */
- if (entry.base_address != 0ULL || entry.start_pci_bus_number != 0 || entry.end_pci_bus_number != 0) {
- if (entry.start_pci_bus_number > entry.end_pci_bus_number)
- entry.start_pci_bus_number = entry.end_pci_bus_number;
- if (pcie_bios_last_bus < entry.end_pci_bus_number)
- pcie_bios_last_bus = entry.end_pci_bus_number;
-
- for (bus=entry.start_pci_bus_number;bus <= entry.end_pci_bus_number;bus++) {
- pcie_bus_mmio_base[bus] = entry.base_address +
- (((uint64_t)(bus - entry.start_pci_bus_number)) << 20ULL);
-
- if (pcie_bus_mmio_base[bus] >= 0xFFF00000ULL)
- above4gb = 1;
- }
- }
-
- count--;
- }
- }
- }
- }
-
- if (pcie_acpi_mcfg_table == 0ULL)
- return PCIE_CFG_NONE;
-
- /* pick a memory access method. use Flat Real Mode because llmem imposes a CPU mode-switch overhead per I/O.
- however if the BIOS put the MMIO ranges above 4GB we have no choice but to use LLMEM.
- for 32-bit builds, the ideal method is to take advantage of the DOS extender's preference NOT to use
- paging and to typecast pointers in the flat 4GB address space */
- if (!above4gb && flatrealmode_allowed())
- pcie_cfg = PCIE_CFG_FLATREAL;
-#if TARGET_MSDOS == 32
- else if (!above4gb && !dos_ltp_info.paging)
- pcie_cfg = PCIE_CFG_PTR;
-#endif
- else if (llmem_available)
- pcie_cfg = PCIE_CFG_LLMEM;
- else
- return PCIE_CFG_NONE;
-
- return pcie_cfg;
-}
-
-uint32_t (*pcie_read_cfg_array[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint8_t size) = {
- pcie_read_cfg_NOTIMPL, /* NONE */
- pcie_read_cfg_FLATREAL, /* PCIE_CFG_FLATREAL */
- pcie_read_cfg_NOTIMPL, /* PCIE_CFG_LLMEM */
- pcie_read_cfg_PTR, /* PCIE_CFG_PTR */
-};
-
-uint64_t (*pcie_read_cfg_arrayq[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg) = {
- pcie_read_cfg_NOTIMPLq, /* NONE */
- pcie_read_cfg_NOTIMPLq, /* PCIE_CFG_FLATREAL */
- pcie_read_cfg_NOTIMPLq, /* PCIE_CFG_LLMEM */
- pcie_read_cfg_PTRq, /* PCIE_CFG_PTR */
-};
-
-void (*pcie_write_cfg_array[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint32_t data,uint8_t size) = {
- pcie_write_cfg_NOTIMPL, /* NONE */
- pcie_write_cfg_FLATREAL, /* PCIE_CFG_FLATREAL */
- pcie_write_cfg_NOTIMPL, /* PCIE_CFG_LLMEM */
- pcie_write_cfg_PTR, /* PCIE_CFG_PTR */
-};
-
-void (*pcie_write_cfg_arrayq[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint64_t data) = {
- pcie_write_cfg_NOTIMPLq, /* NONE */
- pcie_write_cfg_NOTIMPLq, /* PCIE_CFG_FLATREAL */
- pcie_write_cfg_NOTIMPLq, /* PCIE_CFG_LLMEM */
- pcie_write_cfg_PTRq, /* PCIE_CFG_PTR */
-};
-
-uint8_t pcie_probe_device_functions(uint8_t bus,uint8_t dev) {
- uint8_t funcs=8,f;
- uint32_t id[8],bar[8],sub[8];
-
- /* FIXME: Is this necessary, or are there PCIe devices that are still cheap about decoding the bus/device fields? */
-
- for (f=0;f < 8;f++) { /* PCI-Express still has 8 functions per device */
- id[f] = pcie_read_cfgl(bus,dev,f,0x00);
- bar[f] = pcie_read_cfgl(bus,dev,f,0x10);
- sub[f] = pcie_read_cfgl(bus,dev,f,0x2C);
- if (f == 0 && id[f] == 0xFFFFFFFFUL) return 0;
- }
-
- while (funcs > 1) {
- f = funcs >> 1;
- if (id[0] == id[f] && bar[0] == bar[f] && sub[0] == sub[f])
- funcs = f;
- else
- break;
- }
-
- return funcs;
-}
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* PCI Express configuration space is memory-mapped I/O, so the options
- cover the various ways 16-bit and 32-bit code can reach it */
-enum {
- PCIE_CFG_NONE=0,
- PCIE_CFG_FLATREAL, /* 16-bit: 386 flat real mode */
- PCIE_CFG_LLMEM, /* 16/32: llmem library */
- PCIE_CFG_PTR, /* 32-bit: DOS extender put us in flat (nonpaged) 32-bit protected mode, just typecast a ptr */
- PCIE_CFG_MAX
-};
-
-/* Take PCI express bus/device/function/reg/offset pair and convert to offset within MMIO region */
-static inline uint32_t pci_express_bdfero_to_offset(unsigned char bus,unsigned char device,unsigned char function,unsigned short reg,unsigned char offset) {
- return ((uint32_t)bus << 20UL) + ((uint32_t)device << 15UL) + ((uint32_t)function << 12UL) + ((uint32_t)reg << 2UL) + ((uint32_t)offset);
-}
-
-#define pcie_read_cfgq(b,c,f,r) pcie_read_cfg_arrayq[pcie_cfg](b,c,f,r)
-#define pcie_read_cfgl(b,c,f,r) pcie_read_cfg_array[pcie_cfg](b,c,f,r,2)
-#define pcie_read_cfgw(b,c,f,r) pcie_read_cfg_array[pcie_cfg](b,c,f,r,1)
-#define pcie_read_cfgb(b,c,f,r) pcie_read_cfg_array[pcie_cfg](b,c,f,r,0)
-
-#define pcie_write_cfgq(b,c,f,r,d) pcie_write_cfg_arrayq[pcie_cfg](b,c,f,r,d)
-#define pcie_write_cfgl(b,c,f,r,d) pcie_write_cfg_array[pcie_cfg](b,c,f,r,d,2)
-#define pcie_write_cfgw(b,c,f,r,d) pcie_write_cfg_array[pcie_cfg](b,c,f,r,d,1)
-#define pcie_write_cfgb(b,c,f,r,d) pcie_write_cfg_array[pcie_cfg](b,c,f,r,d,0)
-
-extern unsigned char pcie_cfg;
-extern unsigned char pcie_cfg_probed;
-extern uint8_t pcie_bus_decode_bits;
-extern uint8_t pcie_bios_last_bus;
-extern uint64_t pcie_acpi_mcfg_table;
-extern uint64_t pcie_bus_mmio_base[256];
-
-uint8_t pcie_probe_device_functions(uint8_t bus,uint8_t dev);
-void pcie_probe_for_last_bus();
-int pcie_probe(int preference);
-
-extern uint32_t (*pcie_read_cfg_array[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint8_t size);
-extern void (*pcie_write_cfg_array[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint32_t data,uint8_t size);
-
-extern uint64_t (*pcie_read_cfg_arrayq[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg);
-extern void (*pcie_write_cfg_arrayq[PCIE_CFG_MAX])(uint8_t bus,uint8_t card,uint8_t func,uint16_t reg,uint64_t data);
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/flatreal/flatreal.h>
-#include <hw/llmem/llmem.h>
-#include <hw/pcie/pcie.h>
-#include <hw/cpu/cpu.h>
-
-static void help() {
- printf("test [options]\n");
- printf("Test PCI-Express access library\n");
- printf(" /? this help\n");
-}
-
-int main(int argc,char **argv) {
- int pref = -1,i;
-
- for (i=1;i < argc;) {
- char *a = argv[i++];
-
- if (*a == '-' || *a == '/') {
- do { a++; } while (*a == '-' || *a == '/');
-
- if (!strcmp(a,"h") || !strcmp(a,"help") || !strcmp(a,"?")) {
- help();
- return 1;
- }
- else {
- printf("Unknown switch '%s'\n",a);
- help();
- return 1;
- }
- }
- else {
- printf("Unknown arg '%s'\n",a);
- return 1;
- }
- }
-
- printf("PCI-Express bus test code\n");
-
- cpu_probe();
- if (cpu_basic_level < 5) {
- printf("PCI-Express programming requires a Pentium or higher\n");
- return 1;
- }
-
-#if TARGET_MSDOS == 32
- probe_dpmi();
- dos_ltp_probe();
-#endif
-
- if (!llmem_init()) {
- printf("Your system is not suitable to use with the Long-Long memory access library\n");
- printf("Reason: %s\n",llmem_reason);
- }
-
-#if TARGET_MSDOS == 16
- if (!flatrealmode_setup(FLATREALMODE_4GB)) {
- printf("Unable to set up flat real mode (needed for 16-bit builds)\n");
- printf("Most ACPI functions require access to the full 4GB range.\n");
- return 1;
- }
-#endif
-
- if (pcie_probe(pref) == PCIE_CFG_NONE) {
- printf("PCI-Express bus not found\n");
- return 1;
- }
- printf("Found PCI-Express BUS, code %d\n",pcie_cfg);
- printf(" Last bus: %d\n",pcie_bios_last_bus);
- printf(" Bus decode bits: %d\n",pcie_bus_decode_bits);
-
- { /* prove readability by dumping 0,0,0 config space */
- unsigned int reg;
- uint32_t val;
- uint64_t q;
-
- printf("PCI BUS/DEV/FUNC 0/0/0 config space: [DWORD]\n");
- for (reg=0;reg < (4*8);reg += 8) {
- q = pcie_read_cfgq(0,0,0,reg);
- printf("%016llX ",(unsigned long long)q);
- }
- printf("\n");
-
- for (reg=0;reg < (8*4);reg += 4) {
- val = pcie_read_cfgl(0,0,0,reg);
- printf("%08lX ",(unsigned long)val);
- }
- printf("\n");
-
- for (reg=0;reg < (15*2);reg += 2) {
- val = pcie_read_cfgw(0,0,0,reg);
- printf("%04X ",(unsigned int)val);
- }
- printf("\n");
-
- for (reg=0;reg < 25;reg++) {
- val = pcie_read_cfgb(0,0,0,reg);
- printf("%02X ",(unsigned int)val);
- }
- printf("\n");
- while (getch() != 13);
- }
-
- /* then enumerate the bus */
- {
- int line=0;
- uint16_t bus;
- uint8_t dev,func;
- uint32_t t32a,t32b,t32c;
- for (bus=0;bus <= pcie_bios_last_bus;bus++) {
- if (pcie_bus_mmio_base[bus] != 0ULL) {
- fprintf(stderr,"BUS %u at %08llX\n",bus,(unsigned long long)pcie_bus_mmio_base[bus]);
- line++;
- }
-
- for (dev=0;dev < 32;dev++) {
- uint8_t functions = pcie_probe_device_functions(bus,dev);
- for (func=0;func < functions;func++) {
- /* make sure something is there before announcing it */
- uint16_t vendor,device,subsystem,subvendor_id;
- uint32_t class_code;
- uint8_t revision_id;
- vendor = pcie_read_cfgw(bus,dev,func,0x00); if (vendor == 0xFFFF) continue;
- device = pcie_read_cfgw(bus,dev,func,0x02); if (device == 0xFFFF) continue;
- subvendor_id = pcie_read_cfgw(bus,dev,func,0x2C);
- subsystem = pcie_read_cfgw(bus,dev,func,0x2E);
-
- class_code = pcie_read_cfgl(bus,dev,func,0x08);
- revision_id = class_code & 0xFF;
- class_code >>= 8UL;
-
- /* show it Linux sysfs style */
- line++;
- printf(" %04x:%02x:%02x.%x: Vendor %04x Device %04x Sub %04x Vnd %04x Class %06lx rev %02x\n",
- 0,bus,dev,func,
- vendor,device,subsystem,subvendor_id,
- class_code,revision_id);
-
- /* any interrupt? */
- {
- uint8_t l = pcie_read_cfgb(bus,dev,func,0x3C);
- uint8_t p = pcie_read_cfgb(bus,dev,func,0x3D);
- if (p != 0)
- printf(" IRQ: %u (pin %c (%02Xh))\n",l,p-1+'A',p);
- }
-
- /* show resources too. note that to figure out how large the BARs are we have to
- * write to them and see which bits toggle. finally, remember that changing BARs
- * affects any resources that TSRs or other functions might be trying to use at
- * the same time, so we must disable interrupts while doing this */
- {
- uint8_t bar;
-
- for (bar=0;bar < 6;bar++) {
- uint8_t io=0;
- uint32_t lower=0,higher=0;
- uint8_t reg = 0x10+(bar*4);
-
- _cli();
- t32a = pcie_read_cfgl(bus,dev,func,reg);
- if (t32a == 0xFFFFFFFFUL) continue;
- io = t32a & 1;
- if (io) lower = t32a & 0xFFFFFFFCUL;
- else lower = t32a & 0xFFFFFFF0UL;
- pcie_write_cfgl(bus,dev,func,reg,0);
- t32b = pcie_read_cfgl(bus,dev,func,reg);
- pcie_write_cfgl(bus,dev,func,reg,~0UL);
- t32c = pcie_read_cfgl(bus,dev,func,reg);
- pcie_write_cfgl(bus,dev,func,reg,t32a); /* restore prior contents */
- if (t32a == t32b && t32b == t32c) {
- /* hm, can't change it? */
- }
- else {
- uint32_t size = ~(t32c & ~(io ? 3UL : 15UL));
- if (io) size &= 0xFFFFUL;
- if ((size+1UL) == 0UL) continue;
- higher = lower + size;
- }
-
- if (higher == lower) continue;
-
- _sti();
- line++;
- if (io) printf(" IO: 0x%04lx-0x%04lx\n",lower,higher);
- else printf(" MEM: 0x%08lx-0x%08lx %s\n",lower,higher,
- t32a & 8 ? "Prefetch" : "Non-prefetch");
- }
- _sti();
- }
-
- if (line >= 20) {
- while (getch() != 13);
- line -= 20;
- }
- }
- }
-
- if (line >= 20) {
- while (getch() != 13);
- line -= 20;
- }
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-This library is a collection of useful subroutines for accessing MS-DOS IBM
-compatible hardware directly from your program.
-
-It is written to make best use of mid-1990's hardware and older, targeting
-Pentium, 486, 386, 286, and 8086 hardware with less than 32MB of RAM (anything
-too underpowered to run Linux very well to accomplish the same goals). It can
-be used on newer hardware all the way up to modern multicore processors, but
-how well it works depends either the presence of the chipset or the emulation
-of the chipset via System Management Mode on newer BIOSes. Where possible,
-code is provided here for the newer hardware interfaces. But there are some
-situations where supporting the new hardware requires you to make substantial
-changes to your code and to the hardware state that can cause problems with DOS
-(such as the APIC on post-2000 hardware).
-
-If nothing else, this code serves as a useful tutorial on how to program the
-commodity PC hardware out there. If you always wanted to program the hardware
-directly, this code would be an excellent study guide.
-
-This code is designed to run in pure DOS mode. It is written to be tolerant
-towards running in a Windows "DOS Box", though that is strongly discouraged.
-
-8042 ............. 8042 keyboard controller (and PS/2 mouse)
-8250 ............. 8250/16450/16550/16750 serial port UART
-8254 ............. 8254 timer chip
-8259 ............. 8259 programmable interrupt controller
-acpi ............. ACPI BIOS support functions and experiments
-apm .............. APM BIOS support functions
-biosdisk ......... BIOS INT 13H low-level disk access
-cpu .............. CPU utility and CPU/FPU detection
-dos .............. MS-DOS environment library, allowing:
- - DOS detection (version? state?)
- - Windows detection (am I in a DOS Box? version?)
- - DOSBox 0.74-ish emulator detection
- - BIOS extended memory copy (INT 15H)
- - Lotus/Intel/Microsoft Expanded Memory API,
- usually EMM386.EXE
- - HIMEM.SYS Extended Memory API
-flatreal ......... 386 "Flat Real Mode" API, to allow direct extended memory
- access to 16-bit real-mode applications
-ide .............. IDE/ATA hard disk and ATAPI CD-ROM code
-isapnp ........... ISA Plug & Play BIOS API and hardware I/O
-mb ............... Motherboard-specific hacking "toys", see README for
- comprehensive list
-parport .......... PC parallel (printer) port functions
-pci .............. PCI bus functions
-pcie ............. PCI-Express bus functions
-smbios ........... DMI/SMBIOS parsing functions
-sndsb ............ Sound Blaster or compatible support functions
-ultrasnd ......... Gravis Ultrasound support functions
-usb .............. Universal Serial Bus functions
-vesa ............. VESA VGA BIOS video API
-vga .............. VGA/EGA/CGA/MDA/Tandy/PCjr/Hercules support functions
-
-Build subdirectory naming convention:
-
- -- MS-DOS --
-
- dos86c ........... 16-bit real mode build, compact memory model (8086+)
- dos86s ........... 16-bit real mode build, small memory model (8086+)
- dos86m ........... 16-bit real mode build, medium memory model (8086+)
- dos86l ........... 16-bit real mode build, large memory model (8086+)
- dos286c .......... 16-bit real mode build, compact memory model (assume/optimized for 286+)
- dos286s .......... 16-bit real mode build, small memory model (assume/optimized for 286+)
- dos286m .......... 16-bit real mode build, medium memory model (assume/optimized for 286+)
- dos286l .......... 16-bit real mode build, large memory model (assume/optimized for 286+)
- dos386f .......... 32-bit protected mode build, flat memory model (386 or higher)
- dos486f .......... 32-bit protected mode build, flat memory model (assume/optimized for 486+)
- dos586f .......... 32-bit protected mode build, flat memory model (assume/optimized for 586+)
- dos686f .......... 32-bit protected mode build, flat memory model (assume/optimized for 686+)
-
- -- OS/2 --
-
- os2w2l ........... 16-bit protected mode build, large memory model (286 or higher)
- os2w3l ........... 16-bit protected mode build, large memory model (assume/optimized for 386+)
- os2d3f ........... 32-bit protected mode build, flat memory model (386 or higher)
-
- -- Windows 3.0 --
-
- win300l .......... 16-bit build, large memory model (8086+ real or protected mode)
- win300c .......... 16-bit build, compact memory model (8086+ real or protected mode)
- win302l .......... 16-bit build, large memory model (assume/optimized for 286+)
- win302c .......... 16-bit build, compact memory model (assume/optimized for 286+)
- win303l .......... 16-bit build, large memory model (assume/optimized for 386+)
- win303c .......... 16-bit build, compact memory model (assume/optimized for 386+)
-
- -- Windows 3.0 with Win386 --
-
- win386 ........... 32-bit build, flat memory model (386+)
-
- -- Windows 3.1 with Win386 --
-
- win38631 ......... 32-bit build, flat memory model (386+ Windows 3.1 or higher)
-
- -- Windows 3.1 --
-
- win312l .......... 16-bit build, large memory model (286+ protected mode only)
- win312c .......... 16-bit build, compact memory model (286+ protected mode only)
- win313l .......... 16-bit build, large memory model (assume/optimized for 386+)
- win313c .......... 16-bit build, compact memory model (assume/optimized for 386+)
-
- -- Windows 3.1 Win32s --
-
- win32s3 .......... 32-bit build, flat memory model (386+)
- win32s4 .......... 32-bit build, flat memory model (assume/optimized for 486+)
- win32s5 .......... 32-bit build, flat memory model (assume/optimized for 586+)
- win32s6 .......... 32-bit build, flat memory model (assume/optimized for 686+)
-
- -- Windows NT --
-
- winnt ............ 32-bit build, flat memory model (386+)
-
- -- Windows 95/98/ME --
-
- win32 ............ 32-bit build, flat memory model (386+)
-
- ------------------------------------------------------------------------------
-
- The 16-bit small memory model can only hold up to 64KB of code + data,
- anything that won't fit will not provide a working binary.
-
- Tests not applicable to each mode will not provide an EXE or will provide
- a stub that announces why the test was not compiled in. For example:
- 32-bit protected mode builds of the Flat Real Mode library, where flat
- real mode is unnecessary.
-
- Code is written to work as identically as possible across all three
- build modes, unless rendered impossible by DOS extender or environmental
- constraints. Multiple strategies may be chosen at runtime to make the
- operation work. For precise details, read the source code.
-
- NOTES:
-
- - OS/2 16-bit builds are [so far] tested with OS/2 2.x and higher. I'll test
- against OS/2 1.x when I get them working in an emulator someday... apparently
- OS/2 1.x has some very well known timing bugs that can trigger on anything
- faster than the 386 of the day.
-
- - OS/2 32-bit builds require OS/2 2.x and higher
-
- - Some OS/2 builds are compiled against the Presentation Manager. Most of them
- though are written to work from the OS/2 command prompt.
-
- - Windows builds are written to be forward-compatible: Windows 3.0 builds are
- written to remain compatible with Windows 3.1/95/98/ME and Windows
- NT/2000/XP/Vista/7 where possible.
-
- - "win32" and "winnt" builds are usually interchangeable between Windows 9x/ME
- and Windows NT/2000/XP/Vista/7. The different build designations may be used
- in the future to allow programs to specialize for one or the other.
-
- - I have tested this code under Windows 8 Release Preview. winnt and win32 builds
- work fine. DOS and win16 versions will trigger a one-time message about old
- application compatibility on 32-bit builds, but they will work regardless.
-
- - "Win386" refers to Watcom Win386 which allows 32-bit programs to run natively
- in the Win16 environment applying the same "extender" concept that it does for
- DOS programs.
-
-*** KNOWN SERIOUS ISSUES THAT CAN OCCUR WITH THIS PROGRAM ***
-
- 1) FreeDOS 1.0 and DOS32a DOS extender
-
- There is a known issue with DOS32a and FreeDOS 1.0 that can cause bizarre
- erratic behavior with this test code and in many cases can cause hard crashes.
- This is most visible with complex programs like the VGA test program and
- the PCI enumeration code when using the BIOS to enumerate the PCI bus.
-
- You should use the real-mode versions of the code if possible, or use instead
- a FreeDOS 1.1 installation.
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/rtc/rtc.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-#include <hw/dos/doswin.h>
-
-int main(int argc,char **argv) {
- unsigned char tmp[128];
- unsigned int i;
-
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!probe_8259()) {
- printf("Cannot init 8259 PIC\n");
- return 1;
- }
- if (!probe_rtc()) {
- printf("RTC/CMOS not found\n");
- return 1;
- }
- probe_dos();
- detect_windows();
-
- _cli();
- for (i=0;i < 128;i++) tmp[i] = rtc_io_read(i);
- _sti();
-
- for (i=0;i < 128;i++) {
- if ((i&0xF) == 0) printf("%02X: ",i);
- if ((i&0xF) == 0x7) printf("%02X-",tmp[i]);
- else printf("%02X ",tmp[i]);
- if ((i&0xF) == 0xF) printf("\n");
- }
-
- rtc_io_finished();
- return 0;
-}
-
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_RTC_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = rtc.c
-OBJS = $(SUBDIR)$(HPS)rtc.obj $(SUBDIR)$(HPS)rtc.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-CMOS_EXE = $(SUBDIR)$(HPS)cmos.exe
-
-$(HW_RTC_LIB): $(OBJS)
- wlib -q -b -c $(HW_RTC_LIB) -+$(SUBDIR)$(HPS)rtc.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_RTC_LIB) .symbolic
-
-exe: $(TEST_EXE) $(CMOS_EXE) .symbolic
-
-$(CMOS_EXE): $(HW_RTC_LIB) $(HW_RTC_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)cmos.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)cmos.obj $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_RTC_LIB_WLINK_LIBRARIES) name $(CMOS_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(TEST_EXE): $(HW_RTC_LIB) $(HW_RTC_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_RTC_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/rtc/rtc.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-
-int probe_rtc() {
- unsigned char idx,match=0;
-
- _cli();
- for (idx=0;idx < 10;idx += 2) {
- if (rtc_io_read(idx) != 0xFF) match++;
- }
- rtc_io_read(0xC);
- rtc_io_read_unmasked(0xD);
- _sti();
- return (match >= 4);
-}
-
-int rtc_wait_for_update_complete() {
- int r=0,v;
-
- do {
- v=rtc_io_read(0xA);
- if (v & 0x80) r = 1; /* caller also needs to know if update in progress was seen */
- } while (v & 0x80);
-
- return r; /* return whether or not the update cycle was seen */
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-
-static inline void rtc_io_finished() {
- outp(0x70,0x0D);
- inp(0x71);
-}
-
-static inline unsigned char rtc_io_read(unsigned char idx) {
- outp(0x70,idx | 0x80); /* also mask off NMI */
- return inp(0x71);
-}
-
-static inline void rtc_io_write(unsigned char idx,unsigned char c) {
- outp(0x70,idx | 0x80); /* also mask off NMI */
- outp(0x71,c);
-}
-
-static inline unsigned char rtc_io_read_unmasked(unsigned char idx) {
- outp(0x70,idx);
- return inp(0x71);
-}
-
-#define RTC_STATUS_C_INTERRUPT_REQUEST 0x80
-#define RTC_STATUS_C_PERIODIC_INTERRUPT 0x40
-#define RTC_STATUS_C_ALARM_INTERRUPT 0x20
-#define RTC_STATUS_C_UPDATE_ENDED_INTERRUPT 0x10
-
-int probe_rtc();
-int rtc_wait_for_update_complete();
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/rtc/rtc.h>
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC */
-#include <hw/dos/doswin.h>
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-
-static const char *months[12] = {
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
-};
-
-static const char *weekdays[7] = {
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday"
-};
-
-static volatile unsigned int alarm_ints = 0;
-static volatile unsigned int update_ints = 0;
-static volatile unsigned long periodic_ints = 0;
-static volatile unsigned long periodic_sec_ints = 0;
-static volatile unsigned long periodic_measured_ints = 0;
-static volatile unsigned long irq8_ints = 0;
-
-static unsigned char bcd_to_binary(unsigned char c) {
- return ((c >> 4) * 10) + (c & 0xF);
-}
-
-static const char *weekday_to_str(unsigned char c) {
- if (c == 0 || c > 7) return "??";
- return weekdays[c-1];
-}
-
-static const char *month_to_str(unsigned char c) {
- if (c == 0 || c > 12) return "??";
- return months[c-1];
-}
-
-void interrupt far *old_irq8 = NULL;
-void interrupt far rtc_int() {
- unsigned char fl,patience=64;
-
- _cli();
-
- /* ack PIC for IRQ 8 */
- p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
-
- /* Real hardware experience: If you set the periodic rate to max
- (8192Hz) it IS possible for both a periodic and update-ended
- interrupt to occur at the same time. If that happens, then
- apparently the RTC will still only fire one IRQ event. If we
- don't check for additional events, we can leave the RTC IRQ
- "stuck" waiting for service. (Observed on a Pentium 133MHz
- Intel 430-based motherboard). */
- /* Also observed on the same P133MHz system: If this ISR is slow
- enough or the CPU has enough overhead, and the Periodic interrupt
- is cranked up to 8192Hz, it is possible for this code to miss
- update-ended interrupts entirely. You'll see evidence of this
- when every so often the clock on-screen seems to stop, then skip
- a whole second. It doesn't seem to happen at lower periodic
- rates. Prior to moving the PIC ACK to the top, that scenario
- would eventually result in us missing an interrupt and the
- on-screen display "freezing" (when in fact the PIC was waiting
- for another ACK) */
- do {
- fl = rtc_io_read(0x0C); /* read status register C */
- if (fl & RTC_STATUS_C_INTERRUPT_REQUEST) { /* if there actually was an interrupt, then do something */
- irq8_ints++;
- if (fl & RTC_STATUS_C_PERIODIC_INTERRUPT) {
- /* Real hardware experience:
- Most motherboard RTCs will set this
- bit even if periodic interrupts are
- disabled. If all you have are update-ended
- interrupts, then this code will simply
- register periodic interrupts as happening
- one tick per second. It's almost as if
- the "enable" bits are just gates to whether
- or not they trigger IRQ 8. */
- periodic_sec_ints++;
- periodic_ints++;
- }
- if (fl & RTC_STATUS_C_ALARM_INTERRUPT) {
- alarm_ints++;
- }
- if (fl & RTC_STATUS_C_UPDATE_ENDED_INTERRUPT) {
- /* Real hardware experience:
- Most motherboard RTCs will actually
- signal update-ended per second if
- either the Update-Ended interrupt
- or the Periodic interrupt is enabled.
- You can have the Update-Ended interrupt
- disabled and still receive these events
- anyway from your ISR during periodic.
-
- Also noted: If the "freeze" bit (bit 7)
- is set in Status Register B, and left that
- way, the RTC will not send update-ended
- events, and will not run the clock. */
- periodic_measured_ints = periodic_sec_ints;
- periodic_sec_ints = 0;
- update_ints++;
- }
- }
- if (--patience == 0) break;
- } while (fl & RTC_STATUS_C_INTERRUPT_REQUEST);
-
- rtc_io_finished();
-}
-
-int main(int argc,char **argv) {
- char tmp[128];
- unsigned int y,i;
- unsigned long pirq8_ints = 0;
- unsigned int pupdate_ints = 0;
- unsigned char redraw_all=1,redraw=1,update_rdtime=1;
-
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!probe_8259()) {
- printf("Cannot init 8259 PIC\n");
- return 1;
- }
- if (!probe_rtc()) {
- printf("RTC/CMOS not found\n");
- return 1;
- }
- if (!probe_vga()) {
- printf("Cannot detect VGA\n");
- return 1;
- }
- probe_dos();
- detect_windows();
-
- /* set 80x25 mode 3 */
- __asm {
- mov ax,3
- int 10h
- }
- update_state_from_vga();
-
- /* enable the Update Ended interrupt for display niceness */
- /* NOTE: DOSBox 0.74 does not emulate the Alarm and Update Ended RTC interrupts */
- rtc_io_write(0xB,rtc_io_read(0xB) | 0x10);
- rtc_io_finished();
-
- /* take IRQ 8 */
- old_irq8 = _dos_getvect(0x70);
- _dos_setvect(0x70,rtc_int);
- p8259_unmask(8);
-
- while (1) {
- if (redraw_all) {
- VGA_ALPHA_PTR a = vga_alpha_ram;
-
- for (y=0;y < (80*25);y++)
- *a++ = 0x1E20;
-
- redraw_all = 0;
- redraw = 1;
- }
- _cli();
- if (irq8_ints != pirq8_ints || redraw) {
- unsigned char reg_b;
-
- vga_moveto(0,0);
- vga_write_color(0x1E);
-
- /* we need a copy of Status Register B to know what format
- * the values are given in */
- reg_b = rtc_io_read(0xB);
-
- sprintf(tmp,"IRQ 8: %lu total (%lu per, %u alarm, %u up, %lu per/sec) \n",
- (unsigned long)irq8_ints,
- (unsigned long)periodic_ints,
- (unsigned int)alarm_ints,
- (unsigned int)update_ints,
- (unsigned long)periodic_measured_ints);
- vga_write(tmp);
-
- pirq8_ints = irq8_ints;
- rtc_io_finished();
- }
- if (update_ints != pupdate_ints || update_rdtime || redraw) {
- unsigned char reg_b,month,dom,dow,hour,minutes,seconds;
- unsigned int year;
-
- /* we need a copy of Status Register B to know what format
- * the values are given in */
- reg_b = rtc_io_read(0xB);
-
- /* read the time. if an Update In Progress is seen, start over */
-retry: if (rtc_wait_for_update_complete()) goto retry;
-retry2: year = rtc_io_read(9);
- if (rtc_wait_for_update_complete()) goto retry2;
- month = rtc_io_read(8);
- if (rtc_wait_for_update_complete()) goto retry2;
- dom = rtc_io_read(7); /* day of month */
- if (rtc_wait_for_update_complete()) goto retry2;
- dow = rtc_io_read(6); /* day of week */
- if (rtc_wait_for_update_complete()) goto retry2;
- hour = rtc_io_read(4);
- if (rtc_wait_for_update_complete()) goto retry2;
- minutes = rtc_io_read(2);
- if (rtc_wait_for_update_complete()) goto retry2;
- seconds = rtc_io_read(0);
- if (rtc_wait_for_update_complete()) goto retry2;
- rtc_io_finished();
-
- vga_moveto(0,1);
- vga_write_color(0x1E);
- sprintf(tmp,"NOW[%s]: ",reg_b & 0x04 ? "BIN" : "BCD");
- vga_write(tmp);
-
- if (!(reg_b & 0x04)) {
- year = bcd_to_binary(year);
- month = bcd_to_binary(month);
- dom = bcd_to_binary(dom);
- dow = bcd_to_binary(dow);
- hour = bcd_to_binary(hour&0x7F) | (hour&0x80);
- minutes = bcd_to_binary(minutes);
- seconds = bcd_to_binary(seconds);
- }
- year += 1900;
- /* Y2K compliance: Personal computers using this chipset did not exist
- * prior to about 1985 or so, so let's assume years prior to 1980 are
- * in the 2000's */
- if (year < 1980) year += 100;
-
- if (reg_b & 0x02) {/* 24 hour mode */
- sprintf(tmp,"%02d:%02d:%02d [24hr] ",
- hour,minutes,seconds);
- }
- else {
- /* 12-hour mode, bit 7 of "hours" is set for PM */
- sprintf(tmp,"%02d:%02d:%02d %s ",
- hour&0x7F,minutes,seconds,
- hour&0x80?"PM":"AM");
- }
- vga_write(tmp);
- sprintf(tmp,"%s, %s %d, %d",weekday_to_str(dow),month_to_str(month),dom,year);
- vga_write(tmp);
- vga_write(" ");
-
- pupdate_ints = update_ints;
- update_rdtime = 0;
- }
- if (redraw) {
- unsigned char reg_b,hour,minutes,seconds;
-
- /* we need a copy of Status Register B to know what format
- * the values are given in */
- reg_b = rtc_io_read(0xB);
-
- /* read the time. if an Update In Progress is seen, start over */
-aretry: if (rtc_wait_for_update_complete()) goto aretry;
-aretry2: hour = rtc_io_read(5);
- if (rtc_wait_for_update_complete()) goto aretry2;
- minutes = rtc_io_read(3);
- if (rtc_wait_for_update_complete()) goto aretry2;
- seconds = rtc_io_read(1);
- if (rtc_wait_for_update_complete()) goto aretry2;
- rtc_io_finished();
-
- vga_moveto(0,2);
- vga_write_color(0x1E);
- sprintf(tmp,"ALARM[%s]: ",reg_b & 0x04 ? "BIN" : "BCD");
- vga_write(tmp);
-
- if (!(reg_b & 0x04)) {
- hour = (hour >= 0xC0 ? 0xFF : bcd_to_binary(hour&0x7F) | (hour&0x80));
- minutes = (minutes >= 0xC0 ? 0xFF : bcd_to_binary(minutes));
- seconds = (seconds >= 0xC0 ? 0xFF : bcd_to_binary(seconds));
- }
-
- if (reg_b & 0x02) {/* 24 hour mode */
- if (hour == 0xFF) strcpy(tmp,"XX:");
- else sprintf(tmp,"%02d:",hour);
- vga_write(tmp);
-
- if (minutes == 0xFF) strcpy(tmp,"XX:");
- else sprintf(tmp,"%02d:",minutes);
- vga_write(tmp);
-
- if (seconds == 0xFF) strcpy(tmp,"XX");
- else sprintf(tmp,"%02d",seconds);
- vga_write(tmp);
-
- vga_write(" [24hr]");
- }
- else {
- /* 12-hour mode, bit 7 of "hours" is set for PM */
- if (hour == 0xFF) strcpy(tmp,"XX:");
- else sprintf(tmp,"%02d:",hour&0x7F);
- vga_write(tmp);
-
- if (minutes == 0xFF) strcpy(tmp,"XX:");
- else sprintf(tmp,"%02d:",minutes);
- vga_write(tmp);
-
- if (seconds == 0xFF) strcpy(tmp,"XX");
- else sprintf(tmp,"%02d",seconds);
- vga_write(tmp);
-
- if (hour == 0xFF) strcpy(tmp," ??\n");
- else sprintf(tmp," %s",hour&0x80?"PM":"AM");
- vga_write(tmp);
- }
-
- vga_write(" ");
- }
- if (redraw) {
- unsigned int rate;
- unsigned char c,b;
- const char *str;
-
- c = rtc_io_read(0xA);
- vga_moveto(0,3);
- vga_write_color(0x1E);
- vga_write("REG A: ");
-
- vga_write("TimeBase=");
- b = (c >> 4) & 7;
- if (b == 0) str = "4.194304MHz";
- else if (b == 1) str = "1.048576MHz";
- else if (b == 2) str = "32.768KHz";
- else if (b == 6 || b == 7) str = "[DivReset]";
- else str = "??";
- vga_write(str);
-
- b = c & 0xF;
- if (b > 0) {
- rate = 32768UL >> (b - 1);
- if (((c >> 4) & 7) == 2 && rate > 8192) rate >>= 7;
- sprintf(tmp," PeriodicRate=%uHz",rate);
- vga_write(tmp);
- }
- else {
- vga_write(" PeriodicRate=Off");
- }
-
- vga_write(" ");
- rtc_io_finished();
- }
- if (redraw) {
- unsigned char c;
-
- c = rtc_io_read(0xB);
- vga_moveto(0,4);
- vga_write_color(0x1E);
- vga_write("REG B: ");
-
- sprintf(tmp,"DaylightSaving=%u SquareWave=%u Freeze=%u ",
- c & 0x01 ? 1 : 0,
- c & 0x08 ? 1 : 0,
- c & 0x80 ? 1 : 0);
- vga_write(tmp);
-
- sprintf(tmp,"INTERRUPTS: PI=%u AI=%u UEI=%u\n",
- c & 0x40 ? 1 : 0,
- c & 0x20 ? 1 : 0,
- c & 0x10 ? 1 : 0);
- vga_write(tmp);
-
- rtc_io_finished();
- }
- _sti();
- if (redraw) {
- vga_moveto(0,20);
- vga_write_color(0x1F);
- vga_write("SPACEBAR=Refresh time U=toggle UEI A=toggle AI P=toggle PI\n");
- vga_write_color(0x1C);
- vga_write("2=12/24 hour mode ");
- vga_write("B=BCD/BIN mode! ");
- vga_write_color(0x1F);
- vga_write("r/R=change rate\n");
- vga_write_color(0x1C);
- vga_write("t/T=change timebase [!] ");
- vga_write_color(0x1F);
- vga_write("F=Freeze/set S=toggle square wave");
-
- redraw = 0;
- }
-
- if (kbhit()) {
- unsigned char c;
-
- i = getch();
- if (i == 0) i = getch() << 8;
-
- if (i == 27)
- break;
- else if (i == ' ')
- update_rdtime=1;
- else if (i == 's') {
- _cli();
- c = rtc_io_read(0xB) ^ 0x08;
- rtc_io_write(0xB,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == 'f') {
- /* Real hardware experience: Some RTC
- implementations automatically set the
- Update-Ended Interrupt enable to 0 if
- you set bit 7 of register B. Observed
- on a Pentium 133MHz test machine with
- Intel 430VX based motherboard. Also
- observed is that if you leave bit 7
- enabled, the RTC will NOT let you
- set the UEI bit to 1. */
- _cli();
- c = rtc_io_read(0xB) ^ 0x80;
- rtc_io_write(0xB,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == 't' || i == 'T') {
- /* WARNING: This changes the time base the
- RTC uses for keeping time! On actual
- RTC hardware this can cause the clock to
- run fast. That's why the UI shows this
- option in RED.
-
- Note that on most PCs the RTC is faithfully
- emulated but most implementations will
- simply stop the clock if the time base
- is set to anything other than 32768Hz. */
- _cli();
- c = rtc_io_read(0xA);
- if (i == 't')
- c = (c & 0x8F) | (((c & 0x70) - 0x10) & 0x70);
- else
- c = (c & 0x8F) | (((c & 0x70) + 0x10) & 0x70);
-
- rtc_io_write(0xA,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == 'r' || i == 'R') {
- _cli();
- c = rtc_io_read(0xA);
- if (i == 'r')
- c = (c & 0xF0) | (((c & 0xF) - 1) & 0xF);
- else
- c = (c & 0xF0) | (((c & 0xF) + 1) & 0xF);
-
- rtc_io_write(0xA,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == 'u') {
- /* Real hardware experience: If the Periodic
- interrupt is enabled, and update-ended
- interrupt is not, the RTC will not signal
- IRQ 8 for Update-Ended but will report
- it regardless when our interrupt handler
- reads the status register. Observed on a
- Pentium 133MHz test system: disabling
- the Update-Ended interrupt here but leaving
- periodic on still results in our ISR counting
- update-ended events. So if you observe the
- same on your computer, don't worry, there's
- nothing wrong with this code.
-
- Also observed: If the "freeze" bit (bit 7)
- is set, then the RTC will NOT let you set
- the UEI bit. All writes will force it to
- zero until "freeze" is zero. */
- _cli();
- c = rtc_io_read(0xB) ^ 0x10; /* toggle Update-Ended */
- rtc_io_write(0xB,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == 'a') {
- _cli();
- c = rtc_io_read(0xB) ^ 0x20; /* toggle Alarm */
- rtc_io_write(0xB,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == 'p') {
- /* Real hardware experience: If we disable
- IRQ 8 on periodic interrupt, the RTC still
- sets the periodic bit in the status register.
- So if you disable the periodic interrupt here,
- our ISR will still count periodic interrupts.
- Observed on a Pentium 133MHz test machine. */
- _cli();
- c = rtc_io_read(0xB) ^ 0x40; /* toggle Periodic */
- rtc_io_write(0xB,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == '2') {
- /* Observed on an actual Pentium 133MHz test
- system: Changing 12/24 hour formats does NOT
- change the actual byte value, it merely changes
- how the chipset (and this software) interpret
- them, usually with hilarious results and some
- confusion */
- _cli();
- c = rtc_io_read(0xB) ^ 0x02;
- rtc_io_write(0xB,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- else if (i == 'b') {
- /* Observed on an actual Pentium 133MHz test
- system: Changing binary -> BCD or BCD -> binary
- merely causes the chipset (and this program)
- to re-interpret whatever bytes were there,
- it does not magically change the values over.
- That means whatever BCD values you had in the
- RTC clock will suddenly be incremented on update
- as if they were binary, with hilarious results. */
- _cli();
- c = rtc_io_read(0xB) ^ 0x04;
- rtc_io_write(0xB,c);
- rtc_io_finished();
- redraw = 1;
- _sti();
- }
- }
- }
-
- vga_moveto(0,vga_height-2);
- vga_sync_bios_cursor();
- vga_sync_hw_cursor();
-
- /* restore old IRQ 8 */
- _dos_setvect(0x70,old_irq8);
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly\r
-# NTS: HPS is either \ (DOS) or / (Linux)\r
-NOW_BUILDING = HW_SMBIOS_LIB\r
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..\r
-\r
-C_SOURCE = smbios.c\r
-OBJS = $(SUBDIR)$(HPS)smbios.obj\r
-TEST_EXE = $(SUBDIR)$(HPS)test.exe\r
-\r
-$(HW_SMBIOS_LIB): $(OBJS)\r
- wlib -q -b -c $(HW_SMBIOS_LIB) -+$(SUBDIR)$(HPS)smbios.obj\r
-\r
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS\r
-# systems all arguments would exceed the pitiful 128 char command line limit\r
-.C.OBJ:\r
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@\r
- $(CC) @tmp.cmd\r
-\r
-all: lib exe\r
-\r
-lib: $(HW_SMBIOS_LIB) .symbolic\r
- \r
-exe: $(TEST_EXE) .symbolic\r
-\r
-$(TEST_EXE): $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(HW_FLATREAL_LIB_DEPENDENCIES) $(HW_SMBIOS_LIB) $(HW_SMBIOS_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj\r
- %write tmp1.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_SMBIOS_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIS) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) name $(TEST_EXE)\r
- @wlink @tmp1.cmd\r
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe\r
-\r
-clean: .SYMBOLIC\r
- del $(SUBDIR)$(HPS)*.obj\r
- del $(HW_SMBIOS_LIB)\r
- del tmp.cmd\r
- @echo Cleaning done\r
-\r
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h>
-#include <hw/8259/8259.h>
-#include <hw/smbios/smbios.h>
-#include <hw/flatreal/flatreal.h>
-#include <hw/dos/doswin.h>
-
-uint8_t smbios_access=0;
-#if TARGET_MSDOS == 32
-uint8_t *smbios_table=NULL,*smbios_table_fence=NULL;
-#endif
-uint32_t smbios_entry_point=0;
-struct smbios_entry_struct smbios_entry;
-
-const char *smbios_access_str[] = {
- "direct",
- "flat"
-};
-
-const char *smbios_type_to_str(uint8_t t) {
- switch (t) {
- case 0x00: return "BIOS";
- case 0x01: return "System";
- case 0x02: return "Base board";
- case 0x03: return "System enclosure";
- case 0x04: return "Processor";
- case 0x05: return "Memory controller";
- case 0x06: return "Memory module";
- case 0x07: return "Cache";
- case 0x08: return "Port connector";
- case 0x09: return "System slots";
- case 0x0A: return "On-board devices";
- case 0x0B: return "OEM strings";
- case 0x0C: return "System configuration";
- case 0x0D: return "BIOS language";
- case 0x0E: return "Group association";
- case 0x0F: return "System event log";
- case 0x10: return "Physical memory array";
- case 0x11: return "Memory device";
- case 0x12: return "32-bit memory error";
- case 0x13: return "Memory array mapped address";
- case 0x14: return "Memory device mapped address";
- case 0x15: return "Built-in pointing device";
- case 0x16: return "Portable battery";
- case 0x17: return "System reset";
- case 0x18: return "Hardware security";
- case 0x19: return "System power controls";
- case 0x1A: return "Voltage probe";
- case 0x1B: return "Cooling device";
- case 0x1C: return "Temperature probe";
- case 0x1D: return "Electrical current probe";
- case 0x1E: return "Out-of-band remote access";
- case 0x1F: return "Boot integrity services";
- case 0x20: return "System boot";
- case 0x21: return "64-bit memory error";
- case 0x22: return "Management device";
- case 0x23: return "Management device component";
- case 0x24: return "Management device threshold data";
- case 0x25: return "Memory channel";
- case 0x26: return "IPMI device";
- case 0x27: return "System power supply";
- case 0x28: return "Additional information";
- case 0x29: return "Onboard devices extended information";
- case 0x7E: return "Inactive";
- case 0x7F: return "End of table";
- };
-
- return "";
-}
-
-uint8_t smbios_peek(uint32_t ofs) {
-#if TARGET_MSDOS == 32
- if (smbios_table == NULL || ofs >= ((size_t)(smbios_table_fence - smbios_table)))
- return 0;
-
- return smbios_table[ofs];
-#else
- if (ofs >= smbios_entry.structure_table_length)
- return 0;
-
- ofs += smbios_entry.structure_table_address;
- if (smbios_access == SMBIOS_ACCESS_FLAT) {
- if (!flatrealmode_ok() && !flatrealmode_setup(FLATREALMODE_4GB)) return 0;
- return flatrealmode_readb(ofs);
- }
- else if (ofs <= 0xFFFFFUL) {
- return *((unsigned char far*)MK_FP(ofs>>4,ofs&0xF));
- }
-#endif
-
- return 0;
-}
-
-void smbios_get_string(char *d,size_t dl,uint32_t o) {
- unsigned int of=0;
- unsigned char c;
-
- while ((of+1) < (unsigned int)dl) {
- c = smbios_peek(o++);
- if (c == 0) break;
- d[of++] = c;
- }
- d[of] = 0;
-}
-
-int smbios_next_entry(uint32_t ofs,struct smbios_struct_entry *s) {
- unsigned int o;
-
- if ((ofs+4) > smbios_entry.structure_table_length)
- return 0;
-
- s->offset = ofs;
- s->strings = 0;
- s->type = smbios_peek(ofs+0);
- s->length = smbios_peek(ofs+1);
- s->handle = smbios_peek(ofs+2) | ((uint16_t)smbios_peek(ofs+3) << 8U);
- if ((ofs+s->length) > smbios_entry.structure_table_length) return 0;
-
- /* then ASCII strings follow */
- o = s->length;
- do {
- if (smbios_peek(ofs+o) == 0 && smbios_peek(ofs+o+1) == 0) {
- o += 2;
- break;
- }
- else if (smbios_peek(ofs+o) == 0) {
- o++;
- }
-
- if (s->strings < 256) s->str_ofs[s->strings++] = o;
- while (smbios_peek(ofs+o) != 0) o++;
- } while (1);
- s->total_length = o;
- return 1;
-}
-
-int smbios_scan() {
- unsigned int o,i;
-#if TARGET_MSDOS == 32
- unsigned char *base = (unsigned char*)0xF0000UL;
-#else
- unsigned char far *base = (unsigned char far*)MK_FP(0xF000U,0x0000U);
-#endif
-
- assert(sizeof(struct smbios_entry_struct) == 0x1F);
-
- /* the signature lies on a paragraph boundary between 0xF0000-0xFFFFF and is 0x1F long */
- smbios_entry_point=0;
- for (i=0;i < 0xFFF0;i += 0x10) {
- if (base[i+0] == '_' && base[i+1] == 'S' && base[i+2] == 'M' && base[i+3] == '_') { /* _SM_ */
- unsigned char len = base[i+5],chk;
- if (len >= 0x1E && ((long)i + (long)len) < 0xFFFFL) {
- for (o=0,chk=0;o < (unsigned int)len;o++) {
- ((unsigned char*)(&smbios_entry))[o] = base[i+o];
- chk += base[i+o];
- }
- if (chk == 0 && smbios_entry.structure_table_length > 2) {
- /* choose access method */
-#if TARGET_MSDOS == 32
- smbios_access = SMBIOS_ACCESS_DIRECT;
- if (!dos_ltp_info.paging)
- smbios_table = (uint8_t*)smbios_entry.structure_table_address;
- else
- smbios_table = NULL;/* TODO */
- if (smbios_table == NULL) continue;
- smbios_table_fence = smbios_table + smbios_entry.structure_table_length;
-#else
- /* real mode: if the address is below the 1MB boundary we can access it directly */
- if ((smbios_entry.structure_table_address+smbios_entry.structure_table_length) <= 0xFFFFFUL)
- smbios_access = SMBIOS_ACCESS_DIRECT;
- else if (flatrealmode_allowed())
- smbios_access = SMBIOS_ACCESS_FLAT;
- else
- continue;
-#endif
-
- smbios_entry_point=(uint32_t)i + (uint32_t)0xF0000UL;
- return 1;
- }
- }
- }
- }
-
- return 0;
-}
-
-const char *smbios_wake_up_type(uint8_t t) {
- switch (t) {
- case 0x01: return "Other";
- case 0x02: return "Unknown";
- case 0x03: return "APM timer";
- case 0x04: return "Modem ring";
- case 0x05: return "LAN remote";
- case 0x06: return "Power switch";
- case 0x07: return "PCI PME#";
- case 0x08: return "AC Power restored";
- };
-
- return "";
-}
-
+++ /dev/null
-
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdint.h>
-
-#pragma pack(push,1)
-struct smbios_entry_struct {
- char sm_sig[4]; /* +0 */
- uint8_t checksum; /* +4 */
- uint8_t length; /* +5 length of this structure */
- uint8_t major_version,minor_version; /* +6 */
- uint16_t maximum_structure_size; /* +8 */
- uint8_t entry_point_revision; /* +10 */
- uint8_t formatted_area[5]; /* +11 */
- char dmi_sig[5]; /* +16 _DMI_ */
- uint8_t intermediate_checksum; /* +21 */
- uint16_t structure_table_length; /* +22 */
- uint32_t structure_table_address; /* +24 */
- uint16_t number_of_smbios_structures; /* +28 */
- uint8_t smbios_bcd_revision; /* +30 */
-};
-
-struct smbios_struct_entry {
- uint32_t offset;
- uint16_t handle; /* +2 */
- uint16_t total_length;
- uint8_t type,length; /* +0 */
- uint16_t str_ofs[256]; /* offset of string relative to entry */
- uint16_t strings;
-};
-
-struct smbios_bios_info {
- uint8_t type,length; /* +0 type=0 */
- uint16_t handle; /* +2 */
- uint8_t vendor_str_idx; /* +4 */
- uint8_t bios_version_str_idx; /* +5 */
- uint16_t bios_starting_address_segment; /* +6 */
- uint8_t bios_release_data_str_idx; /* +8 */
- uint8_t bios_rom_size; /* +9 size = 64K*(1+n) */
- uint64_t bios_characteristics; /* +10 */
- uint16_t bios_characteristics_ext; /* +18 */
- uint8_t t1,t2,t3,t4; /* +20 */
-};
-
-struct smbios_guid {
- uint32_t a; /* +0 */
- uint16_t b,c; /* +4 */
- uint8_t d[8]; /* +8 */
-};
-
-struct smbios_system_info {
- uint8_t type,length; /* +0 type=1 */
- uint16_t handle; /* +2 */
- uint8_t manufacturer_str_idx; /* +4 */
- uint8_t product_name_str_idx; /* +5 */
- uint8_t version_str_idx; /* +6 */
- uint8_t serial_number_str_idx; /* +7 */
- struct smbios_guid uuid; /* +8 */
- uint8_t wake_up_type; /* +24 */
- uint8_t sku_number_str_idx; /* +25 */
- uint8_t family_str_idx; /* +26 */
-};
-#pragma pack(pop)
-
-enum {
- SMBIOS_ACCESS_DIRECT=0, /* direct access to the struct */
- SMBIOS_ACCESS_FLAT /* flat real mode access */
-};
-
-extern const char *smbios_access_str[];
-#define smbios_access_to_str(x) smbios_access_str[x]
-
-#if TARGET_MSDOS == 32
-extern uint8_t *smbios_table,*smbios_table_fence;
-#endif
-extern uint32_t smbios_entry_point;
-extern uint8_t smbios_access;
-extern struct smbios_entry_struct smbios_entry;
-
-const char *smbios_wake_up_type(uint8_t t);
-int smbios_next_entry(uint32_t ofs,struct smbios_struct_entry *s);
-void smbios_get_string(char *d,size_t dl,uint32_t o);
-const char *smbios_type_to_str(uint8_t t);
-uint8_t smbios_peek(uint32_t ofs);
-int smbios_scan();
-
-#define SMBIOS_BIOS_CF_ISA (1ULL << 4ULL)
-#define SMBIOS_BIOS_CF_MCA (1ULL << 5ULL)
-#define SMBIOS_BIOS_CF_EISA (1ULL << 6ULL)
-#define SMBIOS_BIOS_CF_PCI (1ULL << 7ULL)
-#define SMBIOS_BIOS_CF_PCMCIA (1ULL << 8ULL)
-#define SMBIOS_BIOS_CF_PnP (1ULL << 9ULL)
-#define SMBIOS_BIOS_CF_APM (1ULL << 10ULL)
-#define SMBIOS_BIOS_CF_IS_UPGRADEABLE (1ULL << 11ULL)
-#define SMBIOS_BIOS_CF_SHADOWING_ALLOWED (1ULL << 12ULL)
-#define SMBIOS_BIOS_CF_VL_VESA (1ULL << 13ULL)
-#define SMBIOS_BIOS_CF_ESCD_AVAILABLE (1ULL << 14ULL)
-#define SMBIOS_BIOS_CF_BOOT_FROM_CD (1ULL << 15ULL)
-#define SMBIOS_BIOS_CF_SELECTABLE_BOOT (1ULL << 16ULL)
-#define SMBIOS_BIOS_CF_BIOS_ROM_SOCKETED (1ULL << 17ULL)
-#define SMBIOS_BIOS_CF_BOOT_FROM_PCMCIA (1ULL << 18ULL)
-#define SMBIOS_BIOS_CF_EDD_SUPPORTED (1ULL << 19ULL)
-#define SMBIOS_BIOS_CF_INT13_NEC_9800_FLOPPY (1ULL << 20ULL)
-#define SMBIOS_BIOS_CF_INT13_TOSHIBA_1_2MB (1ULL << 21ULL)
-#define SMBIOS_BIOS_CF_INT13_5_25_360KB (1ULL << 22ULL)
-#define SMBIOS_BIOS_CF_INT13_5_25_1_2MB (1ULL << 23ULL)
-#define SMBIOS_BIOS_CF_INT13_3_5_720KB (1ULL << 24ULL)
-#define SMBIOS_BIOS_CF_INT13_3_5_288MB (1ULL << 25ULL)
-#define SMBIOS_BIOS_CF_INT5_PRINT_SCREEN (1ULL << 26ULL)
-#define SMBIOS_BIOS_CF_INT9_8042_KEYBOARD (1ULL << 27ULL)
-#define SMBIOS_BIOS_CF_INT14_SERIAL (1ULL << 28ULL)
-#define SMBIOS_BIOS_CF_INT17_PRINTER (1ULL << 29ULL)
-#define SMBIOS_BIOS_CF_INT10_CGA_MONO (1ULL << 30ULL)
-#define SMBIOS_BIOS_CF_NEC_PC98 (1ULL << 31ULL)
-
+++ /dev/null
-/* FIXME:
- * On some newer Toshiba laptops I own, 16-bit real-mode versions of this code are unable
- * to read SMBIOS/DMI structures. Why? */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/8254/8254.h>
-#include <hw/8259/8259.h>
-#include <hw/smbios/smbios.h>
-#include <hw/flatreal/flatreal.h>
-#include <hw/dos/doswin.h>
-
-int main() {
- struct smbios_struct_entry sen;
- unsigned int i,j;
- char tmpstr[257];
- uint32_t ofs;
-
- printf("DMI/SMBIOS test program\n");
-
- cpu_probe(); /* ..for the DOS probe routine */
- probe_dos(); /* ..for the Windows detection code */
- detect_windows(); /* Windows virtualizes the LPT ports, and we don't want probing to occur to avoid any disruption */
-#if TARGET_MSDOS == 32
- probe_dpmi();
- dos_ltp_probe();
-#endif
-
- if (!smbios_scan()) {
- printf("SMBIOS/DMI signature not found\n");
- return 1;
- }
-
- printf("SMBIOS entry point at 0x%08lx len=%u v%u.%u max-struct-size=%u rev=%u\n",(unsigned long)smbios_entry_point,smbios_entry.length,
- smbios_entry.major_version,smbios_entry.minor_version,smbios_entry.maximum_structure_size,
- smbios_entry.entry_point_revision);
- printf(" structure table length=%u address=0x%08lX structures=%u BCD=0x%02x\n method=%s\n",
- smbios_entry.structure_table_length,
- smbios_entry.structure_table_address,
- smbios_entry.number_of_smbios_structures,
- smbios_entry.smbios_bcd_revision,
- smbios_access_to_str(smbios_access));
-
- for (i=0,ofs=0UL;i < smbios_entry.number_of_smbios_structures;i++) {
- if (!smbios_next_entry(ofs,&sen)) {
- printf("Premature end\n");
- break;
- }
-
- printf("@%lu Type 0x%02x Len 0x%02x Handle=0x%04x %u strings (%s)\n",
- (unsigned long)ofs,
- sen.type,sen.length,sen.handle,sen.strings,
- smbios_type_to_str(sen.type));
-
- if (sen.type == 0) { /* BIOS information */
- struct smbios_bios_info bi;
-
- for (j=0;j < (unsigned int)sizeof(bi);j++)
- ((uint8_t*)(&bi))[j] = smbios_peek(ofs+j);
-
- if (bi.vendor_str_idx != 0 && bi.vendor_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.vendor_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" Vendor: '%s' (%u)\n",tmpstr,bi.vendor_str_idx);
- if (bi.bios_version_str_idx != 0 && bi.bios_version_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.bios_version_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" BIOS version: '%s' (%u)\n",tmpstr,bi.bios_version_str_idx);
- printf(" BIOS starting addr: 0x%05lx\n",(unsigned long)bi.bios_starting_address_segment << 4UL);
- if (bi.bios_release_data_str_idx != 0 && bi.bios_release_data_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.bios_release_data_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" BIOS release data: '%s' (%u)\n",tmpstr,bi.bios_release_data_str_idx);
- printf(" BIOS ROM size: %uKB\n",64 * ((unsigned int)bi.bios_rom_size + 1));
- printf(" BIOS characteristics: 0x%016llx\n",(unsigned long long)bi.bios_characteristics);
- printf(" ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_ISA) printf("ISA ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_MCA) printf("MCA ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_EISA) printf("EISA ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_PCI) printf("PCI ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_PCMCIA) printf("PCMCIA ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_PnP) printf("PnP ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_APM) printf("APM ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_IS_UPGRADEABLE) printf("Upgradeable ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_SHADOWING_ALLOWED) printf("Shadowable ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_VL_VESA) printf("VL-VESA ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_ESCD_AVAILABLE) printf("ESCD ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_BOOT_FROM_CD) printf("BootFromCD ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_SELECTABLE_BOOT) printf("SelectableBOOT ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_BIOS_ROM_SOCKETED) printf("BIOSROMSocketed ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_BOOT_FROM_PCMCIA) printf("BootFromPCMCIA ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_EDD_SUPPORTED) printf("EDD ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT13_NEC_9800_FLOPPY) printf("NEC9800Floppy ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT13_TOSHIBA_1_2MB) printf("Toshiba1.2MB ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT13_5_25_360KB) printf("5.25/360KB ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT13_5_25_1_2MB) printf("5.25/1.2MB ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT13_3_5_720KB) printf("3.5/720KB ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT13_3_5_288MB) printf("3.5/2.88MB ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT5_PRINT_SCREEN) printf("PrintScreen ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT9_8042_KEYBOARD) printf("8042Keyboard ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT14_SERIAL) printf("INT14Serial ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT17_PRINTER) printf("INT17Printer ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_INT10_CGA_MONO) printf("INT10CGAMono ");
- if (bi.bios_characteristics & SMBIOS_BIOS_CF_NEC_PC98) printf("NEC-PC98 ");
- printf("\n");
- }
- else if (sen.type == 1) {
- struct smbios_system_info bi;
-
- for (j=0;j < (unsigned int)sizeof(bi);j++)
- ((uint8_t*)(&bi))[j] = smbios_peek(ofs+j);
-
- if (bi.manufacturer_str_idx != 0 && bi.manufacturer_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.manufacturer_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" Manufacturer: '%s' (%u)\n",tmpstr,bi.manufacturer_str_idx);
-
- if (bi.product_name_str_idx != 0 && bi.product_name_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.product_name_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" Product name: '%s' (%u)\n",tmpstr,bi.product_name_str_idx);
-
- if (bi.version_str_idx != 0 && bi.version_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.version_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" Version: '%s' (%u)\n",tmpstr,bi.version_str_idx);
-
- if (bi.serial_number_str_idx != 0 && bi.serial_number_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.serial_number_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" Serial No.: '%s' (%u)\n",tmpstr,bi.serial_number_str_idx);
-
- printf(" UUID: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
- (unsigned long)bi.uuid.a,
- (unsigned int)bi.uuid.b,
- (unsigned int)bi.uuid.c,
- bi.uuid.d[0],bi.uuid.d[1],
- bi.uuid.d[2],bi.uuid.d[3],bi.uuid.d[4],bi.uuid.d[5],bi.uuid.d[6],bi.uuid.d[7]);
- printf(" Wake up type: %s (%u)\n",smbios_wake_up_type(bi.wake_up_type),bi.wake_up_type);
-
- if (bi.sku_number_str_idx != 0 && bi.sku_number_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.sku_number_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" SKU No.: '%s' (%u)\n",tmpstr,bi.sku_number_str_idx);
-
- if (bi.family_str_idx != 0 && bi.family_str_idx <= sen.strings)
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[bi.family_str_idx-1]);
- else
- tmpstr[0] = 0;
- printf(" Family: '%s' (%u)\n",tmpstr,bi.family_str_idx);
- }
- else {
- for (j=0;j < sen.strings;j++) {
- smbios_get_string(tmpstr,sizeof(tmpstr),ofs+sen.str_ofs[j]);
- printf(" str(%u) = '%s' @%u\n",j,tmpstr,sen.str_ofs[j]);
- }
- }
-
- ofs += sen.total_length;
- }
-
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_SNDSB_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = sndsb.c
-OBJS = $(SUBDIR)$(HPS)sndsb.obj
-OBJSPNP = $(SUBDIR)$(HPS)sndsbpnp.obj
-PNPCFG_EXE = $(SUBDIR)$(HPS)pnpcfg.exe
-
-!ifeq TARGET_MSDOS 16
-! ifeq MMODE c
-# this test program isn't going to fit in the compact memory model. sorry.
-NO_TEST_ISAPNP=1
-NO_TEST_EXE=1
-! endif
-! ifeq MMODE s
-# yet again, doesn't fit into the small memory model (by 10 bytes)
-NO_TEST_ISAPNP=1
-NO_TEST_EXE=1
-! endif
-!endif
-
-!ifndef NO_TEST_EXE
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-!endif
-
-$(HW_SNDSB_LIB): $(OBJS)
- wlib -q -b -c $(HW_SNDSB_LIB) -+$(SUBDIR)$(HPS)sndsb.obj
-
-$(HW_SNDSBPNP_LIB): $(OBJSPNP)
- wlib -q -b -c $(HW_SNDSBPNP_LIB) -+$(SUBDIR)$(HPS)sndsbpnp.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- @$(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_SNDSB_LIB) $(HW_SNDSBPNP_LIB) .symbolic
-
-exe: $(TEST_EXE) $(PNPCFG_EXE) .symbolic
-
-!ifdef TEST_EXE
-$(TEST_EXE): $(WINDOWS_W9XVMM_LIB) $(WINDOWS_W9XVMM_LIB_DEPENDENCIES) $(HW_SNDSB_LIB) $(HW_SNDSB_LIB_DEPENDENCIES) $(HW_SNDSBPNP_LIB) $(HW_SNDSBPNP_LIB_DEPENDENCIES) $(HW_8237_LIB) $(HW_8237_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_VGAGUI_LIB) $(HW_VGAGUI_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd
-! ifeq TARGET_MSDOS 16 # Sound Blaster library needs more stack than default
- %append tmp.cmd option stack=4096
-! endif
- %append tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_SNDSB_LIB_WLINK_LIBRARIES) $(HW_8237_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_VGAGUI_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES)
-! ifndef NO_TEST_ISAPNP
- %append tmp.cmd $(HW_ISAPNP_LIB_WLINK_LIBRARIES) $(WINDOWS_W9XVMM_LIB_WLINK_LIBRARIES) $(HW_SNDSBPNP_LIB_WLINK_LIBRARIES)
-! endif
- %append tmp.cmd name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-$(PNPCFG_EXE): $(WINDOWS_W9XVMM_LIB) $(HW_SNDSB_LIB) $(HW_SNDSB_LIB_DEPENDENCIES) $(HW_SNDSBPNP_LIB) $(HW_SNDSBPNP_LIB_DEPENDENCIES) $(HW_8237_LIB) $(HW_8237_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_ISAPNP_LIB) $(HW_ISAPNP_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)pnpcfg.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)pnpcfg.obj $(HW_SNDSB_LIB_WLINK_LIBRARIES) $(HW_SNDSBPNP_LIB_WLINK_LIBRARIES) $(HW_8237_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_ISAPNP_LIB_WLINK_LIBRARIES) $(WINDOWS_W9XVMM_LIB_WLINK_LIBRARIES) name $(PNPCFG_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_SNDSB_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/sndsb/sndsb.h>
-#include <hw/isapnp/isapnp.h>
-#include <hw/sndsb/sndsbpnp.h>
-
-/* NTS: caller is expected to WAKE[CSN] the card for us */
-void ms_virtualpc_prompt() {
- int dma,irq=0;
-
- printf("Currently configured:\n");
-
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x00); /* main device */
-
- /* NTS: I/O port is reported "fixed" in both PnP BIOS and configuration data */
- dma = isa_pnp_read_dma(0); /* FIXME: Does Virtual PC support changing this value? */
- irq = isa_pnp_read_irq(0); /* FIXME: Does Virtual PC support changing this value? */
-
- printf(" DMA (main) %d\n",dma);
- printf(" IRQ %d\n",irq);
-
- while (getch() != 13);
-}
-
-enum {
- SB_VIBRA=0,
- SB_AWE
-};
-
-/* NTS: caller is expected to WAKE[CSN] the card for us */
-/* TODO: On AWE32/AWE64 cards the wavetable section is logical device #2 */
-void ct_sb16pnp_prompt(int typ) {
- int io[3]={0,0,0},dma[2]={0,0},irq=0,val,game,wavetable;
-
- printf("Answer the questions. You may enter -1 to skip card, -2 to unassign\n");
- printf("or -3 to not change.\n");
- printf("Currently configured:\n");
-
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x00); /* sound blaster (0) */
-
- io[0] = isa_pnp_read_io_resource(0);
- io[1] = isa_pnp_read_io_resource(1);
- io[2] = isa_pnp_read_io_resource(2);
- dma[0] = isa_pnp_read_dma(0);
- dma[1] = isa_pnp_read_dma(1);
- irq = isa_pnp_read_irq(0);
-
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x01); /* gameport (1) */
-
- game = isa_pnp_read_io_resource(0);
-
- if (typ == SB_AWE) {
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x02); /* wavetable (AWE) (2) */
-
- wavetable = isa_pnp_read_io_resource(0);
- }
-
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x00); /* main device */
-
- printf(" I/O (SoundBlaster) 0x%03x\n",io[0]);
- printf(" I/O (MPU) 0x%03x\n",io[1]);
- printf(" I/O (OPL3) 0x%03x\n",io[2]);
- printf(" I/O (GAME) 0x%03x\n",game);
- if (typ == SB_AWE) printf(" I/O (AWE) 0x%03x\n",wavetable);
- printf(" DMA (8-bit) %d\n",dma[0]);
- printf(" DMA (16-bit) %d\n",dma[1]);
- printf(" IRQ %d\n",irq);
-
- /* 0x220,0x240,0x260,0x280 */
- printf(" - SoundBlaster Port? (2x0 x=2,4,6,8) :"); fflush(stdout); val=2; scanf("%d",&val);
- if (val >= 2 && (val&1) == 0) io[0] = 0x200 + (val * 0x10);
- else if (val == -1) return;
- else if (val == -2) io[0] = 0;
-
- printf(" - MPU Port? (3x0 x=0,3) :"); fflush(stdout); val=0; scanf("%d",&val);
- if (val == 0 || val == 3) io[1] = 0x300 + (val * 0x10);
- else if (val == -1) return;
- else if (val == -2) io[1] = 0;
-
- printf(" - OPL3 Port? (0=388 or 1=392) :"); fflush(stdout); val=0; scanf("%d",&val);
- if (val >= 0 && val <= 15) io[2] = 0x388 + (val * 0x4);
- else if (val == -1) return;
- else if (val == -2) io[2] = 0;
-
- printf(" - GAME Port? (2x0 0-7) :"); fflush(stdout); val=0; scanf("%d",&val);
- if (val >= 0 && val <= 7) game = 0x200 + val;
- else if (val == -1) return;
- else if (val == -2) game = 0;
-
- if (typ == SB_AWE) {
- /* despite Creative's PNP configuration data, programming
- experience says we can literally place it anywhere in
- the 6xx range! */
- printf(" - AWE Port? (6x0 x=0,2,4,6,8) :"); fflush(stdout); val=0; scanf("%d",&val);
- if (val >= 0 && val <= 9) wavetable = 0x600 + (val * 0x10);
- else if (val == -1) return;
- else if (val == -2) wavetable = 0;
- }
-
- printf(" - IRQ? (5,7,9,10) :"); fflush(stdout); val=0; scanf("%d",&val);
- if (val >= 2 && val <= 15) irq = val;
- else if (val == -1) return;
- else if (val == -2) irq = -1;
-
- printf(" - 8-bit DMA? (0,1,3) :"); fflush(stdout); val=0; scanf("%d",&val);
- if (val >= 0 && val <= 3) dma[0] = val;
- else if (val == -1) return;
- else if (val == -2) dma[0] = -1;
-
- printf(" - 16-bit DMA? (0,1,3,5,6,7) :"); fflush(stdout); val=0; scanf("%d",&val);
- if (val >= 0 && val <= 7) dma[1] = val;
- else if (val == -1) return;
- else if (val == -2) dma[1] = -1;
-
- /* disable the device IO (0) */
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x00); /* main device */
-
- isa_pnp_write_data_register(0x30,0x00); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
-
- isa_pnp_write_io_resource(0,io[0]);
- isa_pnp_write_io_resource(1,io[1]);
- isa_pnp_write_io_resource(2,io[2]);
- isa_pnp_write_dma(0,dma[0]);
- isa_pnp_write_dma(1,dma[1]);
- isa_pnp_write_irq(0,irq);
- isa_pnp_write_irq_mode(0,2); /* edge level high */
-
- /* enable the device IO */
- isa_pnp_write_data_register(0x30,0x01); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
-
- /* disable the device IO (1) */
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x01); /* main device */
-
- isa_pnp_write_data_register(0x30,0x00); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
-
- isa_pnp_write_io_resource(0,game);
-
- /* enable the device IO */
- isa_pnp_write_data_register(0x30,0x01); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
-
- if (typ == SB_AWE) {
- /* disable the device IO (2) */
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x02); /* main device */
-
- isa_pnp_write_data_register(0x30,0x00); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
-
- isa_pnp_write_io_resource(0,wavetable);
-
- /* enable the device IO */
- isa_pnp_write_data_register(0x30,0x01); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
- }
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
-
- printf("Okay, I reconfigured the card\n");
- while (getch() != 13);
-}
-
-int main() {
- printf("Sound Blaster Plug & Play configuration utility\n");
-
- if (!probe_8237()) {
- printf("Cannot init 8237 DMA\n");
- return 1;
- }
- if (!probe_8259()) {
- printf("Cannot init 8259 PIC\n");
- return 1;
- }
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!init_sndsb()) {
- printf("Cannot init library\n");
- return 1;
- }
- if (!init_isa_pnp_bios()) {
- printf("Cannot init ISA PnP\n");
- return 1;
- }
- if (find_isa_pnp_bios()) {
- char tmp[192];
- unsigned int j;
- const char *whatis = NULL;
- unsigned char csn,data[192];
-
- memset(data,0,sizeof(data));
- if (isa_pnp_bios_get_pnp_isa_cfg(data) == 0) {
- struct isapnp_pnp_isa_cfg *nfo = (struct isapnp_pnp_isa_cfg*)data;
- isapnp_probe_next_csn = nfo->total_csn;
- isapnp_read_data = nfo->isa_pnp_port;
- }
- else {
- printf(" ISA PnP BIOS failed to return configuration info\n");
- }
-
- if (isapnp_read_data != 0) {
- printf("Scanning ISA PnP devices...\n");
- for (csn=1;csn < 255;csn++) {
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
-
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() == csn) {
- /* apparently doing this lets us read back the serial and vendor ID in addition to resource data */
- /* if we don't, then we only read back the resource data */
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
-
- for (j=0;j < 9;j++) data[j] = isa_pnp_read_config();
-
- if (isa_pnp_is_sound_blaster_compatible_id(*((uint32_t*)data),&whatis)) {
- isa_pnp_product_id_to_str(tmp,*((uint32_t*)data));
-
- printf(" [%u]: %02x %02x %02x %02x %02x %02x %02x %02x %02x ",csn,
- data[0],data[1],data[2],data[3],
- data[4],data[5],data[6],data[7],
- data[8]);
-
- printf("%s %s\n",tmp,whatis);
-
- if (!memcmp(tmp,"CTL",3)) {
- if (!memcmp(tmp+3,"0070",4) || !memcmp(tmp+3,"00F0",4)) {
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
- ct_sb16pnp_prompt(SB_VIBRA);
- }
- /* NTS: The 00B2 version is the "Gold" version */
- else if (!memcmp(tmp+3,"00C3",4) || !memcmp(tmp+3,"00B2",4)) {
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
- ct_sb16pnp_prompt(SB_AWE);
- }
- }
- else if (!memcmp(tmp,"TBA03B0",7)) {
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
- ms_virtualpc_prompt();
- }
- }
- }
- }
- }
- }
- else {
- printf("Warning, ISA PnP BIOS not found\n");
- }
-
- return 0;
-}
-
+++ /dev/null
-
-Creative Sound Blaster or 100% Compatible sound output library.
-(C) 2008-2011 Jonathan Campbell.
-Compiles with Open Watcom.
-
-What it supports:
- Any Sound Blaster or Sound Blaster compatible interface that communicates
- on ISA I/O ports 0x2x0-0x2xF (where X=2,4,6, or 8) using ISA DMA channels
- 0, 1, or 3 and 16-bit DMA on 0, 1, 3, 5, 6, or 7.
-
- Also supports and recognizes various known emulations of the Sound Blaster,
- including:
-
- - Gallant/SC400 Crystal Semiconductor CS4232-based cards
- - They emulate a SB16 with a SBPRO mixer, and a Windows Sound System
- interface on 0x530 or 0xE30.
- - Their Sound Blaster emulation also has a proprietary "plug & play"
- software configuration command set, supported by this library
-
- - Yamaha OPL3-SAx Sound Blaster emulation
-
-NOTICE: The sndsb.lib library by itself does not contain support for ISA Plug &
- Play Sound Blaster cards. The isapnp library is kind of large and
- building this library to depend on it only serves to add bloat to your
- program (especially if you will be targeting pre-486 hardware where
- PnP type hardware is very unlikely to be found).
-
- If you do want your program to support PnP type cards (especially if
- your code is intended for 486 and higher hardware) then you can link
- into your program sndsbpnp.lib and isapnp.lib to enable autodetection
- of ISA Plug & Play based Sound Blaster hardware.
-
-WARNING: Sound Blaster PnP support is written only to read back the
- resources assigned. Cards whos resources have not been assigned
- will be ignored.
-
- In the DOS world, the task of PnP resource assignment is
- generally given to a device driver or DOS utility that carries
- out configuration (such as: Creative PnP utilities).
-
- If you really want to, look at the PNPCFG.EXE utility provided
- here as an example of a minimalist Sound Blaster PnP resource
- assignment program. Then if you really want to, go ahead and
- write your program to auto-configure the card if necessary.
- I strongly recommend though that if you do that, you allow the
- user to turn it off, since the PnP device is likely sharing the
- system with perhaps several other ISA devices that could easily
- conflict with the one you're trying to auto-config!
-
-TABLE OF SUPPORTED CARDS
-------------------------
-
- YES = Card is supported, verified by actual h/w testing
- HWEMU = If listed with YES or LIKELY, the hardware itself responds to I/O ports
- like a Sound Blaster even though the chipset is something else entirely
- LIKELY = Card is supported, because the interface is Sound Blaster compatible,
- but I have not yet tested and verified that it works. If listed with
- SWEMU, then the software emulation is likely Sound Blaster compatible
- even though the actual hardware is not.
- MAYBE = Card might be Sound Blaster compatible, I don't really know
- PNP = Card is ISA Plug & Play compatible, if listed with YES or LIKELY the
- card will work with this library IF you first run an ISA PnP configuration
- utilty to assign it's resources and bring it online.
- PNPNC = Card is ISA Plug & Play compatible, but needs no configuration utility
- to enable Sound Blaster or Sound Blaster emulation
- SWEMU = Card is NOT Sound Blaster compatible, but comes with a DOS TSR that abuses
- EMM386.EXE and/or Virtual 8086 mode to emulate a Sound Blaster
- BIOS = Card is Sound Blaster compatible by emulation using motherboard audio,
- and can be enabled/disabled through the BIOS setup menu
- PCI = Card connects through PCI bus
- MORE = Card is Sound Blaster compatible and has additional functions that might
- be of interest
- NO = Card is NOT Sound Blaster compatible
-
- Finer details on every possible card I've tested is listed in the sndsb library
- source code.
-
-Creative Sound Blaster 1.5 (CT1320C) LIKELY
-Creative Sound Blaster 2.0 (CT1350) YES
-Creative Sound Blaster Pro (CT1330) LIKELY
-Creative Sound Blaster Pro 2 (CT16x0) LIKELY
-Creative Sound Blaster 16 LIKELY
-Creative Sound Blaster 16 ViBRA LIKELY
-Creative Sound Blaster 16 ViBRA PnP (CTL00F0) YES PNP
-Creative Sound Blaster 16 ViBRA PnP (CTL0070) YES PNP
-Creative Sound Blaster AWE64 PnP (CTL00C3) YES PNP MORE
-Creative Sound Blaster AWE64 Gold PnP (CTL00B2) YES PNP MORE
-Creative Sound Blaster Live! Value PCI LIKELY SWEMU
-Gallant SC-6000, Crystal Semiconductor CS4232 YES HWEMU
-VIA EPIA (????) [LOOK IT UP] YES BIOS HWEMU [*VIA EPIA]
-Yamaha OPL3-SAx YES HWEMU PNPNC [*1]
-Gravis Ultrasound MAX & SBOS 4.x YES SWEMU [*GUS]
-Gravis Ultrasound MAX & MEGA-EM YES SWEMU [*GUS]
-
-[*GUS] Gravis Ultrasound: The GUS basically pretends to be a Sound Blaster and other
- components by trapping certain I/O ports and reflecting to
- a TSR by NMI. Most often the ports overlap the GUS's.
- Emulation is terrible, especially MEGA-EM that only emulates
- a Sound Blaster 1.xx DSP and will literally hang the machine
- if you use any DSP command outside the supported set. DMA
- timing is terrible. Rather than a continuous stream as by
- Sound Blaster you see instead the DMA speed by and finish
- far before the audio finishes playing. If you're a DOS
- program depending on the DMA to match timing, you're
- not going to work too well. Also does not emulate auto-init.
-
-[*1] Yamaha OPL3-SAx: it is listed as PNPNC because the only one I have to test against
- is embedded on the motherboard of a laptop who's BIOS takes care
- of ISA PnP resource allocation. In fact the BIOS lists the sound
- card as one of the system nodes that can be enumerated using the
- PnP BIOS entry point.
-
-[*VIA EPIA] VIA EPIA: For whatever reason, despite the BIOS-supported emulation, I am
- unable to actually hear the sound output through the line out
- jack. The card seems to require a proprietary initialization
- procedure to enable the output. Other than that, DMA and IRQ
- activity suggests that it works fine.
-
-DSP VERSIONS
-------------
-
- - DSP 1.xx
-
- The code talks to the card in a manner compatible with the original Sound Blaster.
-
- - DSP 2.00
-
- Sound Blaster 2.0 compatible operation. In this version Creative added auto-init
- playback which means the software only needs to acknowledge the interrupt instead
- of reprogramming the DSP to start another block.
-
- - DSP 2.01
-
- Creative added the "high speed DAC" mode to enable playback up to 44100Hz mono
- (22050Hz stereo). On a real Sound Blaster 2.0 card I own, the DSP appears to have
- timing problems where in non-high speed mode any other use of the ISA bus can
- cause audible slowing down.
-
- - DSP 3.xx
-
- Sound Blaster Pro compatible output. Uses the mixer chip to enable stereo, which
- should also work on clone cards, but will remain monural on Sound Blaster 16 cards
- because Creative removed the control for some reason. Steroe playback on SB16 cards
- require DSP 4.xx playback mode.
-
- - DSP 4.xx
-
- Sound Blaster 16 compatible output. This enables 16-bit audio playback. Stereo
- playback on SB16 requires this mode, Pro stereo does not work. SB16 specific DSP
- commands also allow "flipped sign" playback.
-
- ADPCM playback only works with monural 8-bit audio. Direct DAC mode will only function
- properly with 8-bit monural audio.
-
-WARNINGS
---------
-
-Goldplay & Direct DAC modes:
- - These modes work by using the CPU and the IRQ 0 timer interrupt
- to play sound. If your machine is slow enough, the timer ISR
- can overwhelm the CPU and effectively make the UI unresponsive.
- This can happen for 16-bit builds on a slow enough configuration,
- but it is especially a problem with 32-bit builds due to the
- overhead involved with the 32-bit DOS extender.
-
- This program has a "watchdog timer" implemented into it's timer ISR
- to try and deal with timer overrun. In most cases if the ISR consumes
- all CPU the watchdog will time out, stop playing, and restore the
- tick rate to 18.2/sec so that the UI becomes usable again and you can
- safely stop playback and/or exit to DOS. But it is not 100% perfect,
- and what can happen instead is that the Sound Blaster ISR can get
- triggered in an infinite loop by a General Protection Fault (IRQ 5
- and the GP# fault overlap thanks to politics between Intel and IBM),
- or the DOS extender can crash to DOS with an error message about
- overrunning the stack (with the timer and keyboard unresponsive!).
-
- When you enable Direct DAC or Goldplay mode in the 32-bit version,
- a warning message will remind you (once) of this potential pitfall,
- and allow you to cancel the selection.
-
- The final warning is that this method should never be used in an
- environment where everything is totally virtualized, especially from
- within a Windows DOS box. Windows 95/98 have problems as it is dealing
- with DOS games that reprogram the timer beyond 100Hz.
-
- Remember, if you play with Direct DAC mode or Goldplay mode, and the
- program hangs or crashes, don't blame me---you were warned!
-
- NOTES: Sun/Oracle virtualbox. Does not work, produces low frequency
- "warble". Also seems to cap the timer rate at about 4KHz, no
- matter what rate this program is trying to run at.
-
- NOTES: DOSBox 0.74. Does not work, produces low frequency "warble"
- though timer rate is correct. If you must hear Goldplay mode
- in action use the dosbox-x "branch" source code I posted in
- the Vogons forums, which contains a fix to make Goldplay mode
- work correctly in DOSBox (as well as allow many older demos
- to play music audibly).
-
- NOTES: Direct DAC mode also affects recording. The same ISR timer
- technique is used to issue DSP command 0x20 (Direct ADC input)
- and then read the result from the DSP. Experience says this
- technique maxes out at 11KHz, if overdriven the ISR might
- overrun the stack and crash.
-
-Goldplay mode, an explanation:
-
- In the demoscene from about 1991 to 1993 there was a short-lived
- audio/tracker library called Goldplay that supported Sound Blaster
- and Sound Blaster Pro in addition to Covox, Disney sound source
- and other legacy one-sample-at-a-time sound output methods. The
- libary was written to hook the timer interrupt and reprogram the
- timer to run at the sample rate needed to play audio, then write
- one sample from the interrupt.
-
- The obvious problem the programmer(s?) faced was that the code was
- written for audio output methods that needed the CPU to write to them
- at a constant rate, because the devices themselves had no way to pull
- in audio by themselves. So naturally the timer interrupt was a way
- to accomplish that. But then what do you do about the Sound Blaster,
- which uses DMA and for stereo output does not offer a way to manually
- write audio samples?
-
- Many demos at the time opted for the method of programming the timer
- ISR to twice the sample rate, then alternately writing DSP command 0x10
- and the audio sample to play. But DSP command 0x10 cannot run faster than
- 22050Hz, and cannot play stereo.
-
- Goldplay programmers apparently decided to support Sound Blaster then
- using a simple hack. The library tells the DSP the block size is 65535
- samples, then tells the DMA controller the buffer is 1 sample wide!
- This means that during playback the DMA controller is transmitting the
- same sample over the ISA bus. Then, from the timer ISR, the library
- just overwrites that one byte with the latest sample to transmit. The DMA
- controller sends the new byte next cycle, and the DSP gets "sound".
-
- The obvious problem of course is that the timer is very likely not running
- at the same rate as the DSP, and this trick usually results in slightly
- scratchy sound as a result of samples getting duplicated or dropped.
-
- Such a trick was possible, because systems at the time did not cache CPU
- I/O (286s), or did cache CPU I/O but had logic to keep the cache coherent
- between the DMA controller and the CPU (386, 486, Pentium motherboards).
- On today's hardware the PCI bus logic and CPU memory controller would
- have a lot of difficulty pulling a stunt like that, which is why you don't
- really see that kind of trickery anymore.
-
- For testing purposes, the test program emulates that hacked method of
- playback just to see if it's possible. So far, testing shows that it is,
- even in configurations the Goldplay library would have never used (such
- as "Goldplay mode" with 16-bit stereo PCM).
-
- NOTE: Even though the Goldplay library never recorded audio, this program
- can also be used to test whether one can record audio from the DSP
- in this manner. Apparently it's possible, on real hardware! Switch
- on Goldplay mode and then select "record" to see in action.
-
-ADPCM auto-init:
-
- On actual Creative hardware there are DSP commands to play sound data
- compressed using Creative's proprietary ADPCM compression method.
- On Sound Blaster 2.0 and higher DSPs, there are additional commands to
- play the data in an auto-init fashion. Most clones and emulators know
- the original ADPCM commands, but generally do not respond to the
- auto-init versions. If you enable auto-init ADPCM and playback causes
- nothing to happen, then your card/emulator does not recognize it.
-
- DOSBox 0.74: Supports and decodes ADPCM, does not recognize
- auto-init ADPCM
- VirtualBox: Does not support ADPCM at all
- Virtual PC: Does not support ADPCM at all
- Yamaha OPL3-SAx: Supports 4-bit ADPCM, cycles DMA for 2.6/2-bit silently,
- does not recognize auto-init ADPCM
-
-ADPCM reset step per IRQ:
-
- DOSBox 0.74 emulates Sound Blaster ADPCM playback perfectly, except for
- one difference observed on genuine Creative hardware: Once per IRQ, even
- in auto-init mode, the DSP resets the step value, while DOSBox does not.
- A program that is unaware of the reset will produce audio that generally
- sounds OK but can audibly "flutter" depending on how often the IRQ
- occurs. This fluttering effect is caused by the ADPCM data compressed
- with one step size, and the SB decoding with the wrong step size, until
- ADPCM limits knock them back into sync.
-
- So when Creative documents the DSP commands as having a "reference byte"
- version and a version that "decodes using accumulated reference byte"
- consider they only mention the reference byte for good reason: the DSP
- does not preserve any other ADPCM state. Probably to make decoding from
- an arbitrary point in VOC files more predictable, I suppose.
-
- You can test for proper behavior by loading an 8-bit monural WAV file,
- setting the audio to 2.6 or 2 bit ADPCM, and playing it. On real hardware,
- it should sound fine, while in DOSBox, it should audibly flutter like
- a badly tuned FM radio. Switching off ADPCM reset per block should
- cause the opposite: DOSBox sounds fine, while on real Creative hardware
- it should audibly flutter.
-
- NOTE: The code has been tweaked to produce the best ADPCM output by ear
- on real SB16 hardware. Creative's ADPCM compression overall though
- is crap, so in the end it's difficult to tell whether the flutter
- happens because of errors in my code or because resetting the
- step size leaves little to no room to properly encode the waveform
- at the reset point. All I know is that the reset values in my code
- seem to produce the least amount of audible flutter, even though
- nothing I can do eliminates it completely.
-
- One way to eliminate flutter is to change the IRQ interval to
- the large setting, so that the DSP plays a larger amount of data
- before resetting at the next block.
-
-Sound Blaster Pro stereo:
-
- When Creative first implemented stereo in the Pro cards, they added a bit
- to a mixer register that enables/disables it. The program sends a time
- constant representing twice the sample rate, then flips on stereo, and...
- stereo playback happens.
-
- Most clone cards made afterwards emulate this bit quite well, even the
- cards that implement SB16 commands such as the Gallant SC-6000 chipsets.
-
- But Creative for some reason removed that function on the Sound Blaster 16
- cards and designed them instead to require the DSP 4.xx 0xBx-0xCx DSP
- commands to play back in stereo. The result is that DOS programs written
- around the Pro and it's stereo bit produce scratchy monural audio on the
- SB16, while ironically producing correct stereo output on clone cards!
-
- In this program, DSP mode 3.xx attempts to play stereo using DSP 3.x
- commands and the stereo bit, while DSP 4.xx uses the SB16 command set
- and does not set the stereo bit. If you have DSP 3.xx mode set and stereo
- audio sounds funny, then you have true Creative SB16 hardware and you
- need to reconfigure to DSP 4.xx mode.
-
-ISA Plug & Play compatibility:
-
- If your SB16 is the ISA PnP variety, it will be automatically detected.
- However if neither the BIOS nor any DOS utilities have assigned resources,
- this program will not be able to make use of the card.
-
- To resolve the issue, try:
-
- - Using the PNPCFG program provided to assign resources.
- - Use DOS utilities provided by the manufacturer to assign resources.
- Creative for example offers a DOS utility to test and assign resources
- to their Sound Blaster cards (both PnP and legacy versions)
- - If your BIOS offers the option, see if the setup menu offers ISA
- PnP resource assignment. Some BIOSes will automatically (try) to
- assign resources. One BIOS I test against likes to assign my SB16
- ViBRAX/V to IRQ 2 and DMA channel 0!
-
- ISA PnP compatability verified with:
- Sound Blaster 16 ViBRAC
- Sound Blaster 16 ViBRAX/V
- Sound Blaster AWE 32
- Sound Blaster AWE 64 Gold
- Microsoft Virtual PC Sound Blaster 16 emulation
-
- Some cards, for whatever reason, do not appear to have working 16-bit DMA
- transfer capability. Attempting to play 16-bit audio when the 16-bit DMA
- channel is 5, 6, or 7 will result in nothing at all. If that happens, try
- assigning both 8- and 16-bit DMA channels to DMA 0, 1, or 3.
-
-Non-ISA Plug & Play card software configuration:
-
- Some SB16 cards (or clones) are not ISA Plug & Play compatible, but do
- have some proprietary method of configuring DMA and IRQ resources. For
- these cards the PNPCFG utility will not work. You will instead need to
- identify the card, and then run the appropriate tool to initialize them:
-
- Sound Blaster 16 (non PnP)
- - Run the TEST program. Select the card. Note that if it has not been
- assigned resources the DMA and IRQ fields will read -1. Go to the
- device menu, and select Configure card. The program should indicate
- you are using a non-PnP SB16 and should offer options to configure
- IRQ and DMA channel settings. When you are finished, hit ENTER.
-
- NOTE: IRQ and DMA settings are changeable, while the base I/O address
- is NOT changeable. This method will also NOT work with PnP
- versions of Sound Blaster 16 hardware, nor will it work within
- Microsoft Virtual PC 2007 (emulated PnP SB16).
-
- NOTE: This is the recommended way to reconfigure Sound Blaster 16
- support in DOSBox, VirtualBox, and Bochs emulators as they
- emulate Sound Blaster 16 functions but without ISA PnP.
-
- Gallant SC6600/Crystal CS4321 "SC-4000" cards
- - Uses a jumper to configure the base I/O address, but all other
- resources are assigned by non-standard DSP commands. The card
- emulates a weird hybrid of Sound Blaster functions: a Pro-style mixer
- and a DSP that reports itself as a Pro (v3.5) yet it also supports
- SB16 DSP commands and 16-bit playback. The card also maps the CS4321
- crystal codec to a configurable WSS address (usually 530h).
-
- Run the TEST program. Select the card. Note that if it has not been
- assigned resources the DMA and IRQ fields will read -1. Go to the
- device menu, and select Configure card. The program should indicate
- you are using a SC-6000 card and offer options to change IRQ, DMA,
- and WSS I/O port resources. When you are finished, hit ENTER.
-
-PCI motherboard issues:
-
- Some motherboards block or only allow certain IRQ and DMA channels to
- work across the PCI-ISA bridge. Normally the IRQs blocked are IRQ 9, 10,
- 11, 13, 14, and 15 depending on whether your BIOS has assigned them to
- motherboard resources or PCI peripheral devices, while IRQ 3, 4, 5, 6,
- and 7 are normally left open. BIOSes that assign IRQs to either PCI or
- ISA normally allow you to change the assignment manually in the setup
- menu.
-
-The 32-bit protected mode version has SB IRQ problems when configured to IRQ 8, 9, 10, etc...
-
- On some 486/Pentium boards and ViBRA SB16 cards there seem to be
- some horrible reliability problems between the BIOS, the DOS extender, and
- the upper IRQs. The IRQ may work the first few times but after that nothing
- fires and the Sound Blaster DSP stops playback waiting around for our ISR
- to return acknowledgement.
-
- UPDATE: Independent testing reveals that it is a problem with the DOS4/GW
- DOS extender. The issue mentioned above is reproducible on a lot
- of other hardware such as a Dell Pentium III test machine.
-
- There are several ways to handle this:
- - Stop using DOS4/GW and run the program using open source DOS extender
- DOS32a, which doesn't seem to have this problem.
- - Use the 16-bit real mode versions. On the same systems they do not
- appear to have any problems.
- - Use a PNP configuration utility to move the IRQ down to 5, 7, etc.
-
-16-bit real mode large model hack, the SB IRQ indicator:
-
- For reasons beyond my comprehension, the 16-bit large model builds had
- a mysterious bug where half the time the subroutine would fail to redraw
- the IRQ indicator. This was visible on screen as erratic jumpy movement
- of the 'x' in the indicator. At one point, this indicator was responsible
- for several severe memory corruption issues that would eventually crash
- the machine!
-
- So, the 16-bit large model version redraws it instead from the main loop.
- This means though that if the main loop is unable to function, the IRQ
- indicator will not function and will be unable to show you if the DSP
- is still signalling interrupts.
-
- 16-bit real mode small model, and 32-bit protected mode builds, are
- able to retain redrawing the indicator from the Sound Blaster ISR. Even
- if the main UI hangs, you will still be able to see IRQ activity in the
- upper left corner of your screen.
-
-Flip sign mode:
-
- In the DOS/Windows world there are two de-facto "standard" PCM formats
- widely used. One is 8-bit unsigned PCM, using byte values 0 to 255 (with
- 128 at center) to represent the waveform. The other is 16-bit signed PCM,
- with -32768 to 32767 (with 0 at center). The SB16 DSP commands 0xBx-0xCx
- have bitfields to indicate 16-bit playback, as well as whether the audio
- data is signed or unsigned. In most cases, it is told to play either
- unsigned 8-bit or signed 16-bit data, and clone cards support that command
- as well. What clones and emulators get wrong though, are situations where
- the DOS program instead instructs the DSP to play signed 8-bit PCM, or
- unsigned 16-bit PCM.
-
- Note that the same DSP command is used for playback and recording.
-
- When enabled, the program will flip the sign bit before sending to the
- card, and then tell the SB16 DSP that it is the opposite signed/unsigned
- mode. If your card fully supports the DSP commands, it should make no
- audible change in the sound. If your card is a clone or an emulator that
- is not aware of the bits, you will hear loud static.
-
- DOSBox 0.74: Fully supported
- Bochs: Not fully supported. Loud static.
- Gallant SC-6000 clone: Fully supported
-
-ESS 688 auto-init does not fire IRQ:
-
- ESS chipsets work perfectly fine with auto-init and single-cycle modes,
- EXCEPT that for whatever reason, the chipset does not fire the IRQ if
- playing or recording 16-bit PCM and using auto-init DSP mode.
-
- If designing a game to use this library, this may be something to keep
- in mind if you are considering having music playback or synthesis occur
- from an IRQ---you cannot rely on using the SB IRQ to do this on ESS
- chipsets.
-
-BUGS
-----
-
-1] Direct DAC and Goldplay modes (anything using the timer ISR to play)
- can overwhelm the CPU and effectively freeze the UI, forcing the user
- to push reset button.
-
- FIXED. Timer ISR has watchdog counter. When it hits zero, it forcibly
- stops playback and resets timer to 18.2/sec tick rate. The UI, if
- functional, will otherwise reset the watchdog and therefore allow the
- audio to keep playing. This way, if your CPU is too slow, the program
- will auto-recover within 5-10 seconds so that you can safely stop
- playback and/or exit the program.
-
-2] Audio playback occassionally skips 1-4 seconds forward. Audio recording
- occassionally repeats a 1-4 second section to disk.
-
- FIXED. The DMA counter readback code failed to consider the 8237 does
- not necessarily latch the value during reading, causing reads to
- occassionally give bad or incorrect readback values that confuse the
- DMA tracking logic and cause it to over-refill the buffer.
-
- The 8237 library has been updated to read the counter twice, and re-read
- until the value counts down as expected.
-
-3] The IRQ indicator would randomly draw or not draw in the 16-bit real mode
- large build. It would also cause random memory corruption that would
- eventually crash the computer.
-
- FIXED, and FIXED. Changing the method by which "SB-IRQ" was written
- fixed the memory corruption issue, though it doesn't explain the random
- corruption, and it still didn't fix the random updating problem. Instead,
- the code was written to have the main loop do the IRQ state update.
- 16-bit small model, and 32-bit flat mode builds retain the code to redraw
- IRQ state from within the ISR.
-
-4] On a Pentium motherboard (with Award bios dated 1995) having PCI, ISA slots
- and Pentium 133MHz MMX processor, the 32-bit build cannot reliably service
- Sound Blaster DSP interrupt if IRQ is assigned to IRQ 8 or higher.
- Playback will work for awhile, then stop. A raw dump of the mixer shows
- byte 0x82 set to 0x41 (which means the DSP is waiting for acknowledgement,
- and therefore the IRQ was not serviced). 16-bit builds are not affected
- by this bug.
-
- NOT FIXED. I noticed the problem is reproducible on a lot more than just
- that one motherboard, and testing reveals that it is a problem with the
- DOS4/GW DOS extender. You can resolve the issue by replacing the DOS
- extender with one that does not have this problem, such as DOS32a
- (http://www.sf.net/projects/dos32a).
-
-5] Goldplay record/playback mode doesn't work when EMM386.EXE is resident and
- active.
-
- FIXED. It turns out pointing DMA at the Sound Blaster context structure
- was a bad idea. It happens to work in non-EMM386.EXE situations because
- the struct usually ended up below 16MB. But EMM386.EXE does not virtualize
- locations above 1MB, so DMA was effectively playing some unrelated data.
- Goldplay mode now allocates a separate (16-byte long) DMA buffer.
-
-6] Selecting "Device" -> "Trigger IRQ" when playing or selecting 16-bit audio
- causes computer to lock up. 32-bit builds trigger a crash dump in DOS32a
- and DOS4G/W.
-
- FIXED. The Sound Blaster DSP expects one form of acknowledgement for 8-bit
- I/O, and another form for 16-bit I/O. The code used the 8-bit version at
- all times. If that is done, the Sound Blaster DSP re-fires the IRQ
- expecting the ISR to take care of 16-bit I/O. Since the program never does,
- the IRQ re-fires until the stack overflows and the program crashes.
-
-7] Audio plays twice as fast or skips every other second when playing audio
- on Gravis Ultrasound SBOS/MEGA-EM installations.
-
- SBOS compatibility:
- FIXED [16-bit real mode small model].
-
- FIXED??? [16-bit real mode large model]. At least it seemed to fix
- itself, or at least stopped skipping ahead with noise every time the
- DMA pointer crossed the end of the buffer. Perhaps the phase of the moon
- changed during testing, who the fuck knows? >:[
-
- FIXED, sort of [32-bit protected mode]. The test program now hooks the
- NMI interrupt from protected mode so it can reflect it back to real
- mode. However, the NMI handler doesn't seem to be able to trigger the
- SB IRQ in protected mode, so playback will stall after playing a short
- piece of the audio.
-
- The above NMI hack will work with DOS4/GW and DOS32a. However if
- EMM386.EXE is resident and active, DOS4/GW will hard crash and reboot
- the system upon receipt of an NMI interrupt. If your program needs
- EMM386.EXE to be active, consider using DOS32a instead.
-
- If EMM386.EXE is not active, and the test program does not hook the
- NMI, DOS4/GW simply does not reflect the interrupt and the program
- will not reliably detect the virtual sound card.
-
- MEGA-EM compatibility:
- FIXED [16-bit real mode small model].
-
- NOT FIXED [16-bit real mode large model]. Despite extremely careful
- DMA controller programming, running this program seems to invoke
- EMM386.EXE's panic screen complaining about the program attemping
- to do a 64KB DMA transfer (WHAT?!). Adding D=64 to the EMM386.EXE
- device line in your CONFIG.SYS seems to resolve the issue.
-
- NOT FIXED [32-bit protected mode]. NMI interrupt causes DOS extenders to
- panic. Hooking the NMI interrupt from protected mode to reflect back to
- real mode doesn't resolve DOS4G/W causing a hard reset on NMI, but
- when run under DOS32a the NMI emulation magic apparently fails to work,
- and the test program fails to see the emulated sound card.
-
- While effort has been made to support SBOS and MEGA-EM emulation, I
- consider full compatibility a low priority. I have no patience for
- twitchy TSRs that have stability issues, shitty Sound Blaster emulation,
- and bizarre DMA bugs.
-
-8] When playing audio through SBOS, switching to ADPCM mode causes the
- program to hang and crash.
-
- NOT FIXED. I have no patience with SBOS and I do not forsee any need
- to use ADPCM mode with it.
-
- If you must use ADPCM playback with the Ultrasound, use MEGA-EM, which
- at least does a reasonable job faking the ADPCM playback without causing
- a hard crash.
-
-9] When playing ADPCM audio with MEGA-EM, the audio sounds buzzy and
- distorted, or tinny and quiet like static.
-
- NOT FIXED. MEGA-EM attempts to fake ADPCM playback, but the programmers
- obviously had no documentation on what exactly the ADPCM format did
- (back then, who did?).
-
-Gravis SBOS bugs this code has to deal with:
-
- - The people who wrote SBOS evidently failed to take into
- consideration the interpolation used by the GF1 chip,
- thus there are audible pops and buzzing at the boundaries
- of DSP blocks not because of any errors but because of
- the GF1 interpolating into undefined samples
-
- - SBOS's use of INT 02h (NMI) causes DOS4/GW to hard reset
- and DOS32a to crash to the DOS prompt with an exception
- report. You can avoid the hard crash with DOS32a at least
- by hooking INT 02h from protected mode to reflect to real
- mode, but the NMI handler doesn't seem to be able to issue
- the SB IRQ back into your protected mode program
-
- - I also noticed their NMI handler occasionally seems to not
- carry out the DMA transfer at all. Instead it does the transfer
- within the NMI handler. For programs that rely on the DMA pointer
- to advance audio this is bad news, and something to watch for.
-
-DSP alias port
---------------
-
-A long time ago I stumbled upon an old demo written by the Eletromotive
-force (EMF_ID.ZIP) that I thought was interesting, but could never get
-the Sound Blaster mode working. Every time I tried, the demo hung after
-prompting for Sound Blaster setup.
-
-It wasn't until I ran it in DOSBox that I eventually figured out what
-was wrong: the demo relied on using the ALIAS of the DSP port, meaning
-that it read status from and wrote DSP commands to port 0x22D instead
-of 0x22C. I immediately plugged in an old Sound Blaster (DSP 2.0) and
-confirmed that all I/O ports do in fact appear on both the original
-and the alias ports, as if the card only decodes 4 bits and pays attention
-to the top 3 while ignoring the LSB.
-
-If you have an old Sound Blaster card, you might enable DSP alias port
-mode to instruct the library to use port 0x22D to see if it actually
-works. If it works, you have an original Sound Blaster that aliases
-it's I/O ports.
-
-List of cards and whether or not ports alias:
----------------------------------------------
-Sound Blaster (DSP 1.x) PROBABLY
-Sound Blaster (DSP 2.01) YES
-Sound Blaster Pro (DSP 3.x) PROBABLY NOT
-Sound Blaster 16 (DSP 4.x) NO
-ESS Plug and Play AudioDrive YES (DSP PORTS ONLY)
-
-Backwards mode
---------------
-
-Besides the EMF_ID fix mentioned above (in DSP alias port), the demo
-also appears to use DMA decrement mode. What that means is that, instead
-of pointing the DMA controller at the first byte and rendering audio
-forwards, it instead points the DMA controller at the last byte and
-renders audio backwards, then tells the DMA controller to decrement
-the address after every byte (instead of incrementing) so that the
-backwards audio is played forwards.
-
-If you want to play files backwards or want to test whether your
-motherboard supports DMA decrement mode, you can go into the
-"parameters" page and set "direction" to "backwards". if you hear
-the audio perfectly in reverse, then your motherboard supports the
-"decrement" bit of the DMA controller's mode register.
-
-I consider it an additional test of robustness if you set both DMA
-and the DSP into single-cycle non-auto-init mode and playback does not
-exhibit any glitches.
-
-WARNING: Backwards mode should be used with 8-bit PCM only! 16-bit PCM
- backwards playback is NOT RECOMMENDED, especially if your
- sound card is configured to use an 8-bit DMA channel to carry
- it (byte order is backwards and LOUD STATIC will result!).
-
- If you are using a 16-bit DMA channel, then theoretically it
- MIGHT work, but there are no guarantees. To consider why it
- might work, think about how the DMA controller uses the low
- 15 bits to determine the memory address, then imagine how
- the DMA controller loads 16 bits from memory (PROBABLY in
- the correct byte order!) and sends it to the sound card.
-
-* TODO, NOT YET IMPLEMENTED *
-
- - Recording in backwards mode (use backwards DMA to record, then write
- data FORWARDS to the WAV file)
- - ADPCM playback with DMA backwards mode (compress to ADPCM backwards,
- then write compressed ADPCM backwards!)
-
-What is "nagging the DSP?
--------------------------
-
-I recently patched up DOSBox-X to support the Triton "Crystal Dream" demo's
-Sound Blaster support. In the process of doing so, I learned a few funny
-things about both DOSBox source code and the Sound Blaster.
-
-First, the Crystal Dream demo uses the Goldplay technique, where the
-Sound Blaster is told the DSP block size is 65536 bytes, but the ISA DMA
-controller is put into auto-init mode and told the DMA transfer length
-is 1 byte (2 bytes if stereo). But what Crystal Dream does beyond that
-is interesting in it's own right.
-
-First of all, my initial assumption that the demo was hooking the wrong
-IRQ was wrong. I looked at the interrupt vector table while it was running
-and I saw that it hooked IRQ 0, and IRQ 1, but didn't hook any other
-interrupts. Which means that, when the Sound Blaster signals an IRQ,
-the demo doesn't respond to that IRQ at all.
-
-At the same time, the demo uses the single-cycle DSP playback commands,
-which means that at some point, the DSP will finish the block and the
-demo needs to start another one to keep playing. So how does it keep
-the audio going this way despite no IRQ handler?
-
-It turns out, digging into the IRQ 0 hook it sets up, the demo starts
-audio by sending DSP command 0x14 at the start. Then, the IRQ 0 handler
-not only renders music but also polls the DSP write status port 0x22C.
-If the DSP reports itself busy, the demo resets a counter, else when
-the DSP is not busy, it decrements the counter. When the counter gets
-low enough, the demo uses the IRQ 0 interrupt to send another DSP
-command block (0x14,xx,xx). The fact that the Sound Blaster has not
-yet finished playing the last block at this point is irrelevent.
-So, about 10-20 times a second, the demo is constantly interrupting
-DSP playback to start DSP playback, and the audio keeps going.
-
-Now on actual hardware apparently, this works perfectly fine. In fact,
-the advantage of the technique is that it allows audio without any
-small pops or crackles normally associated with the CPU and interrupt
-system taking too long to start another block, even on the original
-Sound Blaster. The other advantage is that, by doing it all from IRQ
-0 and effectively interrupting the DSP constantly the DSP never fires
-the IRQ normally associated with completing a block, so the demo never
-has to concern itself with IRQ detection logic (never mind it assumes
-DMA channel 1). When I coded support code for this in DOSBox's emulation,
-I coined it "nagging the DSP", because the demo is constantly nagging
-the DSP to keep playing in a rude manner (but it works!)
-
-To test this case, the sndsb library and test program allow you to
-enable that mode to see how well your Sound Blaster handles that kind
-of playback. To actually trigger the behavior, you will need to enable
-DSP nag mode, and switch DSP playback into single-cycle mode (where
-by default it is in autoinit mode).
-
-DSP auto-init vs DMA auto-init
-------------------------------
-
-Despite similar sounding names the two options control entirely different
-things. DMA auto-init concerns itself with the auto-init bit on the ISA
-DMA controller, which if set, causes the DMA controller to automatically
-restart a DMA block when it reaches the end.
-
-DSP auto-init concerns which set of DSP commands are used to start playback.
-The Sound Blaster family has two sets: single cycle, and auto-init.
-
-Single-cycle commands play a block of audio, then fire an IRQ and stop.
-Continuing playback requires the CPU to send another command to start
-playback again.
-
-Auto-init commands are usually only sent once. Once the command is sent,
-the DSP keeps playing (sending an IRQ every so many bytes) until it is told
-to stop. This is the recommended way to play audio on Sound Blaster hardware,
-although the original Sound Blaster does not support auto-init DSP modes,
-and many clones and emulations do not handle it well either.
-
-Sound Blaster 16 auto-init/FIFO modes
--------------------------------------
-
-Sound Blaster 16 cards (DSP 4.xx) support a new set of commands that
-includes bits to specify whether the DSP plays the audio as single-cycle
-or auto-init, as well as whether or not it will enable the FIFO.
-Under normal circumstances, you would not use the FIFO for single-cycle
-and use the FIFO in auto-init. The option is given to you however to see
-what happens if you, say, switch off the FIFO in auto-init, or enable
-the FIFO in single-cycle.
-
-Note that clones implementing SB16 DSP commands support only the most
-common commands and do not support the uncommon combinations mentioned
-above. SC-6000 cards for example support FIFO & auto-init but do not
-support single-cycle or non-FIFO auto-init forms of the command.
-
-Most clones do not emulate the SB16 anyway, even those produced in the
-late years (1996-1999) of the ISA bus and DOS support.
-
-If you're wondering by the way what happens, single-cycle DSP playback
-with the FIFO enabled tends to miss some samples. The DSP acts as if
-it completes the block early with data still in the FIFO, and then
-forgets the contents of the FIFO. Auto-init without FIFO apparently
-has no effect, but I would bet that if the ISA bus was busy with
-another device the lack of FIFO might cause some audible effects.
-
-ESS 688, changing the IRQ and PnP BIOS conflicts
-------------------------------------------------
-
-If you change the IRQ from this test program, understand that if the
-ESS chipset is listed by the PnP BIOS, the original IRQ (now wrong)
-will be used from the PnP BIOS enumeration and IRQ will appear not
-to work. To avoid this, run the test program with /nopnp every time
-after changing the IRQ.
-
-ESS chipsets and the ESS control register raw mode
---------------------------------------------------
-
-For debugging purposes, the program allows you to poke at the ESS
-registers as raw byte values. Understand that doing this may cause
-temporary issues with the hardware or cause problems and hangs with
-the software. Poke at the registers at your own risk.
-
-By default, only registers 0xA0-0xB9 are shown for ESS 688 chipsets.
-Registers 0x00-0x9F do not exist, and on ESS 688 chipsets, the DSP
-will not return any data for registers 0xBA-0xBF so they are blocked
-off. If you want to make sure that the registers exist, type 'p' to
-trigger a re-detection cycle. Know that for undefined registers, the
-program may hang temporarily waiting for DSP timeouts.
-
-ESS 688 undocumented registers
-------------------------------
-
-Perhaps this is simply lack of documentation in the ES1869 datasheet,
-but there are additional registers not listed.
-
-0xA0 Unknown (only 4 bits are changeable)
-0xA3 Unknown (all 8 bits changeable)
-0xA6 Left (master? PCM?) volume
-0xA7 Right (master? PCM?) volume
-0xA8 Unknown (but bit 0 appears to enable/disable audio output)
-0xA9 Unknown (all 8 bits changeable)
-0xAA Master volume? (also changed when you write 0xAB)
-0xAB Master volume? (writing this also changes 0xAA)
-0xAC Unknown (all 8 bits changeable)
-0xAD Unknown (all 8 bits changeable)
-0xAE Unknown (all 8 bits changeable)
-0xAF Unknown (all 8 bits changeable)
-
-0xB0 Unknown (always reads 0xB0, writes change register 0xA0 instead)
-0xB3 Unknown (only bit 0 is changeable)
-
-ESS 1869 undocumented registers (as seen on a Compaq branded ESS 1887)
-----------------------------------------------------------------------
-
-0xA0 Unknown (only 2:0 bits are changeable)
-0xA3 Unknown (all 8 bits changeable)
-0xA6 Zero (not changeable)
-0xA7 Zero (not changeable)
-0xA8 This actually is documented, but some weird behavior observed
- with bits 1:0. In the datasheet, bit 0 is a mono/stereo
- select. Actual behavior with 1:0:
-
- 00 = only one audio channel played
- 01 = normal stereo playback
- 02 = chip output is difference between L-R rather than sum.
- perhaps a good way to hear the Dobly "surround" channel of movie audio,
- or to filter out the vocals of most music, or to hear just how destructive
- your MP3 encoder is to audio you "can't hear".
- 03 = normal stereo playback
-0xA9 Unknown, bits 6:4 and 2:0 are writable, bits 3 and 7 have a mind of their own
-0xAA-0xAF Zero (not changeable)
-0xB0 Unknown (always reads 0xB0, writes change register 0xA0 instead)
-0xB3 Unknown (only bit 0 is changeable)
-
-ESS sample & filter clock divider behavior
-------------------------------------------
-
-This isn't mentioned in ESS's datasheets, but if you set the sample rate
-divider to 0xFF (or 0x7F) the DAC stops (does not cycle samples) and will
-stay that way until you enter another divider. It doesn't appear to harm
-the chip in any way.
-
-Note that 0x00 is also a valid clock divider (in which case the DAC just
-plays the audio really slow).
-
-The divider for their lowpass filter appears to have the same behavior.
-Setting the divider to 0x00 turns the audio into a very low bandwidth
-signal (as you'd expect) while 0xFF silences output entirely.
-
+++ /dev/null
-/* FIXME: This code is failing to detect that it's running under the latest (4.3) VirtualBox. Why? */
-
-/* TODO: Add a flag to the sound blaster context to track whether or not DSP playback/record is active. */
-
-/* TODO: How to add support for full duplex audio? ESS 688 and 1869 chipsets for example can do full
- * duplex but only at the same sample rate. I'm not sure if Sound Blaster 16 ViBRA cards can
- * do full duplex. */
-
-/* FIXME: This just in: your IRQ testing routine can hang the system especially (as in DOSBox) when IRQs that are
- * normally masked have a corresponding interrupt vector set to NULL (0000:0000). You need to double-check
- * the probe function and make sure there is no possible way uninitialized vectors execute when any
- * particular IRQ is fired. */
-
-/* FIXME: On a laptop with ESS 688 playing 16-bit PCM with auto-init DSP and auto-init DMA, the IRQ does not
- * fire periodically as it should. Any other mode (auto-init DMA with single-cycle DMA, or any of the
- * 8-bit modes) fires the IRQ periodically as in auto-init. This is important for anyone who might try
- * to use this library to play music entirely from the interrupt. */
-
-/* FIXME: There might be a way to deal with some troubles you've been having with this code:
- *
- * Troubles:
- * - Gravis SBOS/MEGA-EM NMI causes DOS4GW.EXE to hard-reset the machine rather than deal with it
- * - Even when your code caught the NMI and forwarded it to Gravis's TSRs, Sound Blaster emulation
- * failed to signal your interrupt handler, which is probably why 16-bit real mode builds worked
- * fine with SBOS/MEGA-EM while 32-bit builds did not.
- * - Under DOS4GW.EXE (but not DOS32A.EXE) using IRQ 8-15 eventually resulted in missing an IRQ.
- * I initially panned it as DOS4GW.EXE being a cheap son-of-a-bitch but it might be related instead
- * to a combination of the BIOS forwarding interrupts in real mode, and the lack of a real-mode
- * interrupt handler for the Sound Blaster library.
- *
- * Things to do:
- * - Add code to set the interrupt vector for the IRQ on behalf of the calling program. The calling
- * program provides a function to call, and you set the vector (and keep track of the previous one).
- * - Also add function to remove interrupt vector. Write the code so that if someone else hooked,
- * the unhook function returns an error.
- * - Add code to interrupt vector hooking code so that in 32-bit builds, if MEGA-EM or SBOS is resident
- * or DOS4GW.EXE is resident and IRQ 8-15 is to be used, this code automatically installs a real-mode
- * interrupt vector that reflects the interrupt into protected mode.
- * - Add code so that, in 32-bit builds, if MEGA-EM or SBOS is resident, the library hooks the NMI
- * interrupt in protected mode and reflects it to real-mode so Gravis's emulation can work. [FIXME
- * can you also resolve DOS4GW.EXE hard-crashing in this situation?] */
-
-/* Primary Sound Blaster support library.
- * This compiles into sndsb.lib.
- * This DOES NOT include support for Plug & Play versions,
- * functions for that are in sndsbpnp.c -> sndsbpnp.lib */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/dos/dosbox.h>
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/sndsb/sndsb.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/tgusmega.h>
-#include <hw/dos/tgussbos.h>
-
-/* Windows 9x VxD enumeration */
-#include <windows/w9xvmm/vxd_enum.h>
-
-/* uncomment this to enable debugging messages */
-//#define DBG
-
-#if defined(DBG)
-# define DEBUG(x) (x)
-#else
-# define DEBUG(x)
-#endif
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-/* cut */
-#else
-static int adpcm_pred = 128;
-static signed char adpcm_last = 0;
-static unsigned char adpcm_step = 0;
-static unsigned char adpcm_error = 0;
-static unsigned char adpcm_lim = 0;
-#endif
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-/* cut */
-#else
-/* CT1335 */
-struct sndsb_mixer_control sndsb_mixer_ct1335[] = {
-/* index, of,ln,name */
- {0x02, 1, 3, "Master"},
- {0x06, 1, 3, "MIDI"},
- {0x08, 1, 3, "CD"},
- {0x0A, 1, 2, "Voice"}
-};
-
-/* CT1345 */
-struct sndsb_mixer_control sndsb_mixer_ct1345[] = {
-/* index, of,ln,name */
- {0x04, 1, 3, "Voice R"}, {0x04, 5, 3, "Voice L"},
- {0x0A, 1, 2, "Mic"},
- {0x0C, 1, 2, "Input source"}, {0x0C, 3, 1, "Lowpass filter"}, {0x0C, 5, 1, "Input filter"},
- {0x0E, 1, 1, "Stereo switch"}, {0x0E, 5, 1, "Output filter"},
- {0x22, 1, 3, "Master R"}, {0x22, 5, 3, "Master L"},
- {0x26, 1, 3, "MIDI R"}, {0x26, 5, 3, "MIDI L"},
- {0x28, 1, 3, "CD R"}, {0x28, 5, 3, "CD L"},
- {0x2E, 1, 3, "Line R"}, {0x2E, 5, 3, "Line L"}
-};
-
-/* CT1745 */
-struct sndsb_mixer_control sndsb_mixer_ct1745[] = {
-/* index, of,ln,name */
- {0x30, 3, 5, "Master L"}, {0x31, 3, 5, "Master R"},
- {0x32, 3, 5, "Volume L"}, {0x33, 3, 5, "Volume R"},
- {0x34, 3, 5, "MIDI L"}, {0x35, 3, 5, "MIDI R"},
- {0x36, 3, 5, "CD L"}, {0x37, 3, 5, "CD R"},
- {0x38, 3, 5, "Line L"}, {0x39, 3, 5, "Line R"},
- {0x3A, 3, 5, "Mic"},
- {0x3B, 6, 2, "PC speaker"},
-
- {0x3C, 0, 1, "Out mixer: mic"},
- {0x3C, 1, 1, "Out mixer: CD R"},
- {0x3C, 2, 1, "Out mixer: CD L"},
- {0x3C, 3, 1, "Out mixer: Line R"},
- {0x3C, 4, 1, "Out mixer: Line L"},
-
- {0x3D, 0, 1, "In mixer L: Mic"},
- {0x3D, 1, 1, "In mixer L: CD R"},
- {0x3D, 2, 1, "In mixer L: CD L"},
- {0x3D, 3, 1, "In mixer L: Line R"},
- {0x3D, 4, 1, "In mixer L: Line L"},
- {0x3D, 5, 1, "In mixer L: MIDI R"},
- {0x3D, 6, 1, "In mixer L: MIDI L"},
-
- {0x3E, 0, 1, "In mixer R: Mic"},
- {0x3E, 1, 1, "In mixer R: CD R"},
- {0x3E, 2, 1, "In mixer R: CD L"},
- {0x3E, 3, 1, "In mixer R: Line R"},
- {0x3E, 4, 1, "In mixer R: Line L"},
- {0x3E, 5, 1, "In mixer R: MIDI R"},
- {0x3E, 6, 1, "In mixer R: MIDI L"},
-
- {0x3F, 6, 2, "Input gain L"},
- {0x40, 6, 2, "Input gain R"},
- {0x41, 6, 2, "Output gain L"},
- {0x42, 6, 2, "Output gain R"},
- {0x43, 0, 1, "AGC"},
- {0x44, 4, 4, "Treble L"},
- {0x45, 4, 4, "Treble R"},
- {0x46, 4, 4, "Bass L"},
- {0x47, 4, 4, "Bass R"}
-};
-#endif
-
-signed char gallant_sc6600_map_to_dma[4] = {-1, 0, 1, 3};
-signed char gallant_sc6600_map_to_irq[8] = {-1, 7, 9,10,11, 5,-1,-1};
-
-const char* sndsb_adpcm_mode_str[4] = {
- "none",
- "ADPCM 4-bit",
- "ADPCM 2.6-bit",
- "ADPCM 2-bit"
-};
-
-const char *sndsb_mixer_chip_name[SNDSB_MIXER_MAX] = {
- "none",
- "CT1335",
- "CT1345",
- "CT1745"
-};
-
-const char *sndsb_dspoutmethod_str[SNDSB_DSPOUTMETHOD_MAX] = {
- "direct",
- "1.xx",
- "2.00",
- "2.01",
- "3.xx",
- "4.xx"
-};
-
-const char *sndsb_ess_chipsets_str[SNDSB_ESS_MAX] = {
- "none",
- "ESS688",
- "ESS1869"
-};
-
-#if TARGET_MSDOS == 32
-signed char sndsb_nmi_32_hook = -1;
-#endif
-
-struct sndsb_probe_opts sndsb_probe_options={0};
-struct sndsb_ctx sndsb_card[SNDSB_MAX_CARDS];
-struct sndsb_ctx *sndsb_card_blaster=NULL;
-int sndsb_card_next = 0;
-
-const char *sndsb_ess_chipset_str(unsigned int c) {
- if (c >= SNDSB_ESS_MAX) return NULL;
- return sndsb_ess_chipsets_str[c];
-}
-
-void sndsb_timer_tick_gen(struct sndsb_ctx *cx) {
- cx->timer_tick_signal = 1;
-}
-
-static inline void sndsb_timer_tick_directio_post_read(unsigned short port,unsigned short count) {
- while (count-- != 0) inp(port);
-}
-
-static inline unsigned char sndsb_timer_tick_directio_poll_ready(unsigned short port,unsigned short count) {
- unsigned char r = 0;
-
- do { r = inp(port);
- } while ((r&0x80) && count-- != 0);
-
- return !(r&0x80);
-}
-
-void sndsb_timer_tick_directi_data(struct sndsb_ctx *cx) {
- if (sndsb_timer_tick_directio_poll_ready(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_poll_retry_timeout)) {
- cx->buffer_lin[cx->direct_dsp_io] = inp(cx->baseio+SNDSB_BIO_DSP_READ_DATA);
- if (cx->backwards) {
- if (cx->direct_dsp_io == 0) cx->direct_dsp_io = cx->buffer_size - 1;
- else cx->direct_dsp_io--;
- }
- else {
- if ((++cx->direct_dsp_io) >= cx->buffer_size) cx->direct_dsp_io = 0;
- }
- cx->timer_tick_func = sndsb_timer_tick_directi_cmd;
- cx->direct_dac_sent_command = 0;
- sndsb_timer_tick_directio_post_read(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_read_after_command);
- }
-}
-
-void sndsb_timer_tick_directi_cmd(struct sndsb_ctx *cx) {
- if (sndsb_timer_tick_directio_poll_ready(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_poll_retry_timeout)) {
- outp(cx->baseio+SNDSB_BIO_DSP_WRITE_DATA+(cx->dsp_alias_port?1:0),0x20); /* direct DAC read */
- cx->timer_tick_func = sndsb_timer_tick_directi_data;
- cx->direct_dac_sent_command = 1;
- sndsb_timer_tick_directio_post_read(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_read_after_command);
- }
-}
-
-void sndsb_timer_tick_directo_data(struct sndsb_ctx *cx) {
- if (sndsb_timer_tick_directio_poll_ready(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_poll_retry_timeout)) {
- outp(cx->baseio+SNDSB_BIO_DSP_WRITE_DATA+(cx->dsp_alias_port?1:0),cx->buffer_lin[cx->direct_dsp_io]);
- if (cx->backwards) {
- if (cx->direct_dsp_io == 0) cx->direct_dsp_io = cx->buffer_size - 1;
- else cx->direct_dsp_io--;
- }
- else {
- if ((++cx->direct_dsp_io) >= cx->buffer_size) cx->direct_dsp_io = 0;
- }
- cx->timer_tick_func = sndsb_timer_tick_directo_cmd;
- cx->direct_dac_sent_command = 0;
- sndsb_timer_tick_directio_post_read(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_read_after_command);
- }
-}
-
-void sndsb_timer_tick_directo_cmd(struct sndsb_ctx *cx) {
- if (sndsb_timer_tick_directio_poll_ready(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_poll_retry_timeout)) {
- outp(cx->baseio+SNDSB_BIO_DSP_WRITE_DATA+(cx->dsp_alias_port?1:0),0x10); /* direct DAC write */
- cx->timer_tick_func = sndsb_timer_tick_directo_data;
- cx->direct_dac_sent_command = 1;
- sndsb_timer_tick_directio_post_read(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0),cx->dsp_direct_dac_read_after_command);
- }
-}
-
-void sndsb_timer_tick_goldi_cpy(struct sndsb_ctx *cx) {
- cx->timer_tick_signal = 1;
-#if TARGET_MSDOS == 32
- memcpy(cx->buffer_lin+cx->direct_dsp_io,cx->goldplay_dma->lin,cx->gold_memcpy);
-#else
- _fmemcpy(cx->buffer_lin+cx->direct_dsp_io,cx->goldplay_dma,cx->gold_memcpy);
-#endif
- if (cx->backwards) {
- if (cx->direct_dsp_io < cx->gold_memcpy) cx->direct_dsp_io = cx->buffer_size - cx->gold_memcpy;
- else cx->direct_dsp_io -= cx->gold_memcpy;
- }
- else {
- if ((cx->direct_dsp_io += cx->gold_memcpy) >= cx->buffer_size) cx->direct_dsp_io = 0;
- }
-}
-
-void sndsb_timer_tick_goldo_cpy(struct sndsb_ctx *cx) {
- cx->timer_tick_signal = 1;
-#if TARGET_MSDOS == 32
- memcpy(cx->goldplay_dma->lin,cx->buffer_lin+cx->direct_dsp_io,cx->gold_memcpy);
-#else
- _fmemcpy(cx->goldplay_dma,cx->buffer_lin+cx->direct_dsp_io,cx->gold_memcpy);
-#endif
- if (cx->backwards) {
- if (cx->direct_dsp_io < cx->gold_memcpy) cx->direct_dsp_io = cx->buffer_size - cx->gold_memcpy;
- else cx->direct_dsp_io -= cx->gold_memcpy;
- }
- else {
- if ((cx->direct_dsp_io += cx->gold_memcpy) >= cx->buffer_size) cx->direct_dsp_io = 0;
- }
-}
-
-struct sndsb_ctx *sndsb_by_base(uint16_t x) {
- int i;
-
- for (i=0;i < SNDSB_MAX_CARDS;i++) {
- if (sndsb_card[i].baseio == x)
- return sndsb_card+i;
- }
-
- return 0;
-}
-
-struct sndsb_ctx *sndsb_by_mpu(uint16_t x) {
- int i;
-
- for (i=0;i < SNDSB_MAX_CARDS;i++) {
- if (sndsb_card[i].mpuio == x)
- return sndsb_card+i;
- }
-
- return 0;
-}
-
-struct sndsb_ctx *sndsb_by_irq(int8_t x) {
- int i;
-
- for (i=0;i < SNDSB_MAX_CARDS;i++) {
- if (sndsb_card[i].irq == x)
- return sndsb_card+i;
- }
-
- return 0;
-}
-
-struct sndsb_ctx *sndsb_by_dma(uint16_t x) {
- int i;
-
- for (i=0;i < SNDSB_MAX_CARDS;i++) {
- if (sndsb_card[i].baseio > 0 && (sndsb_card[i].dma8 == x || sndsb_card[i].dma16 == x))
- return sndsb_card+i;
- }
-
- return 0;
-}
-
-#if TARGET_MSDOS == 32
-int sb_nmi_32_auto_choose_hook() {
- if (sndsb_nmi_32_hook >= 0)
- return sndsb_nmi_32_hook;
-
- /* auto-detect SBOS/MEGA-EM and enable nmi reflection if present */
- if (gravis_mega_em_detect(&megaem_info) || gravis_sbos_detect() >= 0)
- return 1;
-
- return 0;
-}
-#endif
-
-void free_sndsb() {
-#if TARGET_MSDOS == 32
- if (sndsb_nmi_32_hook) do_nmi_32_unhook();
-#endif
-}
-
-int init_sndsb() {
- int i;
-
- memset(sndsb_card,0,sizeof(sndsb_card));
- for (i=0;i < SNDSB_MAX_CARDS;i++)
- sndsb_card[i].pnp_bios_node = 0xFF;
-
- sndsb_card_blaster = NULL;
- sndsb_card_next = 0;
-#if TARGET_MSDOS == 32
- sndsb_nmi_32_hook = sb_nmi_32_auto_choose_hook();
- if (sndsb_nmi_32_hook) do_nmi_32_hook();
-#endif
- return 1;
-}
-
-struct sndsb_ctx *sndsb_alloc_card() {
- int i;
-
- for (i=0;i < SNDSB_MAX_CARDS;i++) {
- if (sndsb_card[i].baseio == 0 && sndsb_card[i].mpuio == 0)
- return sndsb_card+i;
- }
-
- return NULL;
-}
-
-void sndsb_free_card(struct sndsb_ctx *c) {
-#if TARGET_MSDOS == 32
- if (c->goldplay_dma) {
- dma_8237_free_buffer(c->goldplay_dma);
- c->goldplay_dma = NULL;
- }
-#endif
- memset(c,0,sizeof(*c));
- c->pnp_bios_node = 0xFF;
- if (c == sndsb_card_blaster) sndsb_card_blaster = NULL;
-}
-
-struct sndsb_ctx *sndsb_try_blaster_var() {
- int A=-1,I=-1,D=-1,H=-1,P=-1;
- struct sndsb_ctx *e;
- char *s;
-
- if (sndsb_card_blaster != NULL)
- return sndsb_card_blaster;
-
- /* some of our detection relies on knowing what OS we're running under */
- cpu_probe();
- probe_dos();
- detect_windows();
-
- s = getenv("BLASTER");
- if (s == NULL) return NULL;
-
- while (*s != 0) {
- if (*s == ' ') {
- s++;
- continue;
- }
-
- if (*s == 'A') {
- s++;
- A = strtol(s,&s,16);
- }
- else if (*s == 'P') {
- s++;
- P = strtol(s,&s,16);
- }
- else if (*s == 'I') {
- s++;
- I = strtol(s,&s,10);
- }
- else if (*s == 'D') {
- s++;
- D = strtol(s,&s,10);
- }
- else if (*s == 'H') {
- s++;
- H = strtol(s,&s,10);
- }
- else {
- while (*s && *s != ' ') s++;
- while (*s == ' ') s++;
- }
- }
-
- if (A < 0 || I < 0 || D < 0 || I > 15 || D > 7)
- return NULL;
-
- if (sndsb_by_base(A) != NULL)
- return 0;
-
- e = sndsb_alloc_card();
- if (e == NULL) return NULL;
-#if TARGET_MSDOS == 32
- e->goldplay_dma = NULL;
-#endif
- e->is_gallant_sc6600 = 0;
- e->baseio = (uint16_t)A;
- e->mpuio = (uint16_t)(P > 0 ? P : 0);
- e->dma8 = (int8_t)D;
- e->dma16 = (int8_t)H;
- e->irq = (int8_t)I;
- e->dsp_vmaj = 0;
- e->dsp_vmin = 0;
- e->mixer_ok = 0;
- e->mpu_ok = 0;
- e->dsp_ok = 0;
- return (sndsb_card_blaster=e);
-}
-
-const char *sndsb_mixer_chip_str(uint8_t c) {
- if (c >= SNDSB_MIXER_MAX) return NULL;
- return sndsb_mixer_chip_name[c];
-}
-
-/* NTS: this function enforces a timeout of 250ms */
-int sndsb_read_dsp(struct sndsb_ctx *cx) {
- unsigned int patience = 25000;
- int c = -1;
-
- do {
- if (inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS+(cx->dsp_alias_port?1:0)) & 0x80) { /* data available? */
- c = inp(cx->baseio+SNDSB_BIO_DSP_READ_DATA);
- break;
- }
-
- t8254_wait(t8254_us2ticks(10));
- if (--patience == 0) {
- DEBUG(fprintf(stdout,"sndsb_read_dsp() read timeout\n"));
- return -1;
- }
- } while (1);
-
- DEBUG(fprintf(stdout,"sndsb_read_dsp() == 0x%02X\n",c));
- return c;
-}
-
-int sndsb_read_dsp_timeout(struct sndsb_ctx *cx,unsigned long timeout_ms) {
- unsigned int patience = (unsigned int)(timeout_ms / 10UL);
- int c = -1;
-
- do {
- if (inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS+(cx->dsp_alias_port?1:0)) & 0x80) { /* data available? */
- c = inp(cx->baseio+SNDSB_BIO_DSP_READ_DATA);
- break;
- }
-
- t8254_wait(t8254_us2ticks(10));
- if (--patience == 0) {
- DEBUG(fprintf(stdout,"sndsb_read_dsp() read timeout\n"));
- return -1;
- }
- } while (1);
-
- DEBUG(fprintf(stdout,"sndsb_read_dsp() == 0x%02X\n",c));
- return c;
-}
-
-unsigned int sndsb_ess_set_extended_mode(struct sndsb_ctx *cx,int enable) {
- if (cx->ess_chipset == 0) return 0; /* if not an ESS chipset then, no */
- if (!cx->ess_extensions) return 0; /* if caller/user says not to use extensions, then, no */
- if (cx->ess_extended_mode == !!enable) return 1;
-
- if (!sndsb_write_dsp(cx,enable?0xC6:0xC7))
- return 0;
-
- cx->ess_extended_mode = !!enable;
- return 1;
-}
-
-int sndsb_ess_read_controller(struct sndsb_ctx *cx,int reg) {
- if (reg < 0xA0 || reg >= 0xC0) return -1;
- if (sndsb_ess_set_extended_mode(cx,1) == 0) return -1;
- /* "Reading the data buffer of the ESS 1869: Command C0h is used to read
- * the ES1869 controller registers used for Extended mode. Send C0h
- * followed by the register number, Axh or Bxh. */
- if (!sndsb_write_dsp_timeout(cx,0xC0,20000UL)) return -1;
- if (!sndsb_write_dsp_timeout(cx,reg,20000UL)) return -1;
- return sndsb_read_dsp(cx);
-}
-
-int sndsb_ess_write_controller(struct sndsb_ctx *cx,int reg,unsigned char value) {
- if (reg < 0xA0 || reg >= 0xC0) return -1;
- if (sndsb_ess_set_extended_mode(cx,1) == 0) return -1;
- if (!sndsb_write_dsp_timeout(cx,reg,20000UL)) return -1;
- if (!sndsb_write_dsp_timeout(cx,value,20000UL)) return -1;
- return 0;
-}
-
-int sndsb_reset_dsp(struct sndsb_ctx *cx) {
- if (cx->baseio == 0) {
- DEBUG(fprintf(stdout,"BUG: sndsb baseio == 0\n"));
- return 0;
- }
-
- /* DSP reset takes the ESS out of extended mode */
- if (cx->ess_chipset != 0)
- cx->ess_extended_mode = 0;
-
- /* DSP reset procedure */
- /* "write 1 to the DSP and wait 3 microseconds" */
- DEBUG(fprintf(stdout,"sndsb_reset_dsp() reset in progress\n"));
- if (cx->ess_extensions)
- outp(cx->baseio+SNDSB_BIO_DSP_RESET,3); /* ESS reset and flush FIFO */
- else
- outp(cx->baseio+SNDSB_BIO_DSP_RESET,1); /* normal reset */
-
- t8254_wait(t8254_us2ticks(1000)); /* be safe and wait 1ms */
- outp(cx->baseio+SNDSB_BIO_DSP_RESET,0);
-
- /* wait for the DSP to return 0xAA */
- /* "typically the DSP takes about 100us to initialize itself" */
- if (sndsb_read_dsp(cx) != 0xAA) {
- if (sndsb_read_dsp(cx) != 0xAA) {
- DEBUG(fprintf(stdout,"sndsb_read_dsp() did not return satisfactory answer\n"));
- return 0;
- }
- }
-
- return 1;
-}
-
-int sndsb_read_mixer(struct sndsb_ctx *cx,uint8_t i) {
- outp(cx->baseio+SNDSB_BIO_MIXER_INDEX,i);
- return inp(cx->baseio+SNDSB_BIO_MIXER_DATA);
-}
-
-void sndsb_write_mixer(struct sndsb_ctx *cx,uint8_t i,uint8_t d) {
- outp(cx->baseio+SNDSB_BIO_MIXER_INDEX,i);
- outp(cx->baseio+SNDSB_BIO_MIXER_DATA,d);
-}
-
-unsigned char sndsb_test_write_mixer(struct sndsb_ctx *cx,uint8_t i,uint8_t d) {
- unsigned char o,c;
- o = sndsb_read_mixer(cx,i); sndsb_write_mixer(cx,i,d);
- c = sndsb_read_mixer(cx,i); sndsb_write_mixer(cx,i,o);
- return c;
-}
-
-/* NTS: If DOSBox's emulation is correct, 0xFF is not necessarily what is returned for
- * unknown registers, therefore it's not an accurate way to probe the chipset.
- * DOSBox for example seems to return 0x0A. */
-int sndsb_probe_mixer(struct sndsb_ctx *cx) {
- cx->mixer_chip = 0;
-
- /* if there is a wider "master volume" control 0x30 then we're a CT1745 or higher */
- if ( (sndsb_test_write_mixer(cx,0x30,0x08)&0xF8) == 0x08 &&
- (sndsb_test_write_mixer(cx,0x30,0x38)&0xF8) == 0x38 &&
- (sndsb_test_write_mixer(cx,0x31,0x08)&0xF8) == 0x08 &&
- (sndsb_test_write_mixer(cx,0x31,0x38)&0xF8) == 0x38) {
- cx->mixer_chip = SNDSB_MIXER_CT1745;
- }
- /* If there is a "master volume" control at 0x22 then we're at CT1345 or higher */
- else if((sndsb_test_write_mixer(cx,0x22,0x33)&0xEE) == 0x22 &&
- (sndsb_test_write_mixer(cx,0x22,0xCC)&0xEE) == 0xCC) {
- cx->mixer_chip = SNDSB_MIXER_CT1345;
- }
- /* hm, may be at CT1335 */
- else if((sndsb_test_write_mixer(cx,0x02,0x02)&0x0E) == 0x02 &&
- (sndsb_test_write_mixer(cx,0x02,0x0C)&0x0E) == 0x0C) {
- cx->mixer_chip = SNDSB_MIXER_CT1335;
- }
-
- sndsb_choose_mixer(cx,-1);
- return (cx->mixer_chip != 0);
-}
-
-int sndsb_mpu_command(struct sndsb_ctx *cx,uint8_t d) {
- unsigned int patience = 100;
-
- do {
- if (inp(cx->mpuio+SNDSB_MPUIO_STATUS) & 0x40) /* if not ready for cmd, wait and try again */
- t8254_wait(t8254_us2ticks(100));
- else {
- outp(cx->mpuio+SNDSB_MPUIO_COMMAND,d);
- return 1;
- }
- } while (--patience != 0);
- return 0;
-}
-
-int sndsb_mpu_write(struct sndsb_ctx *cx,uint8_t d) {
- unsigned int patience = 100;
-
- do {
- if (inp(cx->mpuio+SNDSB_MPUIO_STATUS) & 0x40) /* if not ready for cmd, wait and try again */
- t8254_wait(t8254_us2ticks(100));
- else {
- outp(cx->mpuio+SNDSB_MPUIO_DATA,d);
- return 1;
- }
- } while (--patience != 0);
- return 0;
-}
-
-int sndsb_mpu_read(struct sndsb_ctx *cx) {
- unsigned int patience = 100;
-
- do {
- if (inp(cx->mpuio+SNDSB_MPUIO_STATUS) & 0x80) /* if data ready not ready, wait and try again */
- t8254_wait(t8254_us2ticks(100));
- else {
- return inp(cx->mpuio+SNDSB_MPUIO_DATA);
- }
- } while (--patience != 0);
-
- return -1;
-}
-
-/* this code makes sure the MPU exists */
-int sndsb_probe_mpu401(struct sndsb_ctx *cx) {
- unsigned int patience = 10;
- int c;
-
- if (cx->mpuio == 0) return 0;
-
- /* check the command register. note however that if neither data is available
- * or a command can be written this can return 0xFF */
- if (inp(cx->mpuio+SNDSB_MPUIO_STATUS) == 0xFF) {
- /* hm, perhaps it's stuck returning data? */
- do { /* wait for it to signal no data and/or ability to write command */
- inp(cx->mpuio+SNDSB_MPUIO_DATA);
- if (inp(cx->mpuio+SNDSB_MPUIO_STATUS) != 0xFF)
- break;
-
- if (--patience == 0) return 0;
- t8254_wait(t8254_us2ticks(100)); /* 100us */
- } while(1);
- }
-
- patience=3;
- do {
- /* OK we got the status register to return something other than 0xFF.
- * Issue a reset */
- if (sndsb_mpu_command(cx,0xFF)) {
- if ((c=sndsb_mpu_read(cx)) == 0xFE) {
- break;
- }
- }
-
- if (--patience == 0)
- return 0;
-
- t8254_wait(t8254_us2ticks(10)); /* 10us */
- } while (1);
-
- return 1;
-}
-
-int sndsb_write_dsp(struct sndsb_ctx *cx,uint8_t d) {
- unsigned int patience = 25000;
-
- DEBUG(fprintf(stdout,"sndsb_write_dsp(0x%02X)\n",d));
- do {
- if (inp(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0)) & 0x80)
- t8254_wait(t8254_us2ticks(10));
- else {
- outp(cx->baseio+SNDSB_BIO_DSP_WRITE_DATA+(cx->dsp_alias_port?1:0),d);
- return 1;
- }
- } while (--patience != 0);
- DEBUG(fprintf(stdout,"sndsb_write_dsp() timeout\n"));
- return 0;
-}
-
-int sndsb_write_dsp_timeout(struct sndsb_ctx *cx,uint8_t d,unsigned long timeout_ms) {
- unsigned int patience = (unsigned int)(timeout_ms / 10UL);
-
- DEBUG(fprintf(stdout,"sndsb_write_dsp(0x%02X)\n",d));
- do {
- if (inp(cx->baseio+SNDSB_BIO_DSP_WRITE_STATUS+(cx->dsp_alias_port?1:0)) & 0x80)
- t8254_wait(t8254_us2ticks(10));
- else {
- outp(cx->baseio+SNDSB_BIO_DSP_WRITE_DATA+(cx->dsp_alias_port?1:0),d);
- return 1;
- }
- } while (--patience != 0);
- DEBUG(fprintf(stdout,"sndsb_write_dsp() timeout\n"));
- return 0;
-}
-
-int sndsb_write_dsp_timeconst(struct sndsb_ctx *cx,uint8_t tc) {
- if (!sndsb_write_dsp(cx,0x40))
- return 0;
- if (!sndsb_write_dsp(cx,tc))
- return 0;
- return 1;
-}
-
-int sndsb_query_dsp_version(struct sndsb_ctx *cx) {
- int a,b;
-
- if (!sndsb_write_dsp(cx,SNDSB_DSPCMD_GET_VERSION))
- return 0;
-
- if ((a=sndsb_read_dsp(cx)) < 0)
- return 0;
- if ((b=sndsb_read_dsp(cx)) < 0)
- return 0;
- if (a == 0xFF || b == 0xFF)
- return 0;
-
- cx->dsp_vmaj = (uint8_t)a;
- cx->dsp_vmin = (uint8_t)b;
- DEBUG(fprintf(stdout,"sndsb_query_dsp_version() == v%u.%u\n",a,b));
- return 1;
-}
-
-/* NTS: We do not test IRQ and DMA channels here */
-/* NTS: The caller may have set irq == -1, dma8 == -1, or dma16 == -1, such as
- * when probing. If any of them are -1, and this code knows how to deduce
- * it directly from the hardware, then they will be updated */
-int sndsb_init_card(struct sndsb_ctx *cx) {
- /* some of our detection relies on knowing what OS we're running under */
- cpu_probe();
- probe_dos();
- detect_windows();
-
-#if TARGET_MSDOS == 32
- cx->goldplay_dma = NULL;
-#endif
- cx->backwards = 0;
- cx->ess_chipset = 0;
- cx->dsp_nag_mode = 0;
- cx->ess_extensions = 0;
- cx->dsp_nag_hispeed = 0;
- cx->ess_extended_mode = 0;
- cx->hispeed_matters = 1; /* assume it does */
- cx->dosbox_emulation = 0;
- cx->hispeed_blocking = 1; /* assume it does */
- cx->timer_tick_signal = 0;
- cx->timer_tick_func = NULL;
- cx->poll_ack_when_no_irq = 1;
- cx->virtualbox_emulation = 0;
- cx->reason_not_supported = NULL;
- cx->dsp_alias_port = sndsb_probe_options.use_dsp_alias;
- cx->dsp_direct_dac_poll_retry_timeout = 16; /* assume at least 16 I/O reads to wait for DSP ready */
- cx->dsp_direct_dac_read_after_command = 0;
- cx->windows_creative_sb16_drivers_ver = 0;
- cx->windows_creative_sb16_drivers = 0;
- cx->dsp_4xx_fifo_single_cycle = 0;
- cx->windows_9x_me_sbemul_sys = 0;
- cx->audio_data_flipped_sign = 0;
- cx->dsp_4xx_fifo_autoinit = 1;
- cx->dsp_autoinit_command = 1;
- cx->buffer_irq_interval = 0;
- cx->windows_springwait = 0;
- cx->chose_autoinit_dma = 0;
- cx->chose_autoinit_dsp = 0;
- cx->do_not_probe_irq = 0;
- cx->do_not_probe_dma = 0;
- cx->is_gallant_sc6600 = 0;
- cx->windows_emulation = 0;
- cx->windows_xp_ntvdm = 0;
- cx->dsp_copyright[0] = 0;
- cx->dsp_autoinit_dma = 1;
- cx->buffer_last_io = 0;
- cx->direct_dsp_io = 0;
- cx->goldplay_mode = 0;
- cx->force_hispeed = 0;
- cx->chose_use_dma = 0;
- cx->vdmsound = 0;
- cx->mega_em = 0;
- cx->sbos = 0;
- cx->mpu_ok = 0;
- cx->dsp_ok = 0;
- cx->mixer_ok = 0;
- cx->dsp_vmaj = 0;
- cx->dsp_vmin = 0;
- cx->buffer_phys = 0;
- cx->buffer_lin = NULL;
- cx->buffer_rate = 22050;
- cx->enable_adpcm_autoinit = 0;
- cx->dsp_adpcm = 0;
- cx->dsp_record = 0;
- cx->sb_mixer_items = 0;
- cx->sb_mixer = NULL;
- cx->max_sample_rate_sb_play_dac = 23000;
- cx->max_sample_rate_sb_rec_dac = 13000;
-
- if (!sndsb_reset_dsp(cx)) return 0;
- cx->dsp_ok = 1;
-
- /* hm, what version are you? */
- if (!sndsb_query_dsp_version(cx)) {
- /* hm? failed the DSP version command?
- * are you OK? test by sending "disable speaker" */
- if (!sndsb_write_dsp(cx,0xD1))
- cx->dsp_ok = 0;
- }
-
- /* FIX: Apparently when SBOS unloads it leaves behind the I/O
- port stuck returning 0xAA, which can trick most SB
- compatible DOS programs into thinking the DSP is still
- there. But if we read back the DSP version as 0xAA 0xAA
- then we know it's just SBOS not cleaning up after itself */
- if (cx->dsp_vmaj == 0xAA && cx->dsp_vmin == 0xAA)
- return 0; /* That's not a Sound Blaster! */
-
- /* FIX: Gravis Ultrasound MEGA-EM emulates a VERY LIMITED SUBSET
- of the Sound Blaster. Worse, it hangs the machine with an
- error message when you use any command it doesn't know!
-
- MEGA-EM usually reports itself as v1.3, but you can also
- use EMUSET -X2 to enable a rudimentary sort of DSP v2.1
- emulation. True SB hardware doesn't carry a DSP copyright
- string until v3.0, so it's probable we wouldn't get anything
- anyway. The DSP copyright string command is not recognized
- by MEGA-EM. */
- if (cx->dsp_vmaj <= 2) {
- if (gravis_mega_em_detect(&megaem_info)) { /* is that you, MEGA-EM? */
- /* FIXME: Is there some sort of hack we can use
- to determine what I/O port MEGA-EM is
- watching? I would like this code to
- not self-limit it's capabilities to
- ALL interfaces just because one happens
- to be a GUS with MEGA-EM. */
- cx->mega_em = 1;
- cx->dsp_autoinit_dma = 0;
- strcpy(cx->dsp_copyright,"Gravis MEGA-EM");
- }
- }
-
- /* if the DSP is recent enough, it might have a copyright string.
-
- DSPs prior to the Sound Blaster Pro don't really seem to return
- anything in response to DSP command 0xE3, in fact it might be that
- Creative added it with the SB16 (DSP v4.x). However I also know
- from programming experience that many SB clones DO return a string
- and report themselves with varying version numbers like v3.1, v2.5,
- etc. */
- if (!cx->mega_em && cx->dsp_vmaj >= 2) {
- int i,c;
-
- sndsb_write_dsp(cx,0xE3);
- for (i=0;i < (sizeof(cx->dsp_copyright)-1);i++) {
- c = sndsb_read_dsp(cx);
- if (c < 0) break;
- cx->dsp_copyright[i] = (char)c;
- if (c == 0) break;
- }
- cx->dsp_copyright[i] = (char)0;
- DEBUG(fprintf(stdout,"sndsb_init_card() copyright == '%s'\n",cx->dsp_copyright));
-
- /* check for whacked-out DSP "strings" like a continuous
- sequence of 0x01 bytes. it might be Gravis SBOS, which
- also reports itself as DSP v2.1 */
- if (cx->dsp_vmaj <= 2 && i >= (sizeof(cx->dsp_copyright)-1)) {
- for (i=0,c=0;i < (sizeof(cx->dsp_copyright)-1);i++) {
- if (cx->dsp_copyright[i] == 1)
- c++;
- else
- break;
- }
-
- if (c == i) {
- if (gravis_sbos_detect() >= 0) { /* is that you, SBOS? */
- strcpy(cx->dsp_copyright,"Gravis SBOS");
- cx->dsp_autoinit_dma = 0;
- cx->sbos = 1;
- }
- }
- }
- }
-
- if (sndsb_probe_mixer(cx)) /* NTS: Don't reset the mixer, just probe it */
- cx->mixer_ok = 1;
-
- /* Sound Blaster 16 (DSP 4.xx): we read the mixer registers, unless this card was initialized from a PnP device */
- /* Earlier cards: we have to probe around for it */
- if (cx->dsp_vmaj == 4 && !sndsb_probe_options.disable_sb16_read_config_byte && cx->pnp_id == 0) {
- unsigned char irqm = sndsb_read_mixer(cx,0x80);
- unsigned char dmam = sndsb_read_mixer(cx,0x81);
- if (cx->irq < 0 && irqm != 0xFF && irqm != 0x00) {
- if (irqm & 8) cx->irq = 10;
- else if (irqm & 4) cx->irq = 7;
- else if (irqm & 2) cx->irq = 5;
- else if (irqm & 1) cx->irq = 2;
-
- cx->do_not_probe_irq = 1;
- }
- if (dmam != 0xFF && dmam != 0x00) {
- if (cx->dma8 < 0) {
- if (dmam & 8) cx->dma8 = 3;
- else if (dmam & 2) cx->dma8 = 1;
- else if (dmam & 1) cx->dma8 = 0;
- }
-
- if (cx->dma16 < 0) {
- if (dmam & 0x80) cx->dma16 = 7;
- else if (dmam & 0x40) cx->dma16 = 6;
- else if (dmam & 0x20) cx->dma16 = 5;
- }
-
- /* NTS: From the Creative programming guide:
- * "DSP version 4.xx also supports the transfer of 16-bit sound data through
- * 8-bit DMA channel. To make this possible, set all 16-bit DMA channel bits
- * to 0 leaving only 8-bit DMA channel set" */
- if (cx->dma16 == -1)
- cx->dma16 = cx->dma8;
-
- cx->do_not_probe_dma = 1;
- }
- }
-
- /* Reveal SC400 SB16 clone: I have this card and I can tell
- * from programming experience that while it reports itself
- * as DSP v3.5 (Sound Blaster Pro) it actually has a SB16
- * type mixer and supports most (but not all) of the SB16
- * type DSP commands. It lacks however the configuration
- * registers in the mixer for DMA and IRQ settings, on
- * this card you use secret undocumented DSP commands.
- * The card also has a "Windows Sound System" interface
- * at 0x530, which is not relevent here since we focus on
- * the Sound Blaster part.
- *
- * It also has a amusing hardware bug where I can set the
- * DSP up as if doing a DMA transfer, and then my code can
- * fake the DMA transfer by writing to the DSP command
- * port, something I took advantage of prior to figuring out
- * the DMA controller back in the day */
- if (!strcmp(cx->dsp_copyright,"SC-6000")) {
- if (sndsb_write_dsp(cx,0x58)) {
- unsigned char a,b,c;
- a = (unsigned char)sndsb_read_dsp(cx);
- if (a == 0xAA) a = (unsigned char)sndsb_read_dsp(cx);
- /* observation: if the card is jumpered to 220h, the first byte is 0x2E, second is 0xC5.
- if the card is jumpered to 240h, the first byte is 0x2F, second is 0xC3.
- is that really what bit 0 indicates? */
- if ((a&0xFE) == 0x2E) {
- cx->is_gallant_sc6600 = 1;
- b = (unsigned char)sndsb_read_dsp(cx);
- c = (unsigned char)sndsb_read_dsp(cx);
- if (b != 0 && c != 0) {
- /* SC400: Experience says the card always works over
- * the 8-bit DMA even for 16-bit PCM audio */
- if (cx->dma8 < 0)
- cx->dma8 = gallant_sc6600_map_to_dma[c&3];
- if (cx->dma16 < 0)
- cx->dma16 = cx->dma8;
- if (cx->irq < 0)
- cx->irq = gallant_sc6600_map_to_irq[(c>>3)&7];
-
- cx->do_not_probe_irq = 1;
- cx->do_not_probe_dma = 1;
- }
- }
- }
- }
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- /* trimmed to keep total code <= 64KB */
-#else
- if (windows_mode == WINDOWS_NT) {
- /* Windows NT would never let a DOS program like us talk directly to hardware,
- * so if we see a Sound Blaster like device it's very likely an emulation driver.
- * Working correctly then requires us to deduce what emulation driver we're running under. */
-
- /* No copyright string and DSP v2.1: Microsoft Windows XP/Vista/7 native NTVDM.EXE SB emulation */
- if (cx->dsp_copyright[0] == 0 && cx->dsp_vmaj == 2 && cx->dsp_vmin == 1) {
- cx->windows_xp_ntvdm = 1;
- cx->windows_emulation = 1;
- strcpy(cx->dsp_copyright,"Microsoft Windows XP/Vista/7 NTVDM.EXE SB emulation");
- }
- /* anything else: probably VDMSOUND.EXE, which provides good enough emulation we don't need workarounds */
- /* TODO: Is there anything we can do to detect with certainty that it's VDMSOUND.EXE? */
- else {
- /* NTS: VDMSOUND.EXE emulates everything down to the copyright string, so append to the string instead of replacing */
- char *x = cx->dsp_copyright+strlen(cx->dsp_copyright);
- char *f = cx->dsp_copyright+sizeof(cx->dsp_copyright)-1;
- const char *add = " [VDMSOUND]";
-
- cx->vdmsound = 1;
- cx->windows_emulation = 1;
- if (x != cx->dsp_copyright) {
- while (x < f && *add) *x++ = *add++;
- *x = 0;
- }
- else {
- strcpy(cx->dsp_copyright,"VDMSOUND");
- }
- }
- }
- else if (windows_mode == WINDOWS_ENHANCED) { /* Windows 9x/ME Sound Blaster */
- struct w9x_vmm_DDB_scan vxdscan;
- unsigned char vxdscanned = 0;
-
- /* Two possibilities from experience:
- * a) We can see and talk to the Sound Blaster because the driver
- * implements a "pass through" virtualization like mode. Meaning,
- * if we start talking to the Sound Blaster the driver catches it
- * and treats it as yet another process opening the sound card.
- * Meaning that, as long as we have the sound card playing audio,
- * other Windows applications cannot open it, and if other Windows
- * applications have it open, we cannot initialize the card.
- *
- * That scenario is typical of:
- *
- * - Microsoft Windows 95 with Microsoft stock Sound Blaster 16 drivers
- *
- * That scenario brings up an interesting problem as well: Since
- * it literally "passes through" the I/O, we see the card for what
- * it is. So we can't check for inconsistencies in I/O like we can
- * with most emulations. If knowing about this matters enough, we
- * have to know how to poke around inside the Windows kernel and
- * autodetect which drivers are resident.
- *
- * b) The Sound Blaster is virtual. In the most common case with
- * Windows 9x, it likely means there's a PCI-based sound card
- * installed with kernel-level emulation enabled. What we are able
- * to do depends on what the driver offers us.
- *
- * That scenario is typical of:
- *
- * Microsoft Windows 98/ME with PCI-based sound hardware. In
- * one test scenario of mine, it was a Sound Blaster Live!
- * value card and Creative "Sound Blaster 16 emulation" drivers.
- *
- * Microsoft Windows ME, through SBEMUL.SYS, which uses the
- * systemwide default sound driver to completely virtualize
- * the sound card. On one virtual machine, Windows ME uses the
- * AC'97 codec driver to emulate a Sound Blaster Pro.
- *
- * Since emulation can vary greatly, detecting the emulator through
- * I/O inconsistencies is unlikely to work, again, if it matters we
- * need a way to poke into the Windows kernel and look at which drivers
- * are resident.
- *
- * c) The Sound Blaster is actual hardware, and Windows is not blocking
- * or virtualizing any I/O ports.
- *
- * I know you're probably saying to yourself: Ick! But under Windows 95
- * such scenarios are possible: if there is a SB16 compatible sound
- * card out there and no drivers are installed to talk to it, Windows
- * 95 itself will not talk to the card, but will allow DOS programs
- * to do so. Amazingly, it will still virtualize the DMA controller
- * in a manner that allows everything to work!
- *
- * Whatever you do in this scenario: Don't let multiple DOS boxes talk
- * to the same Sound Blaster card!!!
- *
- * So unlike the Windows NT case, we can't assume emulators or capabilities
- * because it varies greatly depending on the host configuration. But we
- * can try our best and at least try to avoid things that might trip up
- * Windows 9x. */
- cx->windows_emulation = 1; /* NTS: The "pass thru" scenario counts as emulation */
-
- if (!sndsb_probe_options.disable_windows_vxd_checks && w9x_vmm_first_vxd(&vxdscan)) {
- vxdscanned = 1;
- do {
- /* If SBEMUL.SYS is present, then it's definitely Windows 98/ME SBEMUL.SYS */
- if (!memcmp(vxdscan.ddb.name,"SBEMUL ",8)) {
- cx->windows_9x_me_sbemul_sys = 1;
- }
- /* If a Sound Blaster 16 is present, usually Windows 9x/ME will install the
- * stock Creative drivers shipped on the CD-ROM */
- else if (!memcmp(vxdscan.ddb.name,"VSB16 ",8)) {
- cx->windows_creative_sb16_drivers = 1;
- cx->windows_creative_sb16_drivers_ver = ((uint16_t)vxdscan.ddb.Mver << 8U) | ((uint16_t)vxdscan.ddb.minorver);
- }
- } while (w9x_vmm_next_vxd(&vxdscan));
- w9x_vmm_last_vxd(&vxdscan);
- }
-
- /* DSP v3.2, no copyright string, and (no VxD scan OR SBEMUL.SYS is visible)
- * Might be Microsoft Windows 98/ME SBEMUL.SYS */
- if ((!vxdscanned || cx->windows_9x_me_sbemul_sys) && cx->dsp_vmaj == 3 && cx->dsp_vmin == 2 && cx->dsp_copyright[0] == 0) {
- /* No hacks required, the emulation is actually quite reasonable, though as usual
- * using extremely short block sizes will cause stuttering. The only recognition
- * necessary is that SBEMUL.SYS does not support the ADPCM modes. Applies to Windows 98
- * and Windows ME. */
- strcpy(cx->dsp_copyright,"Microsoft Windows 98/ME SBEMUL.SYS");
- }
- /* Sound Blaster 16 DSP, and VSB16 (SB16.VXD) is visible.
- * Might be Creative's Sound Blaster 16 drivers. */
- else if (cx->windows_creative_sb16_drivers && cx->dsp_vmaj == 4 && !strcmp(cx->dsp_copyright,"COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.")) {
- sprintf(cx->dsp_copyright,"Creative Sound Blaster 16 driver for Win 3.1/9x/ME v%u.%u",
- cx->windows_creative_sb16_drivers_ver>>8,
- cx->windows_creative_sb16_drivers_ver&0xFF);
- }
- }
-
- /* add our commentary for other emulation environments we can detect */
- if (!cx->windows_emulation && detect_dosbox_emu()) {
- /* add commentary if we know we're running under the DOSBox emulator.
- * Nothing special, DOSBox does a damn good job at it's emulation so
- * no workarounds are required. */
- char *x = cx->dsp_copyright+strlen(cx->dsp_copyright);
- char *f = cx->dsp_copyright+sizeof(cx->dsp_copyright)-1;
- const char *add = " [DOSBox]";
-
- cx->dosbox_emulation = 1;
- if (x != cx->dsp_copyright) {
- while (x < f && *add) *x++ = *add++;
- *x = 0;
- }
- else {
- strcpy(cx->dsp_copyright,"DOSBox emulator");
- }
- }
-
- if (!cx->windows_emulation && detect_virtualbox_emu())
- cx->virtualbox_emulation = 1;
-
- /* DSP v3.1 and no copyright string means it might be an ESS 688/1869 chipset */
- /* FIXME: A freak accident during development shows me it's possible to change the DSP version to v2.1 */
- if (!cx->windows_emulation && !cx->is_gallant_sc6600 && cx->dsp_vmaj == 3 && cx->dsp_vmin == 1 &&
- cx->dsp_copyright[0] == 0 && !sndsb_probe_options.disable_ess_extensions) {
- /* Use DSP command 0xE7 to detect ESS chipset */
- if (sndsb_write_dsp(cx,0xE7)) {
- unsigned char c1,c2;
- int in;
-
- c1 = sndsb_read_dsp(cx);
- c2 = sndsb_read_dsp(cx);
- if (c1 == 0x68 && (c2 & 0xF0) == 0x80) { /* ESS responds 0x68 0x8x where x = version code */
- c2 &= 0xF;
- if (c2 != 0) {
- cx->ess_chipset = (c2 & 8) ? SNDSB_ESS_1869 : SNDSB_ESS_688;
-
- if (cx->ess_chipset == SNDSB_ESS_688) { /* ESS 688? I know how to program that! */
- cx->ess_extensions = 1;
-
- /* that also means that we can deduce the true IRQ/DMA from the chipset */
- if ((in=sndsb_ess_read_controller(cx,0xB1)) != -1) { /* 0xB1 Legacy Audio Interrupt Control */
- switch (in&0xF) {
- case 0x5:
- cx->irq = 5;
- break;
- case 0xA:
- cx->irq = 7;
- break;
- case 0xF:
- cx->irq = 10;
- break;
- case 0x0: /* "2,9,all others" */
- cx->irq = 9;
- break;
- default:
- break;
- }
- }
- if ((in=sndsb_ess_read_controller(cx,0xB2)) != -1) { /* 0xB2 DRQ Control */
- switch (in&0xF) {
- case 0x0:
- cx->dma8 = cx->dma16 = -1;
- break;
- case 0x5:
- cx->dma8 = cx->dma16 = 0;
- break;
- case 0xA:
- cx->dma8 = cx->dma16 = 1;
- break;
- case 0xF:
- cx->dma8 = cx->dma16 = 3;
- break;
- default:
- if (cx->dma8 >= 0 && cx->dma16 < 0)
- cx->dma16 = cx->dma8;
- if (cx->dma16 >= 0 && cx->dma8 < 0)
- cx->dma8 = cx->dma16;
- break;
- }
- }
- }
- else if (cx->ess_chipset == SNDSB_ESS_1869) { /* ESS 1869? I know how to program that! */
- cx->ess_extensions = 1;
-
- /* NTS: The ESS 1869 and later have PnP methods to configure themselves, and the
- * registers are documented as readonly for that reason, AND, on the ESS 1887 in
- * the Compaq system I test, the 4-bit value that supposedly corresponds to IRQ
- * doesn't seem to do anything. */
-
- /* The ESS 1869 (on the Compaq) appears to use the same 8-bit DMA for 16-bit as well.
- * Perhaps the second DMA channel listed by the BIOS is the second channel (for full
- * duplex?) */
- if (cx->dma8 >= 0 && cx->dma16 < 0)
- cx->dma16 = cx->dma8;
- if (cx->dma16 >= 0 && cx->dma8 < 0)
- cx->dma8 = cx->dma16;
- }
-
- /* TODO: 1869 datasheet recommends reading mixer index 0x40
- * four times to read back 0x18 0x69 A[11:8] A[7:0]
- * where A is the base address of the configuration
- * device. I don't have an ESS 1869 on hand to test
- * and dev that. Sorry. --J.C. */
- }
- }
- }
- }
-#endif
-
- if (cx->ess_chipset != 0 && cx->dsp_copyright[0] == 0) {
- const char *s = sndsb_ess_chipset_str(cx->ess_chipset);
- if (s != NULL) strcpy(cx->dsp_copyright,s);
- }
-
- /* check DMA against the DMA controller presence.
- * If there is no 16-bit DMA (channels 4-7) then we cannot use
- * those channels */
- if (!(d8237_flags&D8237_DMA_SECONDARY)) {
- if (cx->dma16 >= 4) cx->dma16 = -1;
- if (cx->dma8 >= 4) cx->dma8 = -1;
- }
- if (!(d8237_flags&D8237_DMA_PRIMARY)) {
- if (cx->dma16 >= 0 && cx->dma16 < 4) cx->dma16 = -1;
- if (cx->dma8 >= 0 && cx->dma8 < 4) cx->dma8 = -1;
- }
-
- if (cx->mpuio == 0) { /* uh oh, we have to probe for it */
- if (sndsb_by_mpu(0x330) == NULL) {
- cx->mpuio = 0x330; /* more common */
- if (sndsb_probe_mpu401(cx))
- cx->mpu_ok = 1;
- else {
- if (sndsb_by_mpu(0x300) == NULL) {
- cx->mpuio = 0x300; /* less common */
- if (sndsb_probe_mpu401(cx))
- cx->mpu_ok = 1;
- else {
- cx->mpuio = 0;
- }
- }
- }
- }
- }
- else {
- if (sndsb_probe_mpu401(cx))
- cx->mpu_ok = 1;
- }
-
- if (cx->dsp_vmaj >= 4) {
- /* Highspeed DSP commands don't matter anymore, they're just an alias to older commands */
- cx->hispeed_matters = 0;
- cx->hispeed_blocking = 0;
- /* The DSP is responsive even during hispeed mode, you can nag it then just fine */
- cx->dsp_nag_hispeed = 1;
- /* FIXME: At exactly what DSP version did SB16 allow going up to 48KHz?
- * I'm going by the ViBRA test card I own having DSP 4.13 vs DOSBox sbtype=sb16
- * reporting DSP v4.5 */
- if (cx->dsp_vmaj == 4 && cx->dsp_vmin > 5)
- cx->max_sample_rate_dsp4xx = 48000;
- else
- cx->max_sample_rate_dsp4xx = 44100;
-
- cx->enable_adpcm_autoinit = 1; /* NTS: Unless there are DSP 4.xx SB clones out there that don't, we can assume auto-init ADPCM */
- cx->max_sample_rate_sb_hispeed_rec = cx->max_sample_rate_dsp4xx;
- cx->max_sample_rate_sb_hispeed = cx->max_sample_rate_dsp4xx;
- cx->max_sample_rate_sb_play = cx->max_sample_rate_dsp4xx;
- cx->max_sample_rate_sb_rec = cx->max_sample_rate_dsp4xx;
- if (cx->max_sample_rate_dsp4xx > 44100) { /* SB16 ViBRA cards apparently allow Direct DAC output up to 24KHz instead of 23KHz */
- cx->max_sample_rate_sb_play_dac = 24000;
- /* TODO: Is recording speed affected? */
- }
- }
- else if (cx->dsp_vmaj == 3) {
- if (cx->ess_chipset != 0) { /* ESS 688/1869 */
- /* NTS: The ESS 688 (Sharp laptop) and ESS 1869 (Compaq desktop) I test against seems quite capable
- * of playing back at 48KHz, in fact it will happily go beyond 48KHz up to 64KHz in my tests
- * barring ISA bus limitations (16-bit stereo at 54KHz audibly "warbles" for example). For
- * for consistentcy's sake, we'll just go ahead and say the chip goes up to 48KHz */
- cx->dsp_direct_dac_poll_retry_timeout = 4; /* DSP is responsive to direct DAC to allow lesser timeout */
- cx->max_sample_rate_dsp4xx = 48000;
- cx->max_sample_rate_sb_hispeed_rec = 48000;
- cx->max_sample_rate_sb_hispeed = 48000;
- cx->max_sample_rate_sb_play = 48000;
- cx->max_sample_rate_sb_rec = 48000;
- cx->enable_adpcm_autoinit = 0; /* does NOT support auto-init ADPCM */
- /* also: hi-speed DSP is blocking, and it matters: to go above 23KHz you have to use hi-speed DSP commands */
- }
- else if (cx->is_gallant_sc6600) { /* SC-6600 clone card */
- cx->dsp_direct_dac_poll_retry_timeout = 4; /* DSP is responsive to direct DAC to allow lesser timeout */
- /* NTS: Officially, the max sample rate is 24000Hz, but the DSP seems to allow up to 25000Hz,
- * then limit the sample rate to that up until about 35000Hz where it suddenly clamps
- * the rate down to 24000Hz. Mildly strange bug. */
- cx->max_sample_rate_dsp4xx = 44100;
- cx->max_sample_rate_sb_hispeed_rec = 44100; /* playback and recording rate (it's halved to 22050Hz for stereo) */
- cx->max_sample_rate_sb_hispeed = 44100; /* playback and recording rate (it's halved to 22050Hz for stereo) */
- cx->max_sample_rate_sb_play = 25000; /* non-hispeed mode (and it's halved to 11500Hz for stereo) */
- cx->max_sample_rate_sb_rec = 25000; /* non-hispeed mode (and it's halved to 11500Hz for stereo) */
- cx->enable_adpcm_autoinit = 0; /* does NOT support auto-init ADPCM */
- /* also: hi-speed DSP is blocking, and it matters: to go above 23KHz you have to use hi-speed DSP commands */
- }
- else { /* Sound Blaster Pro */
- cx->max_sample_rate_dsp4xx = 0;
- cx->max_sample_rate_sb_hispeed_rec = 44100; /* playback and recording rate (it's halved to 22050Hz for stereo) */
- cx->max_sample_rate_sb_hispeed = 44100; /* playback and recording rate (it's halved to 22050Hz for stereo) */
- cx->max_sample_rate_sb_play = 23000; /* non-hispeed mode (and it's halved to 11500Hz for stereo) */
- cx->max_sample_rate_sb_rec = 23000; /* non-hispeed mode (and it's halved to 11500Hz for stereo) */
- }
- }
- else if (cx->dsp_vmaj == 2) {
- if (cx->dsp_vmin >= 1) { /* Sound Blaster 2.01 */
- cx->max_sample_rate_dsp4xx = 0;
- cx->max_sample_rate_sb_hispeed_rec = 15000;
- cx->max_sample_rate_sb_rec = 13000;
- cx->max_sample_rate_sb_hispeed = 44100; /* NTS: On actual SB 2.1 hardware I own you can apparently go up to 46KHz? */
- cx->max_sample_rate_sb_play = 23000;
- }
- else { /* Sound Blaster 2.0, without hispeed DSP commands */
- cx->max_sample_rate_dsp4xx = 0;
- cx->max_sample_rate_sb_hispeed_rec = cx->max_sample_rate_sb_rec = 13000;
- cx->max_sample_rate_sb_hispeed = cx->max_sample_rate_sb_play = 23000;
- }
- }
- else { /* Sound Blaster 1.x */
- cx->max_sample_rate_dsp4xx = 0;
- cx->max_sample_rate_sb_hispeed_rec = cx->max_sample_rate_sb_rec = 13000;
- cx->max_sample_rate_sb_hispeed = cx->max_sample_rate_sb_play = 23000;
- }
-
- /* if any of our tests left the SB IRQ hanging, clear it now */
- if (cx->irq >= 0) {
- sndsb_interrupt_ack(cx,3);
- sndsb_interrupt_ack(cx,3);
- }
-
- /* DSP 2xx and earlier do not have auto-init commands */
- if (cx->dsp_vmaj < 2 || (cx->dsp_vmaj == 2 && cx->dsp_vmin == 0))
- cx->dsp_autoinit_command = 0;
- if (cx->irq < 0) {
- if (cx->dsp_autoinit_command)
- cx->dsp_nag_mode = 0;
- else
- cx->dsp_nag_mode = 1;
- }
-
- sndsb_determine_ideal_dsp_play_method(cx);
-
- return 1;
-}
-
-int sndsb_determine_ideal_dsp_play_method(struct sndsb_ctx *cx) {
- if (cx->dma8 < 0) /* No IRQ, no DMA, fallback to direct */
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_DIRECT;
- else if (cx->dsp_vmaj >= 4 || cx->is_gallant_sc6600)
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_4xx;
- else if (cx->dsp_vmaj == 3)
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_3xx;
- else if (cx->dsp_vmaj == 2 && cx->dsp_vmin >= 1) {
- /* Gravis SBOS does not do auto-init at all.
- Gravis MEGA-EM will fucking hang the computer and gripe
- about "unknown DSP command 1Ch" despite reporting itself
- as DSP v2.1 (EMUSET -X2). So don't do it! */
- if (cx->sbos || cx->mega_em)
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_1xx;
- else
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_201;
- }
- else if (cx->dsp_vmaj == 2)
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_200;
- else if (cx->dsp_vmaj == 1)
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_1xx;
- else
- cx->dsp_play_method = SNDSB_DSPOUTMETHOD_DIRECT;
-
- return 1;
-}
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
-static unsigned char sb_test_irq_number = 0;
-static volatile unsigned short int sb_test_irq_flag = 0;
-static void interrupt far sb_test_irq() {
- sb_test_irq_flag++;
- if (sb_test_irq_number >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
-}
-#endif
-
-/* alternative "lite" IRQ probing that hooks the interrupt and wait for an event.
- * Microsoft Windows friendly version that avoids 1) PIC commands to read back
- * events and 2) The undocumented DSP command 0xF2 that triggers an interrupt.
- *
- * While the primary method in manual_probe_irq() works well in pure DOS and
- * some DOS boxes, this lite version works better in virtualized environments
- * like Windows NT/9x DOS boxes. */
-void sndsb_alt_lite_probe_irq(struct sndsb_ctx *cx) {
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- /* too much code */
-#else
- void (interrupt *old_irq)() = NULL;
- unsigned int round = 0,tolerance;
- unsigned char ml,mh,maybe;
- unsigned int patience = 0;
- unsigned short eliminated = 0U,possible;
- unsigned char tries[] = {5,7},tri;
- unsigned int testlen = 22050/20; /* 1/20th of a second */
- struct dma_8237_allocation *dma;
- const unsigned char timeconst = (unsigned char)((65536UL - (256000000UL / 22050UL)) >> 8UL);
- DEBUG(fprintf(stdout,"Sound blaster IRQ unknown, I'm going to have to probe for it [alt lite]\n"));
-
- /* for this test we initiate playback of short blocks. so we must ensure that this
- * card has a known DMA channel assignment. */
- if (cx->dma8 < 0) return;
-
- dma = dma_8237_alloc_buffer(testlen);
- if (dma == NULL) return;
-
-#if TARGET_MSDOS == 32
- memset(dma->lin,128,testlen);
-#else
- _fmemset(dma->lin,128,testlen);
-#endif
-
- /* save the IRQ mask */
- _cli();
- ml = p8259_read_mask(0); /* IRQ0-7 */
- mh = p8259_read_mask(8); /* IRQ8-15 */
-
- round = 0;
- do {
- if (++round >= 8)
- break;
-
- possible = 0;
- /* go through the remaining ones, one at a time */
- for (tri=0;tri < sizeof(tries);tri++) {
- if (eliminated & (1U << tries[tri]))
- continue;
- if (!sndsb_reset_dsp(cx)) {
- DEBUG(fprintf(stdout,"WARNING: DSP reset failed, aborting IRQ probe\n"));
- break;
- }
-
- DEBUG(fprintf(stdout," Now testing IRQ %u\n",tries[tri]));
-
- /* clear SoundBlaster's previous interrupt */
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS);
-
- p8259_mask(tries[tri]);
- /* hook the interrupt, reset the flag, unmask the interrupt */
- sb_test_irq_flag = 0;
- sb_test_irq_number = tries[tri];
- old_irq = _dos_getvect(irq2int(tries[tri]));
- _dos_setvect(irq2int(tries[tri]),sb_test_irq);
- p8259_unmask(tries[tri]);
-
- /* wait for IRQ to show response (prior to triggering one) */
- _sti();
- maybe = 0;
- patience = 140;
- tolerance = 0;
- do {
- if (sb_test_irq_flag) {
- _cli();
- /* VDMSOUND bugfix: a previous invocation of this program without playing sound
- * leaves the IRQ primed and ready to trigger the instant this code tests again,
- * leading to false "Caught IRQ prior to DSP command" situations. It's sort of
- * like the "stuck IRQ" situation and Gravis Ultrasound cards. */
- if (tri == 0 && tolerance == 0) {
- sb_test_irq_flag = 0;
- tolerance++;
- patience = 250;
- _sti();
- }
- else {
- break;
- }
- }
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
-
- /* if the IRQ triggered between unmasking and NOW, then clearly it doesn't belong to the SB */
- if (sb_test_irq_flag) {
- eliminated |= 1U << tries[tri];
- DEBUG(fprintf(stdout,"Caught IRQ prior to DSP command, updating IRQ elimination: 0x%04x\n",eliminated));
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- continue;
- }
-
- /* make the SoundBlaster trigger an interrupt by playing a short sample block */
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8) | D8237_MASK_SET); /* mask */
- outp(D8237_REG_W_WRITE_MODE,
- D8237_MODER_CHANNEL(cx->dma8) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
- d8237_write_base(cx->dma8,dma->phys); /* RAM location with not much around */
- d8237_write_count(cx->dma8,testlen);
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8)); /* unmask */
-
- /* Time Constant */
- if (!sndsb_write_dsp_timeconst(cx,timeconst) || !sndsb_write_dsp(cx,0x14) ||
- !sndsb_write_dsp(cx,testlen-1) || !sndsb_write_dsp(cx,(testlen-1)>>8)) {
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8) | D8237_MASK_SET); /* unmask */
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- continue;
- }
-
- /* wait for IRQ to show response */
- _sti();
- maybe = 0;
- patience = 140;
- do {
- if (sb_test_irq_flag) {
- DEBUG(fprintf(stdout,"Flag with %ums to go for IRQ %d\n",patience,tries[tri]));
- _cli();
- sb_test_irq_flag = 0; /* immediately clear it */
- maybe = 1;
- break;
- }
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8) | D8237_MASK_SET); /* unmask */
-
- DEBUG(fprintf(stdout," maybe=%u\n",maybe));
- if (maybe == 0) {
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- continue;
- }
-
- if (!sndsb_reset_dsp(cx)) {
- DEBUG(fprintf(stdout,"WARNING: DSP reset failed, aborting IRQ probe\n"));
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- break;
- }
-
- /* wait for IRQ to show response (prior to triggering one) */
- _cli();
- sb_test_irq_flag = 0;
- _sti();
- maybe = 0;
- patience = 140;
- do {
- if (sb_test_irq_flag) break;
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
-
- /* if the IRQ triggered between unmasking and NOW, then clearly it doesn't belong to the SB */
- if (sb_test_irq_flag) {
- eliminated |= 1U << tries[tri];
- DEBUG(fprintf(stdout,"Caught IRQ prior to DSP command, updating IRQ elimination: 0x%04x\n",eliminated));
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- continue;
- }
-
- /* make the SoundBlaster trigger an interrupt by playing a short sample block */
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8) | D8237_MASK_SET); /* mask */
- outp(D8237_REG_W_WRITE_MODE,
- D8237_MODER_CHANNEL(cx->dma8) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
- d8237_write_base(cx->dma8,dma->phys); /* RAM location with not much around */
- d8237_write_count(cx->dma8,testlen);
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8)); /* unmask */
-
- /* Time Constant */
- if (!sndsb_write_dsp_timeconst(cx,timeconst) || !sndsb_write_dsp(cx,0x14) ||
- !sndsb_write_dsp(cx,testlen-1) || !sndsb_write_dsp(cx,(testlen-1)>>8)) {
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8) | D8237_MASK_SET); /* unmask */
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- continue;
- }
-
- /* wait for IRQ to show response */
- _sti();
- maybe = 0;
- patience = 140;
- do {
- if (sb_test_irq_flag) {
- DEBUG(fprintf(stdout,"Flag with %ums to go on IRQ %d\n",patience,tries[tri]));
- _cli();
- sb_test_irq_flag = 0; /* immediately clear it */
- maybe = 1;
- break;
- }
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(cx->dma8) | D8237_MASK_SET); /* unmask */
-
- DEBUG(fprintf(stdout," maybe2=%u\n",maybe));
- if (maybe == 0) {
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- continue;
- }
-
- if (!sndsb_reset_dsp(cx)) {
- DEBUG(fprintf(stdout,"WARNING: DSP reset failed, aborting IRQ probe\n"));
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
- break;
- }
-
- /* OK cleanup */
- p8259_mask(tries[tri]);
- _dos_setvect(irq2int(tries[tri]),old_irq);
-
- possible |= 1U << tries[tri];
- DEBUG(fprintf(stdout,"Possible=0x%04X\n",possible));
- }
- /* loop while we see possibilities, but more than one IRQ appears to be it */
- DEBUG(fprintf(stdout,"Round %u result: possible=0x%04x\n",possible));
- } while (possible != 0 && (possible&(possible-1)) != 0);
-
- if (possible != 0 && (possible&(possible-1)) == 0) {
- for (tri=0;tri < sizeof(tries);tri++) {
- if (possible & (1U << tries[tri])) {
- cx->irq = tries[tri];
- break;
- }
- }
- }
-
- /* release DMA buffer */
- dma_8237_free_buffer(dma);
-
- /* restore interrupt mask */
- _cli();
- p8259_write_mask(0,ml);
- p8259_write_mask(8,mh);
- _sti();
-#endif
-}
-
-/* On Sound Blaster cards prior to the SB16 the only way to autodetect the IRQ
- * was to cause a SB IRQ and watch the interrupt controller to see which one
- * went off. that's what this function does. */
-/* NTS: This doesn't work in some situations:
- * - Windows XP native Sound Blaster emulation under NTVDM.EXE
- * Workaround: use the SBLASTER environment variable given by NTVDM.EXE itself
- * - Sun/Oracle VirtualBox SB16 emulation (short DSP blocks fail to trigger IRQ activity)
- * Workaround: read the SB16 compatible mixer byte to obtain configuration
- * - Microsoft Virtual PC SB16 emulation (short DSP blocks fail to trigger IRQ activity)
- * Workaround: read the SB16 compatible mixer byte to obtain configuration */
-void sndsb_manual_probe_irq(struct sndsb_ctx *cx) {
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- /* too much code */
-#else
- unsigned int round = 0;
- unsigned char ml,mh,maybe;
- unsigned int patience = 0;
- unsigned short eliminated = 0U,irr,possible;
- unsigned char tries[] = {2,3,5,7,10},tri;
- DEBUG(fprintf(stdout,"Sound blaster IRQ unknown, I'm going to have to probe for it\n"));
-
- _cli();
- ml = p8259_read_mask(0); /* IRQ0-7 */
- mh = p8259_read_mask(8); /* IRQ8-15 */
- p8259_write_mask(0,0xFF); /* mask off all interrupts */
- p8259_write_mask(8,0xFF);
-
- /* wait a bit. during the wait, mark off any interrupts
- * that happen while we're waiting because they're obviously
- * not coming from the Sound Blaster */
- patience = 250;
- do {
- t8254_wait(t8254_us2ticks(1000));
- irr = (unsigned short)p8259_read_IRR(0);
- irr |= (unsigned short)p8259_read_IRR(8) << 8U;
- for (tri=0;tri < sizeof(tries);tri++) {
- if (irr & (1U << tries[tri])) {
- eliminated |= 1U << tries[tri];
- }
- }
- } while (--patience != 0);
- DEBUG(fprintf(stdout,"Pre-test IRQ elimination: 0x%04X\n",eliminated));
-
- /* restore interrupt mask */
- p8259_write_mask(0,ml);
- p8259_write_mask(8,mh);
- _sti();
-
- round = 0;
- do {
- if (++round >= 8)
- break;
-
- /* go through the remaining ones, one at a time */
- possible = 0;
- for (tri=0;tri < sizeof(tries);tri++) {
- if (eliminated & (1U << tries[tri]))
- continue;
- if (!sndsb_reset_dsp(cx)) {
- DEBUG(fprintf(stdout,"WARNING: DSP reset failed, aborting IRQ probe\n"));
- break;
- }
-
- DEBUG(fprintf(stdout," Now testing IRQ %u\n",tries[tri]));
-
- /* clear SoundBlaster's previous interrupt */
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS);
-
- _cli();
- p8259_write_mask(0,0xFF); /* mask off all interrupts */
- p8259_write_mask(8,0xFF);
-
- /* did this IRQ already trigger? then the SB didn't do it */
- irr = (unsigned short)p8259_read_IRR(tries[tri]);
- if (irr & (1 << (tries[tri] & 7))) {
- eliminated |= 1U << tries[tri];
- DEBUG(fprintf(stdout,"Caught IRQ prior to DSP command, updating IRQ elimination: 0x%04x\n",eliminated));
- continue;
- }
-
- /* make the SoundBlaster trigger an interrupt */
- if (!sndsb_write_dsp(cx,0xF2)) {
- if (!sndsb_write_dsp(cx,0xF2)) {
- DEBUG(fprintf(stdout,"WARNING: DSP write failed, aborting IRQ probe\n"));
- break;
- }
- }
-
- /* wait for IRQ to show response */
- maybe = 0;
- patience = 10;
- do {
- irr = (unsigned short)p8259_read_IRR(tries[tri]);
- if (irr & (1 << (tries[tri] & 7))) {
- maybe = 1;
- break;
- }
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
-
- DEBUG(fprintf(stdout," maybe=%u\n",maybe));
- if (maybe == 0)
- continue;
-
- /* restore interrupt mask */
- p8259_write_mask(0,ml);
- p8259_write_mask(8,mh);
- _sti();
-
- if (!sndsb_reset_dsp(cx)) {
- DEBUG(fprintf(stdout,"WARNING: DSP reset failed, aborting IRQ probe\n"));
- break;
- }
-
- /* clear SoundBlaster's previous interrupt */
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS);
-
- _cli();
- p8259_write_mask(0,0xFF); /* mask off all interrupts */
- p8259_write_mask(8,0xFF);
-
- /* did this IRQ already trigger? then the SB didn't do it */
- irr = (unsigned short)p8259_read_IRR(tries[tri]);
- if (irr & (1 << (tries[tri] & 7))) {
- eliminated |= 1U << tries[tri];
- DEBUG(fprintf(stdout,"Caught IRQ prior to DSP command, updating IRQ elimination: 0x%04x\n",eliminated));
- continue;
- }
-
- /* make the SoundBlaster trigger an interrupt */
- if (!sndsb_write_dsp(cx,0xF2)) {
- if (!sndsb_write_dsp(cx,0xF2)) {
- DEBUG(fprintf(stdout,"WARNING: DSP write failed, aborting IRQ probe\n"));
- break;
- }
- }
-
- /* wait for IRQ to show response */
- maybe = 0;
- patience = 10;
- do {
- irr = (unsigned short)p8259_read_IRR(tries[tri]);
- if (irr & (1 << (tries[tri] & 7))) {
- maybe = 1;
- break;
- }
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
-
- DEBUG(fprintf(stdout," maybe2=%u\n",maybe));
- if (maybe == 0)
- continue;
-
- possible |= 1U << tries[tri];
- }
- /* loop while we see possibilities, but more than one IRQ appears to be it */
- DEBUG(fprintf(stdout,"Round %u result: possible=0x%04x\n",possible));
- } while (possible != 0 && (possible&(possible-1)) != 0);
-
- if (possible != 0 && (possible&(possible-1)) == 0) {
- for (tri=0;tri < sizeof(tries);tri++) {
- if (possible & (1U << tries[tri])) {
- cx->irq = tries[tri];
- break;
- }
- }
- }
-
- /* restore interrupt mask */
- p8259_write_mask(0,ml);
- p8259_write_mask(8,mh);
- _sti();
-#endif
-}
-
-void sndsb_manual_probe_high_dma(struct sndsb_ctx *cx) {
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- /* too much code */
-#else
- /* NTS: Original code test-played 8192 bytes at 8KHz.
- * On every test machine, this meant a considerably long delay when probing.
- * To help speed it up, we now play a much shorter sample at 22KHz.
- * Unfortunately a sample playback block that short doesn't trigger an IRQ
- * under certain emulators like VirtualBox or Virtual PC. If we detect that we're
- * running under such emulators we then use a longer block size. */
- unsigned int testlen = 22050/20; /* 1/20th of a second */
- unsigned char tries[] = {5,6,7},tri;
- unsigned int srate = 22050;
- unsigned char dma_count_began = 0;
- unsigned char eliminated = 0;
- uint16_t prev[sizeof(tries)];
- unsigned int patience = 0,rem;
- struct dma_8237_allocation *dma;
- DEBUG(fprintf(stdout,"Sound blaster high DMA unknown, I'm going to have to probe for it\n"));
-
- if (windows_mode != WINDOWS_NT) {
- /* Sun/Oracle VirtualBox: Sound transfers that are too short are dropped without any
- * IRQ signal from the emulated SB16 card. Apparently this also has to do with a bug
- * in their DMA controller emulation where 'terminal count' is the original programmed
- * value rather than the 0xFFFF value most DMA controllers return. In other words,
- * we're compensating for VirtualBox's mediocre DMA emulation. */
- if (detect_virtualbox_emu()) {
- cx->virtualbox_emulation = 1;
- DEBUG(fprintf(stdout,"Setting test duration to longer period to work with VirtualBox\n"));
- testlen = 22050/5;
- }
- }
-
- /* sit back for a bit and watch the DMA channels. if any of them
- * are cycling, then they are active. NTS: Because the SB16 is
- * the only one using high DMA and it has a function to tell us
- * directly, we only probe the lower 8-bit channels */
- _cli();
- for (tri=0;tri < sizeof(tries);tri++) prev[tri] = d8237_read_count_lo16(tries[tri]);
- patience = 500;
- do {
- for (tri=0;tri < sizeof(tries);tri++) {
- if (eliminated & (1U << tries[tri]))
- continue;
- if (prev[tri] != d8237_read_count_lo16(tries[tri]))
- eliminated |= 1U << tries[tri];
- }
- } while (--patience != 0);
- DEBUG(fprintf(stdout,"Pre-test DMA elimination 0x%02x\n",eliminated));
-
- dma = dma_8237_alloc_buffer(testlen);
- if (dma != NULL) {
-#if TARGET_MSDOS == 32
- memset(dma->lin,0,testlen);
-#else
- _fmemset(dma->lin,0,testlen);
-#endif
-
- for (tri=0;tri < sizeof(tries);tri++) {
- if (eliminated & (1U << tries[tri]))
- continue;
- if (!sndsb_reset_dsp(cx))
- break;
-
- /* clear SoundBlaster's previous interrupt */
- /* note that some emulations of the card will fail to play the block
- * unless we clear the interrupt status. */
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS);
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS16);
-
- DEBUG(fprintf(stdout," Testing DMA channel %u\n",tries[tri]));
-
- /* set up the DMA channel */
- outp(d8237_ioport(tries[tri],D8237_REG_W_SINGLE_MASK),
- D8237_MASK_CHANNEL(tries[tri]) | D8237_MASK_SET); /* mask */
- outp(d8237_ioport(tries[tri],D8237_REG_W_WRITE_MODE),
- D8237_MODER_CHANNEL(tries[tri]) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
- d8237_write_base(tries[tri],dma->phys); /* RAM location with not much around */
- d8237_write_count(tries[tri],testlen);
- outp(d8237_ioport(tries[tri],D8237_REG_W_SINGLE_MASK),
- D8237_MASK_CHANNEL(tries[tri])); /* unmask */
-
- /* Time Constant */
- if (!sndsb_write_dsp_outrate(cx,srate))
- continue;
-
- /* play a short block */
- if (!sndsb_write_dsp(cx,0xB0|0x02)) continue; /* 16-bit single block FIFO on */
- if (!sndsb_write_dsp(cx,0x10)) continue; /* mono signed */
- if (!sndsb_write_dsp(cx,testlen)) continue;
- if (!sndsb_write_dsp(cx,testlen>>8)) continue;
- DEBUG(fprintf(stdout," DSP block started\n",tries[tri]));
-
- /* wait */
- dma_count_began = 0;
- patience = (unsigned int)(((unsigned long)testlen * 1500UL) / (unsigned long)srate);
- do {
- rem = d8237_read_count(tries[tri]);
- if (rem <= 2 || rem >= 0xFFFF) break; /* if below 2 or at terminal count */
-
- /* explanation: it turns out some emulation software doesn't quite do the DMA
- * controllers correctly: on terminal count their counter register reverts to
- * the value we originally set it to, rather than 0xFFFF. so to detect terminal
- * count we have to watch it count down, then return to 0xFFFF or to it's
- * original value.
- *
- * This hack is necessary to detect DMA cycling under Sun/Oracle VirtualBox */
- if (dma_count_began) {
- if (rem == testlen) {
- DEBUG(fprintf(stdout,
- "DMA controller snafu: Terminal count appears to be the original\n"
- "counter value, not the 0xFFFF value returned by most controllers.\n"
- "Expect other DOS programs to choke on it too!\n"));
- rem = 0;
- break;
- }
- }
- else {
- if (rem != testlen)
- dma_count_began = 1;
- }
-
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
- if (rem >= 0xFFFF) rem = 0; /* the DMA counter might return 0xFFFF when terminal count reached */
- outp(d8237_ioport(tries[tri],D8237_REG_W_SINGLE_MASK),
- D8237_MASK_CHANNEL(tries[tri]) | D8237_MASK_SET); /* mask */
- sndsb_reset_dsp(cx);
-
- /* clear SoundBlaster's previous interrupt */
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS);
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS16);
-
- if ((unsigned int)(rem+1) < testlen) { /* it moved, this must be the right one */
- DEBUG(fprintf(stdout," This one changed, must be the right one\n"));
- cx->dma16 = tries[tri];
- break;
- }
- }
-
- dma_8237_free_buffer(dma);
- }
-
- _sti();
-#endif
-}
-
-void sndsb_manual_probe_dma(struct sndsb_ctx *cx) {
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- /* too much code */
-#else
- /* NTS: Original code test-played 8192 bytes at 8KHz.
- * On every test machine, this meant a considerably long delay when probing.
- * To help speed it up, we now play a much shorter sample at 22KHz.
- * Unfortunately a sample playback block that short doesn't trigger an IRQ
- * under certain emulators like VirtualBox or Virtual PC. If we detect that we're
- * running under such emulators we then use a longer block size. */
- unsigned char timeconst = (unsigned char)((65536UL - (256000000UL / 22050UL)) >> 8UL);
- unsigned int testlen = 22050/20; /* 1/20th of a second */
- unsigned char tries[] = {0,1,3},tri;
- unsigned int srate = 22050;
- unsigned char dma_count_began = 0;
- unsigned char eliminated = 0;
- uint16_t prev[sizeof(tries)];
- unsigned int patience = 0,rem;
- struct dma_8237_allocation *dma;
- DEBUG(fprintf(stdout,"Sound blaster DMA unknown, I'm going to have to probe for it\n"));
-
- if (windows_mode != WINDOWS_NT) {
- /* Sun/Oracle VirtualBox: Sound transfers that are too short are dropped without any
- * IRQ signal from the emulated SB16 card. Apparently this also has to do with a bug
- * in their DMA controller emulation where 'terminal count' is the original programmed
- * value rather than the 0xFFFF value most DMA controllers return. In other words,
- * we're compensating for VirtualBox's mediocre DMA emulation. */
- if (detect_virtualbox_emu()) {
- cx->virtualbox_emulation = 1;
- DEBUG(fprintf(stdout,"Setting test duration to longer period to work with VirtualBox\n"));
- testlen = 22050/5;
- }
- }
-
- /* sit back for a bit and watch the DMA channels. if any of them
- * are cycling, then they are active. NTS: Because the SB16 is
- * the only one using high DMA and it has a function to tell us
- * directly, we only probe the lower 8-bit channels */
- _cli();
- for (tri=0;tri < sizeof(tries);tri++) prev[tri] = d8237_read_count_lo16(tries[tri]);
- patience = 500;
- do {
- for (tri=0;tri < sizeof(tries);tri++) {
- if (eliminated & (1U << tries[tri]))
- continue;
- if (prev[tri] != d8237_read_count_lo16(tries[tri]))
- eliminated |= 1U << tries[tri];
- }
- } while (--patience != 0);
- DEBUG(fprintf(stdout,"Pre-test DMA elimination 0x%02x\n",eliminated));
-
- dma = dma_8237_alloc_buffer(testlen);
- if (dma != NULL) {
-#if TARGET_MSDOS == 32
- memset(dma->lin,128,testlen);
-#else
- _fmemset(dma->lin,128,testlen);
-#endif
-
- /* then, initiate short playback tests to figure out which one */
- /* EMULATOR NOTES:
- * - Microsoft Virtual PC: works
- * - DOSBox: works
- * - Sun/Oracle VirtualBox: works
- *
- * Some emulators like VPC and VirtualBox are not concerned with
- * accurate emulation. Unfortunately for us this means any attempt
- * to play really short blocks would fail, because those emulators
- * would just drop the block and not fire the IRQ. */
- for (tri=0;tri < sizeof(tries);tri++) {
- if (eliminated & (1U << tries[tri]))
- continue;
- if (!(d8237_flags&D8237_DMA_SECONDARY) && tries[tri] >= 4)
- continue;
- if (!(d8237_flags&D8237_DMA_PRIMARY) && tries[tri] < 4)
- continue;
- if (!sndsb_reset_dsp(cx))
- break;
-
- /* clear SoundBlaster's previous interrupt */
- /* note that some emulations of the card will fail to play the block
- * unless we clear the interrupt status. */
- inp(cx->baseio+SNDSB_BIO_DSP_READ_STATUS);
-
- DEBUG(fprintf(stdout," Testing DMA channel %u\n",tries[tri]));
-
- /* set up the DMA channel */
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(tries[tri]) | D8237_MASK_SET); /* mask */
- outp(D8237_REG_W_WRITE_MODE,
- D8237_MODER_CHANNEL(tries[tri]) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) |
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_SINGLE));
- d8237_write_base(tries[tri],dma->phys); /* RAM location with not much around */
- d8237_write_count(tries[tri],testlen);
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(tries[tri])); /* unmask */
-
- /* Time Constant */
- if (!sndsb_write_dsp_timeconst(cx,timeconst))
- continue;
-
- /* play a short block */
- if (!sndsb_write_dsp(cx,0x14)) continue;
- if (!sndsb_write_dsp(cx,testlen-1)) continue;
- if (!sndsb_write_dsp(cx,(testlen-1)>>8)) continue;
- DEBUG(fprintf(stdout," DSP block started\n",tries[tri]));
-
- /* wait */
- dma_count_began = 0;
- patience = (unsigned int)(((unsigned long)testlen * 1500UL) / (unsigned long)srate);
- do {
- rem = d8237_read_count(tries[tri]);
- if (rem <= 2 || rem >= 0xFFFF) break; /* if below 2 or at terminal count */
-
- /* explanation: it turns out some emulation software doesn't quite do the DMA
- * controllers correctly: on terminal count their counter register reverts to
- * the value we originally set it to, rather than 0xFFFF. so to detect terminal
- * count we have to watch it count down, then return to 0xFFFF or to it's
- * original value.
- *
- * This hack is necessary to detect DMA cycling under Sun/Oracle VirtualBox */
- if (dma_count_began) {
- if (rem == testlen) {
- DEBUG(fprintf(stdout,
- "DMA controller snafu: Terminal count appears to be the original\n"
- "counter value, not the 0xFFFF value returned by most controllers.\n"
- "Expect other DOS programs to choke on it too!\n"));
- rem = 0;
- break;
- }
- }
- else {
- if (rem != testlen)
- dma_count_began = 1;
- }
-
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
- if (rem >= 0xFFFF) rem = 0; /* the DMA counter might return 0xFFFF when terminal count reached */
- outp(D8237_REG_W_SINGLE_MASK,D8237_MASK_CHANNEL(tries[tri]) | D8237_MASK_SET); /* mask */
- sndsb_reset_dsp(cx);
-
- if ((unsigned int)(rem+1) < testlen) { /* it moved, this must be the right one */
- DEBUG(fprintf(stdout," This one changed, must be the right one\n"));
- cx->dma8 = tries[tri];
- break;
- }
- }
-
- dma_8237_free_buffer(dma);
- }
-
- _sti();
-#endif
-}
-
-/* this is for taking a base address and probing the I/O ports there to see if something like a SB DSP is there. */
-/* it is STRONGLY recommended that you don't do this unless you try only 0x220 or 0x240 and you know that nothing
- * else important is there */
-int sndsb_try_base(uint16_t iobase) {
- struct sndsb_ctx *cx;
-
- if ((iobase&0xF) != 0)
- return 0;
- if (iobase < 0x210 || iobase > 0x270)
- return 0;
- if (sndsb_by_base(iobase) != NULL)
- return 0;
-
- /* some of our detection relies on knowing what OS we're running under */
- cpu_probe();
- probe_dos();
- detect_windows();
-
- cx = sndsb_alloc_card();
- if (cx == NULL) return 0;
-
- DEBUG(fprintf(stdout,"sndsb_try_base(0x%03X)\n",iobase));
-
- cx->baseio = iobase;
- cx->dma8 = cx->dma16 = cx->irq = -1; /* NTS: zero HERE, the init card routine might figure them out */
- if (!sndsb_init_card(cx)) {
- DEBUG(fprintf(stdout,"failed to init card\n"));
- sndsb_free_card(cx);
- return 0;
- }
-
- /* if we still have to figure out the IRQ, and it's not PnP then probe around to figure it out */
- if (cx->dsp_ok && !cx->is_gallant_sc6600 && !cx->do_not_probe_irq && cx->pnp_id == 0 && cx->irq == -1 &&
- windows_mode == WINDOWS_NONE && !sndsb_probe_options.disable_manual_irq_probing)
- sndsb_manual_probe_irq(cx);
-
- /* if we have to, detect the DMA channel. */
- if (cx->dsp_ok && !cx->is_gallant_sc6600 && !cx->do_not_probe_dma && cx->pnp_id == 0 && cx->dma8 == -1 &&
- !sndsb_probe_options.disable_manual_dma_probing)
- sndsb_manual_probe_dma(cx);
- /* and the high DMA channel too, if a SB16 or compatible. */
- if (cx->dsp_ok && !cx->is_gallant_sc6600 && !cx->do_not_probe_dma && cx->pnp_id == 0 && cx->dma16 == -1 &&
- cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_4xx && !sndsb_probe_options.disable_manual_high_dma_probing)
- sndsb_manual_probe_high_dma(cx);
-
- /* if we still have to figure out the IRQ, then probe around to figure it out */
- if (cx->dsp_ok && !cx->is_gallant_sc6600 && !cx->do_not_probe_irq && cx->pnp_id == 0 && cx->irq == -1 &&
- !sndsb_probe_options.disable_alt_irq_probing)
- sndsb_alt_lite_probe_irq(cx);
-
- /* If an ESS chipset, there's a good chance that 16-bit PCM is played over the 8-bit DMA channel */
- if (cx->ess_extensions && cx->dma16 < 0 && cx->dma8 >= 0)
- cx->dma16 = cx->dma8;
-
- sndsb_determine_ideal_dsp_play_method(cx);
- return 1;
-}
-
-int sndsb_interrupt_reason(struct sndsb_ctx *cx) {
- if (cx->dsp_vmaj >= 4) {
- /* Sound Blaster 16: We can read a mixer byte to determine why the interrupt happened */
- /* bit 0: 1=8-bit DSP or MIDI */
- /* bit 1: 1=16-bit DSP */
- /* bit 2: 1=MPU-401 */
- return sndsb_read_mixer(cx,0x82) & 7;
- }
- else if (cx->ess_extensions) {
- return cx->buffer_16bit ? 2 : 1;
- }
-
- /* DSP 3.xx and earlier: just assume the interrupt happened because of the DSP */
- return 1;
-}
-
-int sndsb_reset_mixer(struct sndsb_ctx *cx) {
- if (cx->baseio == 0)
- return 0;
-
- sndsb_write_mixer(cx,0x00,0x00); /* "write any 8-bit value to reset the chip" */
- return 1;
-}
-
-/* general main loop idle function. does nothing, unless we're playing with no IRQ,
- * in which case we're expected to poll IRQ status */
-void sndsb_main_idle(struct sndsb_ctx *cx) {
- unsigned int oflags;
-
- oflags = get_cpu_flags();
- _cli();
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->timer_tick_signal) {
- /* DSP "nag" mode: when the host program's IRQ handler called our timer tick callback, we
- * noted it so that at idle() we can nag the DSP at moderate intervals. Note that nag mode
- * only makes sense when autoinit DMA is in use, otherwise we risk skipping popping and
- * crackling. We also don't nag if the DSP is doing auto-init playback, because it makes
- * no sense to do so.
- *
- * The idea is to mimic for testing purposes the DSP "nagging" technique used by the
- * Triton Crystal Dreams demo that allow it to do full DMA playback Goldplay style
- * without needing to autodetect what IRQ the card is on. The programmer did not
- * write the code to use auto-init DSP commands. Instead, the demo uses the single
- * cycle DSP playback command (1.xx commands) with the DMA settings set to one sample
- * wide (Goldplay style), then, from the same IRQ 0 handler that does the music,
- * polls the DSP write status register to check DSP busy state. If the DSP is not busy,
- * it counts down a timer internally on each IRQ 0, then when it hits zero, begins
- * sending another DSP playback block (DSP command 0x14,xx,xx). It does this whether
- * or not the last DSP 0x14 command has finished playing or not, thus, "nagging" the
- * DSP. The upshot of this bizarre technique is that it doesn't need to pay any
- * attention to the Sound Blaster IRQ. The downside, of course, is that later
- * "emulations" of the Sound Blaster don't recognize the technique and playback will
- * not work properly like that.
- *
- * The other reason to use such a technique is to avoid artifacts caused by the amount
- * of time it takes the signal an IRQ vs the CPU to program another single-cycle block
- * (longer than one sample period), since nagging the DSP ensures it never stops despite
- * the single-cycle mode it's in. The side effect of course is that since the DSP is
- * never given a chance to complete a whole block, it never fires the IRQ! */
- if (cx->dsp_nag_mode && sndsb_will_dsp_nag(cx))
- sndsb_send_buffer_again(cx);
-
- cx->timer_tick_signal = 0;
- }
- if (oflags & 0x200/* if interrupts were enabled */) _sti();
-
- /* if DMA based playback and no IRQ assigned, then we need to poll the ack register to keep
- * playback from halting on SB16 hardware. Clones and SBpro and earlier don't seem to care. */
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->irq < 0 && cx->poll_ack_when_no_irq)
- sndsb_interrupt_ack(cx,3);
-}
-
-/* we can do output method. if we can't, then don't bother playing, because it flat out won't work.
- * if we can, then you want to check if it's supported, because if it's not, you may get weird results, but nothing catastrophic. */
-int sndsb_dsp_out_method_can_do(struct sndsb_ctx *cx,unsigned long wav_sample_rate,unsigned char wav_stereo,unsigned char wav_16bit) {
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-# define MSG(x) cx->reason_not_supported = x
-#else
-# define MSG(x)
- cx->reason_not_supported = "";
-#endif
-
- if (!cx->dsp_ok) {
- MSG("DSP not detected");
- return 0; /* No DSP, no playback */
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_MAX) {
- MSG("play method out of range");
- return 0; /* invalid DSP output method */
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && !wav_16bit && cx->dma8 < 0) {
- MSG("DMA-based playback, 8-bit PCM, no channel assigned (dma8)");
- return 0;
- }
-
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx && cx->ess_extensions) {
- /* OK. we can use ESS extensions with flipped sign */
- }
- else if (cx->dsp_play_method < SNDSB_DSPOUTMETHOD_4xx && cx->audio_data_flipped_sign) {
- MSG("Flipped sign playback requires DSP 4.xx playback");
- return 0;
- }
-
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx && cx->ess_extensions) {
- /* OK. we can use ESS extensions to do 16-bit playback */
- }
- else if (cx->dsp_play_method < SNDSB_DSPOUTMETHOD_4xx && wav_16bit) {
- MSG("16-bit PCM playback requires DSP 4.xx mode");
- return 0;
- }
-
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && wav_16bit && cx->dma16 < 0) {
- MSG("DMA-based playback, 16-bit PCM, no channel assigned (dma16)");
- return 0;
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && wav_16bit && cx->dma16 >= 4 && !(d8237_flags&D8237_DMA_SECONDARY)) {
- MSG("DMA-based playback, 16-bit PCM, dma16 channel refers to\nnon-existent secondary DMA controller");
- return 0;
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && wav_16bit && cx->dma16 >= 0 && cx->dma16 < 4 && !(d8237_flags&D8237_DMA_PRIMARY)) {
- MSG("DMA-based playback, 16-bit PCM, dma16 channel refers to\nnon-existent primary DMA controller");
- return 0;
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && !wav_16bit && cx->dma8 >= 4 && !(d8237_flags&D8237_DMA_SECONDARY)) { /* as if this would ever happen, but.. */
- MSG("DMA-based playback, 8-bit PCM, dma8 channel refers to\nnon-existent secondary DMA controller");
- return 0;
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && !wav_16bit && cx->dma8 >= 0 && cx->dma8 < 4 && !(d8237_flags&D8237_DMA_PRIMARY)) {
- MSG("DMA-based playback, 8-bit PCM, dma8 channel refers to\nnon-existent primary DMA controller");
- return 0;
- }
-
- if (cx->dsp_adpcm > 0) {
- if (cx->dsp_record) {
- MSG("No such thing as ADPCM recording");
- return 0;
- }
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) {
- MSG("No such thing as direct DAC ADPCM playback");
- return 0;
- }
- if (wav_16bit) {
- MSG("No such thing as 16-bit ADPCM playback");
- return 0;
- }
- if (wav_stereo) {
- MSG("No such thing as stereo ADPCM playback");
- return 0;
- }
- if (cx->audio_data_flipped_sign) {
- MSG("No such thing as flipped sign ADPCM playback");
- return 0;
- }
- if (cx->goldplay_mode) {
- MSG("Goldplay ADPCM playback not supported");
- return 0;
- }
- }
- else if (cx->goldplay_mode) {
-#if TARGET_MSDOS == 16
- /* bug-check: goldplay 16-bit DMA is not possible if somehow the goldplay_dma[] field is not WORD-aligned
- * and 16-bit audio is using the 16-bit DMA channel (misaligned while 8-bit DMA is fine) */
- if (cx->buffer_16bit && cx->dma16 >= 4 && ((unsigned int)(cx->goldplay_dma))&1) {
- MSG("16-bit PCM Goldplay playback requested\nand DMA buffer is not word-aligned.");
- return 0;
- }
-#endif
- }
-
-# if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- cx->reason_not_supported = NULL;
-# endif
- return 1;
-#undef MSG
-}
-
-unsigned int sndsb_will_dsp_nag(struct sndsb_ctx *cx) {
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT)
- return 0;
-
- if (cx->chose_autoinit_dma && !cx->chose_autoinit_dsp) {
- /* NTS: Do not nag the DSP when it's in "highspeed" DMA mode. Normal DSPs cannot accept
- * commands in that state and any attempt will cause this function to hang for the
- * DSP timeout period causing the main loop to jump and stutter. But if the user
- * really *wants* us to do it (signified by setting dsp_nag_highspeed) then we'll do it */
- if (cx->dsp_play_method < SNDSB_DSPOUTMETHOD_4xx && cx->buffer_hispeed && cx->hispeed_matters && cx->hispeed_blocking && !cx->dsp_nag_hispeed)
- return 0;
- }
-
- return 1;
-}
-
-/* meant to be called from an IRQ */
-void sndsb_irq_continue(struct sndsb_ctx *cx,unsigned char c) {
- if (cx->dsp_nag_mode) {
- /* if the main loop is nagging the DSP then we shouldn't do anything */
- if (sndsb_will_dsp_nag(cx)) return;
- }
-
- /* only call send_buffer_again if 8-bit DMA completed
- and bit 0 set, or if 16-bit DMA completed and bit 1 set */
- if ((c & 1) && !cx->buffer_16bit)
- sndsb_send_buffer_again(cx);
- else if ((c & 2) && cx->buffer_16bit)
- sndsb_send_buffer_again(cx);
-}
-
-/* output method is supported (as in, recommended) */
-int sndsb_dsp_out_method_supported(struct sndsb_ctx *cx,unsigned long wav_sample_rate,unsigned char wav_stereo,unsigned char wav_16bit) {
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-# define MSG(x) cx->reason_not_supported = x
-#else
-# define MSG(x)
- cx->reason_not_supported = "";
-#endif
-
- if (!sndsb_dsp_out_method_can_do(cx,wav_sample_rate,wav_stereo,wav_16bit))
- return 0;
-
- if (cx->dsp_play_method < SNDSB_DSPOUTMETHOD_4xx && wav_sample_rate < 4000) {
- MSG("Non-SB16 playback below 4000Hz probably not going to work");
- return 0;
- }
- if (cx->dsp_alias_port && cx->dsp_vmaj > 2) {
- MSG("DSP alias I/O ports only exist on original Sound Blaster\nDSP 1.xx and 2.xx");
- return 0;
- }
-
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_4xx) {
- if (cx->is_gallant_sc6600) {
- if (cx->dsp_vmaj < 3) {
- MSG("DSP 4.xx playback requires SB16 or clone [SC-6000]");
- return 0;
- }
- }
- else {
- if (cx->dsp_vmaj < 4) {
- MSG("DSP 4.xx playback requires SB16");
- return 0;
- }
- }
- }
-
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->goldplay_mode && !cx->dsp_autoinit_dma) {
- MSG("Goldplay mode requires auto-init DMA to work properly");
- return 0;
- }
- if (cx->dsp_autoinit_command && cx->dsp_vmaj < 2) {
- MSG("Auto-init DSP command support requires DSP 2.0 or higher");
- return 0;
- }
- if ((cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT || cx->goldplay_mode) && cx->windows_emulation) {
- MSG("Direct mode or goldplay mode not recommended\nfor use within a Windows DOS box, it won't work");
- return 0;
- }
-
- if (wav_stereo && cx->dsp_vmaj < 3) {
- MSG("You are playing stereo audio on a DSP that doesn't support stereo");
- return 0;
- }
-
- if (wav_stereo && cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->dsp_play_method < SNDSB_DSPOUTMETHOD_3xx) {
- MSG("You are playing stereo audio in a DSP mode\nthat doesn't support stereo");
- return 0;
- }
- if (wav_stereo && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) {
- MSG("Direct DAC mode does not support stereo");
- return 0;
- }
-
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_201 &&
- (cx->dsp_vmaj < 2 || (cx->dsp_vmaj == 2 && cx->dsp_vmin == 0))) {
- MSG("DSP 2.01+ or higher playback requested for DSP older than v2.01");
- return 0;
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_200 && cx->dsp_vmaj < 2) {
- MSG("DSP 2.0 or higher playback requested for DSP older than v2.0");
- return 0;
- }
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->dsp_vmaj < 1) {
- MSG("DSP 1.xx or higher playback requested for\na DSP who's version I can't determine");
- return 0;
- }
-
- /* this library can play DMA without an IRQ channel assigned, but there are some restrictions on doing so */
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->irq < 0) {
- /* we can do it if auto-init DMA and auto-init DSP and we poll the ack register (best for SB16).
- * for pre-SB16, we can ignore the IRQ and playback will continue anyway. */
- if (cx->dsp_autoinit_dma && cx->dsp_autoinit_command &&
- ((cx->dsp_adpcm > 0 && cx->enable_adpcm_autoinit) || cx->dsp_adpcm == 0) &&
- (cx->poll_ack_when_no_irq || cx->dsp_vmaj < 4) &&
- !(cx->vdmsound || cx->windows_xp_ntvdm || cx->windows_9x_me_sbemul_sys)) {
- /* yes */
- }
- /* we can do it if auto-init DMA and single-cycle DSP and we're nagging the DSP */
- else if (cx->dsp_nag_mode && sndsb_will_dsp_nag(cx)) {
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_4xx) {
- /* yes */
- }
- else if ((cx->force_hispeed || (wav_sample_rate*(wav_stereo?2:1)) > (cx->dsp_record ? 13000UL : 23000UL)) && cx->hispeed_blocking) {
- /* no */
- MSG("No IRQ assigned & DSP nag mode is ineffective\nif the DSP will run in 2.0/Pro highspeed DSP mode.");
- return 0;
- }
- else {
- /* yes */
- }
- }
- else {
- /* anything else is iffy */
- MSG("No IRQ assigned, no known combinations are selected that\n"
- "allow DSP playback to work. Try DSP auto-init with Poll ack\n"
- "or DSP single-cycle with nag mode enabled.");
- return 0;
- }
- }
-
- if (cx->dsp_nag_mode) {
- /* nag mode can cause problems with DSP 4.xx commands? */
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_4xx) {
- MSG("DSP nag mode on a SB16 in DSP 4.xx mode can cause problems.\n"
- "Halting, popping/cracking, stereo L/R swapping timing glitches.\n"
- "Use DSP auto-init and non-IRQ polling for more reliable DMA.");
- return 0;
- }
- /* nag mode can cause lag from the idle command if hispeed mode is involved */
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_201 && cx->hispeed_matters && cx->hispeed_blocking &&
- cx->dsp_nag_hispeed && (cx->force_hispeed || (wav_sample_rate*(wav_stereo?2:1)) > (cx->dsp_record ? 13000UL : 23000UL))) {
- MSG("DSP nag mode when hispeed DSP playback is involved can cause\n"
- "lagging and delay on this system because the DSP will block during playback");
- return 0;
- }
- }
-
- MSG("Target sample rate out of range");
- if (cx->dsp_adpcm > 0) {
- /* Neither VDMSOUND.EXE or NTVDM's SB emulation handle ADPCM well */
- if (cx->vdmsound || cx->windows_xp_ntvdm || cx->windows_9x_me_sbemul_sys) {
- MSG("You are attempting ADPCM within Windows\nemulation that will likely not support ADPCM playback");
- return 0;
- }
-
- /* Gallant SC-6600 clones do not support auto-init ADPCM, though they support all modes */
- if (cx->is_gallant_sc6600 && cx->enable_adpcm_autoinit && cx->dsp_autoinit_command) {
- MSG("SC-6600 SB clones do not support auto-init ADPCM");
- return 0;
- }
-
- /* NTS: If we could easily differentiate Creative SB 2.0 from clones, we could identify the
- * slightly out-of-spec ranges supported by the SB 2.0 that deviates from Creative
- * documentation */
- if (cx->dsp_adpcm == ADPCM_4BIT) {
- if (wav_sample_rate > 12000UL) return 0;
- }
- else if (cx->dsp_adpcm == ADPCM_2_6BIT) {
- if (wav_sample_rate > 13000UL) return 0;
- }
- else if (cx->dsp_adpcm == ADPCM_2BIT) {
- if (wav_sample_rate > 11000UL) return 0; /* NTS: On actual Creative SB 2.0 hardware, this can apparently go up to 15KHz */
- }
- else {
- return 0;
- }
- }
- else if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_4xx) {
- /* based on Sound Blaster 16 PnP cards that max out at 48000Hz apparently */
- /* FIXME: Is there a way for us to distinguish a Sound Blaster 16 (max 44100Hz)
- * from later cards (max 48000Hz) *other* than whether or not it is Plug & Play?
- * Such as using the DSP version? At what DSP version did the card go from
- * a max 44100Hz to 48000Hz? */
- if (wav_sample_rate > cx->max_sample_rate_dsp4xx) return 0;
- }
- else if (cx->ess_extensions && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) {
- /* I've been able to drive ESS chips up to 48Khz and beyond (though beyond 48KHz 16-bit stereo
- * the ISA bus can't keep up well). But let's cap it at 48KHz anyway */
- if (wav_sample_rate > 48000) return 0;
- }
- else if ((!cx->hispeed_matters && cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx) ||
- cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx || cx->dsp_play_method == SNDSB_DSPOUTMETHOD_201) {
- /* Because of the way Sound Blaster Pro stereo works and the way the time constant
- * is generated, the maximum sample rate is halved in stereo playback. On Pro and
- * old SB16 cards this means a max of 44100Hz mono 22050Hz stereo. On SB16 ViBRA
- * cards, this usually means a maximum of 48000Hz mono 24000Hz stereo.
- *
- * For DSP 2.01+ support, we also use this calculation because hispeed mode is involved */
- if (wav_sample_rate > ((cx->dsp_record ? cx->max_sample_rate_sb_hispeed : cx->max_sample_rate_sb_hispeed) / (wav_stereo ? 2U : 1U))) return 0;
- }
- else if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_200 || cx->dsp_play_method == SNDSB_DSPOUTMETHOD_1xx) {
- if (wav_sample_rate > (cx->dsp_record ? cx->max_sample_rate_sb_rec : cx->max_sample_rate_sb_play)) return 0;
- }
- else if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) {
- if (wav_sample_rate > (cx->dsp_record ? cx->max_sample_rate_sb_rec_dac : cx->max_sample_rate_sb_play_dac)) return 0;
- }
- MSG(NULL);
- /* Creative SB16 cards do not pay attention to the Sound Blaster Pro stereo bit.
- * Playing stereo using the 3xx method on 4.xx DSPs will not work. Most SB16 clones
- * will pay attention to that bit however, but it's best not to assume that will happen. */
- if (cx->dsp_vmaj >= 4 && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx && wav_stereo) {
- MSG("Sound Blaster Pro stereo playback on SB16 (DSP 4.xx)\nwill not play as stereo because Creative SB16\ncards ignore the mixer bit");
- return 0;
- }
- /* SB16 cards seem to alias hispeed commands to normal DSP and let them set the time constant all the way up to the max supported by
- * the DSP, hispeed mode or not. */
- if (cx->dsp_vmaj >= 4 && (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_201 || cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) && cx->hispeed_matters) {
- MSG("Sound Blaster 2.0/Pro high-speed DSP modes not\nrecommended for use on your DSP (DSP 4.xx detected)");
- return 0;
- }
- /* friendly reminder to the user that despite DSP autoinit enable 1.xx commands are not auto-init */
- if (cx->dsp_autoinit_command && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_1xx) {
- MSG("DSP 1.xx commands do not support auto-init. Playback\nis automatically using single-cycle commands instead.");
- return 1; /* we support it, but just to let you know... */
- }
- /* playing DMA backwards with 16-bit audio is not advised.
- * it COULD theoretically work with a 16-bit DMA channel because of how it counts, but...
- * there's also the risk you use an 8-bit DMA channel which of course gets the byte order wrong! */
- if (cx->backwards && wav_16bit) {
- MSG("16-bit PCM played backwards is not recommended\nbyte order may not be correct to sound card");
- return 0;
- }
- /* it's also a good bet Windows virtualization never even considers DMA in decrement mode because nobody really ever uses it */
- if (cx->backwards && cx->windows_emulation) {
- MSG("DMA played backwards is not recommended from\nwithin a Windows DOS box");
- return 0;
- }
- /* EMM386.EXE seems to handle backwards DMA just fine, but we can't assume v86 monitors handle it well */
-#if TARGET_MSDOS == 32
- if (cx->backwards && dos_ltp_info.paging && dos_ltp_info.dma_dos_xlate) {
-#else
- if (cx->backwards && (cpu_flags&CPU_FLAG_V86_ACTIVE)) {
-#endif
- MSG("DMA played backwards is not recommended from\nwithin a virtual 8086 mode monitor");
- return 0;
- }
-
- /* NTS: Virtualbox supports backwards DMA, it's OK */
-
-# if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- cx->reason_not_supported = NULL;
-# endif
- return 1;
-#undef MSG
-}
-
-int sndsb_write_dsp_blocksize(struct sndsb_ctx *cx,uint16_t tc) {
- if (!sndsb_write_dsp(cx,0x48))
- return 0;
- if (!sndsb_write_dsp(cx,tc-1))
- return 0;
- if (!sndsb_write_dsp(cx,(tc-1)>>8))
- return 0;
- return 1;
-}
-
-int sndsb_write_dsp_outrate(struct sndsb_ctx *cx,unsigned long rate) {
- if (!sndsb_write_dsp(cx,0x41))
- return 0;
- if (!sndsb_write_dsp(cx,rate>>8)) /* Ugh, Creative, be consistent! */
- return 0;
- if (!sndsb_write_dsp(cx,rate))
- return 0;
- return 1;
-}
-
-uint32_t sndsb_read_dma_buffer_position(struct sndsb_ctx *cx) {
- uint32_t r;
-
- /* the program is asking for DMA position. If we're doing the Windows springwait hack,
- * then NOW is the time to initialize DSP transfer! */
- if (cx->windows_emulation && cx->windows_springwait == 1 && cx->windows_xp_ntvdm) {
- sndsb_prepare_dsp_playback(cx,cx->buffer_rate,cx->buffer_stereo,cx->buffer_16bit);
- sndsb_setup_dma(cx);
- sndsb_begin_dsp_playback(cx);
- cx->windows_springwait = 2;
- }
-
- /* "direct" and "goldplay" methods require the program to update the play point in some fashion,
- * usually by programming IRQ 0 to tick at the sample rate */
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT || cx->goldplay_mode) {
- r = cx->direct_dsp_io;
- if (r >= cx->buffer_size) r = cx->buffer_size - 1;
- }
- else if (cx->buffer_16bit) {
- if (cx->dma16 < 0) return 0;
- r = d8237_read_count(cx->dma16);
- if (cx->backwards) {
- /* TODO */
- }
- else {
- if (r >= 0xFFFEUL) r = 0; /* FIXME: the 8237 library should have a "is terminal count" function */
- if (r >= cx->buffer_dma_started_length) r = cx->buffer_dma_started_length - 1;
- r = cx->buffer_dma_started_length - (r+1);
- r += cx->buffer_dma_started;
- }
- }
- else {
- if (cx->dma8 < 0) return 0;
- r = d8237_read_count(cx->dma8);
- if (cx->backwards) {
- if (r >= 0xFFFFUL) r = 0;
- if (r >= cx->buffer_dma_started_length) r = cx->buffer_dma_started_length - 1;
- r += cx->buffer_dma_started;
- }
- else {
- if (r >= 0xFFFFUL) r = 0;
- if (r >= cx->buffer_dma_started_length) r = cx->buffer_dma_started_length - 1;
- r = cx->buffer_dma_started_length - (r+1);
- r += cx->buffer_dma_started;
- }
- }
-
- return r;
-}
-
-int sndsb_shutdown_dma(struct sndsb_ctx *cx) {
- unsigned char ch = cx->buffer_16bit ? cx->dma16 : cx->dma8;
- if ((signed char)ch == -1) return 0;
- /* set up the DMA channel */
- outp(d8237_ioport(ch,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(ch) | D8237_MASK_SET); /* mask */
- return 1;
-}
-
-int sndsb_setup_dma(struct sndsb_ctx *cx) {
- unsigned char ch = cx->buffer_16bit ? cx->dma16 : cx->dma8;
- unsigned char dma_mode = D8237_MODER_MODESEL_SINGLE;
-
- /* ESS bugfix: except for goldplay mode, we tell the chipset to use demand mode fetching.
- * So then, setup the DMA controller for it too! */
- if (cx->ess_extensions && !cx->goldplay_mode)
- dma_mode = D8237_MODER_MODESEL_DEMAND;
-
- /* if we're doing the Windows "spring" buffer hack, then don't do anything.
- * later when the calling program queries the DMA position, we'll setup DSP playback and call this function again */
- if (cx->windows_emulation && cx->windows_springwait == 0 && cx->windows_xp_ntvdm)
- return 1;
-
- if (cx->backwards)
- cx->direct_dsp_io = cx->buffer_size - 1;
- else
- cx->direct_dsp_io = 0;
-
- if ((signed char)ch == -1) return 0;
- /* set up the DMA channel */
- outp(d8237_ioport(ch,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(ch) | D8237_MASK_SET); /* mask */
-
- outp(d8237_ioport(ch,D8237_REG_W_WRITE_MODE),
- (cx->chose_autoinit_dma ? D8237_MODER_AUTOINIT : 0) |
- (cx->backwards ? D8237_MODER_ADDR_DEC : 0) |
- D8237_MODER_CHANNEL(ch) |
- D8237_MODER_TRANSFER(cx->dsp_record ? D8237_MODER_XFER_WRITE : D8237_MODER_XFER_READ) |
- D8237_MODER_MODESEL(dma_mode));
-
- if (cx->goldplay_mode) {
- /* goldplay mode REQUIRES auto-init DMA */
- if (!cx->chose_autoinit_dma) return -1;
-
- cx->gold_memcpy = (cx->buffer_16bit?2:1)*(cx->buffer_stereo?2:1);
-
-#if TARGET_MSDOS == 32
- if (cx->goldplay_dma == NULL) {
- if ((cx->goldplay_dma=dma_8237_alloc_buffer(16)) == NULL)
- return 0;
- }
-#endif
-
- /* Goldplay mode: The size of ONE sample is given to the DMA controller.
- * This tricks the DMA controller into re-transmitting that sample continuously
- * to the sound card. Then the demo uses the timer interrupt to modify that byte
- * and make audio. This was apparently popular with Goldplay in the 1991-1993
- * demoscene time frame, and evidently worked fine, but on today's PCs with CPU
- * caches and buffers this crap would obviously never fly.
- *
- * Note we allow the program to do this with 16-bit output, even though the
- * original Goldplay library was limited to 8 and nobody ever did this kind of
- * hackery by the time 16-bit SB output was the norm. But my test code shows
- * that you can pull that stunt with stereo and 16-bit audio modes too! */
- d8237_write_count(ch,(cx->buffer_stereo ? 2 : 1)*(cx->buffer_16bit ? 2 : 1));
- /* point it to our "goldplay_dma" */
-#if TARGET_MSDOS == 32
- d8237_write_base(ch,cx->goldplay_dma->phys + (cx->backwards ? (cx->gold_memcpy-1) : 0));
-
- if ((cx->buffer_16bit?1:0)^(cx->audio_data_flipped_sign?1:0))
- memset(cx->goldplay_dma->lin,0,4);
- else
- memset(cx->goldplay_dma->lin,128,4);
-#else
- {
- unsigned char far *p = (unsigned char far*)(cx->goldplay_dma);
- d8237_write_base(ch,((uint32_t)FP_SEG(p) << 4UL) + (uint32_t)FP_OFF(p) + (cx->backwards ? (cx->gold_memcpy-1) : 0));
-
- if ((cx->buffer_16bit?1:0)^(cx->audio_data_flipped_sign?1:0))
- _fmemset(p,0,4);
- else
- _fmemset(p,128,4);
- }
-#endif
- }
- else {
- d8237_write_count(ch,cx->buffer_dma_started_length);
- if (cx->backwards)
- d8237_write_base(ch,cx->buffer_phys+cx->buffer_dma_started+cx->buffer_dma_started_length-1);
- else
- d8237_write_base(ch,cx->buffer_phys+cx->buffer_dma_started); /* RAM location with not much around */
- }
-
- outp(d8237_ioport(ch,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(ch)); /* unmask */
- return 1;
-}
-
-unsigned long sndsb_real_sample_rate(struct sndsb_ctx *cx) {
- unsigned long total_rate;
- unsigned char timeconst;
- unsigned long real_rate;
-
- total_rate = (unsigned long)cx->buffer_rate * (cx->buffer_stereo ? 2UL : 1UL);
- if (total_rate < 4000UL) total_rate = 4000UL;
- timeconst = (unsigned char)((65536UL - (256000000UL / total_rate)) >> 8UL);
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_4xx) return cx->buffer_rate;
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) return cx->buffer_rate;
-
- /* 256 - (1000000 / rate) = const
- * -(1000000 / rate) = const - 256
- * 1000000 / rate = -(const - 256)
- * 1000000 / rate = -const + 256
- * 1000000 = (-const + 256) * rate
- * 1000000 / (-const + 256) = rate
- * 1000000 / (256 - const) = rate */
- real_rate = 1000000UL / (unsigned long)(256 - timeconst);
- if (cx->buffer_stereo) real_rate /= 2UL;
- return real_rate;
-}
-
-unsigned char sndsb_rate_to_time_constant(struct sndsb_ctx *cx,unsigned long rate) {
- if (rate < 4000UL) rate = 4000UL;
- return (unsigned char)((65536UL - (256000000UL / rate)) >> 8);
-}
-
-int sndsb_prepare_dsp_playback(struct sndsb_ctx *cx,unsigned long rate,unsigned char stereo,unsigned char bit16) {
- unsigned long lm;
-
- /* TODO: Don't play if already playing */
-
- cx->chose_use_dma = 0;
- cx->chose_autoinit_dma = 0;
- cx->chose_autoinit_dsp = 0;
- cx->direct_dac_sent_command = 0;
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT && cx->windows_emulation)
- return 0;
-
- /* set up the params. if we already did (windows spring hack) then don't do it again, but proceed directly
- * to programming the hardware */
- if (cx->windows_springwait == 0) {
- cx->buffer_stereo = stereo;
- cx->buffer_16bit = bit16;
- cx->buffer_rate = rate;
- cx->buffer_hispeed = 0;
- cx->buffer_dma_started = 0;
- cx->buffer_last_io = 0;
- cx->dsp_stopping = 0;
-
- lm = cx->buffer_size;
- if (cx->dsp_adpcm == 0) {
- if (bit16) lm >>= 1UL;
- if (stereo) lm >>= 1UL;
- }
-
- /* if IRQ interval is not assigned, give it the buffer length.
- we must also ensure the requested interval is less than the
- buffer length. */
- if (cx->buffer_irq_interval == 0 ||
- cx->buffer_irq_interval > lm)
- cx->buffer_irq_interval = lm;
-
- /* Windows XP SB emulation: Microsoft's shameful NTVDM.EXE Sound Blaster emulation
- * attempts to mimic the auto-init modes of DSP v2.0/v2.1 but has a very stupid bug:
- * if the interval (DSP block size) you specify is not precisely 1/1, 1/2, 1/4, etc.
- * of the total buffer size (DMA transfer length), their implementation will miss the
- * end of the DMA transfer and run off into the weeds.
- *
- * Another bug: if the block size is too large (4KB or larger?!?) their implementation
- * will randomly drop portions of the audio and the audio will seem to play extra fast.
- *
- * So we have to restrict the irq interval according to these stupid bugs in order to
- * produce anything close to glitch free audio when under Windows XP's DOS box.
- *
- * Shame on you, Microsoft! */
- if (cx->windows_emulation && cx->windows_xp_ntvdm) {
- if (cx->buffer_irq_interval <= (lm / 16UL) || (cx->buffer_size/8) > 4096)
- cx->buffer_irq_interval = (lm / 16UL);
- else if (cx->buffer_irq_interval <= (lm / 8UL) || (cx->buffer_size/4) > 4096)
- cx->buffer_irq_interval = (lm / 8UL);
- else if (cx->buffer_irq_interval <= (lm / 4UL) || (cx->buffer_size/2) > 4096)
- cx->buffer_irq_interval = (lm / 4UL);
- /* Microsoft's shitty implementation also doesn't mesh well with our circular buffer
- * implementation when the interval is equal to the buffer size. Ther implementation
- * makes no effort to simulate a DMA transfer going along at the sample rate, it just
- * "jumps" forward on IRQ. Just as bad as Gravis's SBOS emulation and their shitty
- * DMA timing. */
- else
- cx->buffer_irq_interval = (lm / 2UL);
- }
- else if (cx->ess_extensions) {
- /* ESS 688/1869 chipsets: Unless using Goldplay mode we normally tell the chipset
- * to use 2 or 4 byte demand transfers to optimize ISA bandwidth. If not using
- * auto-init DMA, this method of transfer will fail if the interval is not a
- * multiple of 4 bytes.
- *
- * I *think* that this might be responsible for why non-auto-init DSP+DMA playback
- * eventually stalls on one ESS 688-based laptop SB clone I test on. */
- if (!cx->goldplay_mode && !cx->dsp_autoinit_dma) {
- if (bit16) lm <<= 1UL;
- if (stereo) lm <<= 1UL;
- lm &= ~3; /* round down 4 bytes */
- if (lm == 0) lm = 4;
- if (bit16) lm >>= 1UL;
- if (stereo) lm >>= 1UL;
- }
- }
-
- /* don't let the API play 16-bit audio if less than DSP 4.xx because 16-bit audio played
- * as 8-bit sounds like very loud garbage, be kind to the user */
- if (bit16) {
- if (cx->ess_extensions) {
- if (cx->dsp_play_method < SNDSB_DSPOUTMETHOD_3xx)
- return 0;
- }
- else if (cx->dsp_play_method < SNDSB_DSPOUTMETHOD_4xx) {
- return 0;
- }
- }
-
- /* NTS: we use the "can do" function to reject obvious configurations that will never work
- * on the card, verses an unsupported configuration that we advise not using */
- if (!sndsb_dsp_out_method_can_do(cx,rate,stereo,bit16))
- return 0;
- }
-
- /* if we're doing the Windows "spring" buffer hack, then don't do anything.
- * later when the calling program queries the DMA position, we'll setup DSP playback and call this function again */
- if (cx->windows_emulation && cx->windows_springwait == 0 && cx->windows_xp_ntvdm)
- return 1;
-
- /* clear any pending DSP events (DSP 4.xx) */
- if (cx->dsp_vmaj >= 4)
- sndsb_interrupt_ack(cx,3);
-
- /* NTS: I have an old CT1350 that requires the "speaker on" command
- * even for direct command (0x10) audio to work (or else, you get a
- * quiet staticky sound that resembles your audio). So while this
- * command is pointless for Sound Blaster 16 and later, it is vital
- * for older Sound Blasters.
- *
- * CT1350 Detail: DSP v2.2, no mixer chip, does not support stereo,
- * maxes out at 44.1KHz, and on the Pentium MMX 200MHz
- * system I test it on the DSP has problems playing at
- * 22050Hz if the floppy drive is running (the audio
- * audibly warbles). The card is 8-bit ISA. I also
- * noticed modern computer mics don't work with it.
- * It was designed for unpowered mics, which were
- * common at the time and often used with tape recorders. */
- sndsb_write_dsp(cx,cx->dsp_record ? 0xD3 : 0xD1); /* turn off speaker if recording, else, turn on */
-
- /* these methods involve DMA */
- cx->chose_use_dma = 1;
- /* use auto-init DMA unless for some reason we can't */
- cx->chose_autoinit_dma = cx->dsp_autoinit_dma;
- cx->chose_autoinit_dsp = cx->dsp_autoinit_command;
-
- /* Gravis Ultrasound SBOS/MEGA-EM don't handle auto-init 1.xx very well.
- the only way to cooperate with their shitty emulation is to strictly
- limit DMA count to the IRQ interval and to NOT set the auto-init flag */
- if (cx->sbos || cx->mega_em)
- cx->chose_autoinit_dma = cx->chose_autoinit_dsp = 0;
-
- if (cx->dsp_adpcm > 0) {
- sndsb_write_dsp_timeconst(cx,sndsb_rate_to_time_constant(cx,rate));
- if (stereo || bit16 || cx->dsp_record || cx->goldplay_mode)
- return 0; /* ADPCM modes do not support stereo or 16 bit nor recording */
-
- /* if DSP 2.xx mode or higher and ADPCM auto-init enabled, enable autoinit */
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_200 && cx->enable_adpcm_autoinit && cx->dsp_autoinit_command) {
- sndsb_write_dsp_blocksize(cx,cx->buffer_irq_interval);
- cx->chose_autoinit_dsp = 1;
- }
- else {
- cx->chose_autoinit_dsp = 0;
- }
- }
- else if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_1xx) {
- /* NTS: Apparently, issuing Pause & Resume commands at this stage hard-crashes DOSBox 0.74? */
- sndsb_write_dsp_timeconst(cx,sndsb_rate_to_time_constant(cx,rate * (cx->buffer_stereo ? 2UL : 1UL)));
- cx->chose_autoinit_dsp = 0; /* DSP 1.xx does not support auto-init DSP commands */
- }
- else if (cx->ess_extensions && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) {
- /* do nothing----using SBPro DSP commands then programming ESS registers serves only to
- * confuse the chip and cause it to stop responding. */
- }
- else if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_200 && cx->dsp_play_method <= SNDSB_DSPOUTMETHOD_3xx) {
- /* DSP 2.00, 2.01+, and DSP 3.xx */
- unsigned long total_rate = rate * (cx->buffer_stereo ? 2UL : 1UL);
-
- /* NTS: Apparently, issuing Pause & Resume commands at this stage hard-crashes DOSBox 0.74? */
- sndsb_write_dsp_timeconst(cx,sndsb_rate_to_time_constant(cx,total_rate));
-
- /* DSP 2.01 and higher can do "high-speed" DMA transfers up to 44.1KHz */
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_201) {
- /* NTS: I have a CT1350B card that has audible problems with the ISA bus when driven up to
- * 22050Hz in non-hispeed modes (if I have something else run, like reading the floppy
- * drive, the audio "warbles", changing speed periodically). So while Creative suggests
- * enabling hispeed mode for rates 23KHz and above, I think it would be wiser instead
- * to do hispeed mode for 16KHz or higher instead. [1]
- * [DSP v2.2 with no copyright string]
- * [Tested on Pentium MMX 200MHz system with ISA and PCI slots]
- * [Applying fix [1] indeed resolved the audible warbling]
- * [Is this fix needed for any other Sound Blaster products of that era?] */
- if (cx->ess_extensions && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) /* ESS 688/1869 use of the extensions it doesn't matter */
- cx->buffer_hispeed = 0;
- else if (cx->force_hispeed)
- cx->buffer_hispeed = 1;
- else if (cx->dsp_vmaj == 2 && cx->dsp_vmin == 2 && !strcmp(cx->dsp_copyright,"")) /* [1] */
- cx->buffer_hispeed = (total_rate >= (cx->dsp_record ? 8000 : 16000));
- else
- cx->buffer_hispeed = (total_rate >= (cx->dsp_record ? 13000 : 23000));
-
- /* DSP 3.xx stereo management */
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) {
- /* Sound Blaster Pro requires the "set input mode to mono/stereo" commands if recording,
- * and sets mono/stereo mode with a bit defined in a specific mixer register */
- if (cx->dsp_record) sndsb_write_dsp(cx,cx->buffer_stereo ? 0xA8 : 0xA0);
- sndsb_write_mixer(cx,0x0E,0x20 | (cx->buffer_stereo ? 0x02 : 0x00));
- }
-
- /* if we need to, transmit block length */
- if (cx->buffer_hispeed || cx->chose_autoinit_dsp)
- sndsb_write_dsp_blocksize(cx,cx->buffer_irq_interval * (stereo?2:1));
- }
- else {
- cx->buffer_hispeed = 0;
- if (cx->chose_autoinit_dsp)
- sndsb_write_dsp_blocksize(cx,cx->buffer_irq_interval * (stereo?2:1));
- }
- }
- else if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_4xx) {
- /* DSP 4.xx management is much simpler here */
- sndsb_write_dsp_outrate(cx,rate);
- }
-
- /* auto-init DSP modes require auto-init DMA. if auto-init DMA
- * is not available, then don't use auto-init DSP commands. */
- if (!cx->chose_autoinit_dma) cx->chose_autoinit_dsp = 0;
-
- /* pick the DMA buffer length to be programmed.
- * if auto-init, then we can safely give the entire buffer size.
- * else, we must match the IRQ interval */
- if (cx->chose_autoinit_dma) {
- cx->buffer_dma_started_length = cx->buffer_size;
- }
- else {
- cx->buffer_dma_started_length = cx->buffer_irq_interval;
- if (cx->dsp_adpcm == 0) {
- if (bit16) cx->buffer_dma_started_length <<= 1UL;
- if (stereo) cx->buffer_dma_started_length <<= 1UL;
- }
-
- if (cx->backwards)
- cx->buffer_dma_started = cx->buffer_size - cx->buffer_dma_started_length;
- }
-
- return 1;
-}
-
-int sndsb_begin_dsp_playback(struct sndsb_ctx *cx) {
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) {
- cx->gold_memcpy = 0;
- if (cx->dsp_record)
- cx->timer_tick_func = sndsb_timer_tick_directi_cmd;
- else
- cx->timer_tick_func = sndsb_timer_tick_directo_cmd;
- }
- else if (cx->goldplay_mode) {
-#if TARGET_MSDOS == 32
- if (cx->goldplay_dma == NULL)
- return 0;
-#endif
-
- cx->gold_memcpy = (cx->buffer_16bit?2:1)*(cx->buffer_stereo?2:1);
- if (cx->dsp_record)
- cx->timer_tick_func = sndsb_timer_tick_goldi_cpy;
- else
- cx->timer_tick_func = sndsb_timer_tick_goldo_cpy;
- }
- else {
- if (cx->dsp_nag_mode)
- cx->timer_tick_func = sndsb_timer_tick_gen;
- else
- cx->timer_tick_func = NULL;
-
- cx->gold_memcpy = 0;
- }
-
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) /* do nothing */
- return 1;
-
- /* defer beginning playback until the program first asks for the DMA position */
- if (cx->windows_emulation && cx->windows_springwait == 0 && cx->windows_xp_ntvdm) {
- cx->windows_springwait = 1;
- return 1;
- }
-
- if (cx->dsp_adpcm > 0) {
- if (cx->dsp_record || cx->goldplay_mode)
- return 0;
-
- if (cx->chose_autoinit_dsp) {
- if (cx->dsp_adpcm == ADPCM_4BIT)
- sndsb_write_dsp(cx,0x7D); /* with ref. byte */
- else if (cx->dsp_adpcm == ADPCM_2_6BIT)
- sndsb_write_dsp(cx,0x7F); /* with ref. byte */
- else if (cx->dsp_adpcm == ADPCM_2BIT)
- sndsb_write_dsp(cx,0x1F); /* with ref. byte */
- }
- else {
- unsigned short lv;
-
- lv = cx->buffer_irq_interval - 1;
- if (cx->dsp_adpcm == ADPCM_4BIT)
- sndsb_write_dsp(cx,0x75); /* with ref. byte */
- else if (cx->dsp_adpcm == ADPCM_2_6BIT)
- sndsb_write_dsp(cx,0x77); /* with ref. byte */
- else if (cx->dsp_adpcm == ADPCM_2BIT)
- sndsb_write_dsp(cx,0x17); /* with ref. byte */
- sndsb_write_dsp(cx,lv);
- sndsb_write_dsp(cx,lv >> 8);
- }
- }
- else if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->dsp_play_method <= SNDSB_DSPOUTMETHOD_3xx) {
- unsigned short lv = (cx->buffer_irq_interval * (cx->buffer_stereo?2:1) * (cx->buffer_16bit?2:1)) - 1;
-
- if (cx->ess_extensions && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) {
- /* ESS 688/1869 chipset specific DSP playback.
- using this mode bypasses a lot of the Sound Blaster Pro emulation
- and restrictions and allows us to run up to 48KHz 16-bit stereo */
- unsigned short t16;
- int b;
-
- _cli();
-
- /* clear IRQ */
- sndsb_interrupt_ack(cx,3);
-
- b = 0x00; /* DMA disable */
- b |= (cx->chose_autoinit_dsp) ? 0x04 : 0x00;
- b |= (cx->dsp_record) ? 0x0A : 0x00; /* [3]=DMA converter in ADC mode [1]=DMA read for ADC */
- if (sndsb_ess_write_controller(cx,0xB8,b) == -1) {
- _sti();
- return 0;
- }
-
- b = sndsb_ess_read_controller(cx,0xA8);
- if (b == -1) {
- _sti();
- return 0;
- }
- b &= ~0xB; /* clear mono/stereo and record monitor (bits 3, 1, and 0) */
- b |= (cx->buffer_stereo?1:2); /* 10=mono 01=stereo */
- if (sndsb_ess_write_controller(cx,0xA8,b) == -1) {
- _sti();
- return 0;
- }
-
- /* NTS: The meaning of bits 1:0 in register 0xB9
- *
- * 00 single DMA transfer mode
- * 01 demand DMA transfer mode, 2 bytes/request
- * 10 demand DMA transfer mode, 4 bytes/request
- * 11 reserved
- *
- * NOTES on what happens if you set bits 1:0 (DMA transfer type) to the "reserved" 11 value:
- *
- * ESS 688 (Sharp laptop) Nothing, apparently. Treated the same as 4 bytes/request
- *
- * ESS 1887 (Compaq Presario) Triggers a hardware bug where the chip appears to fetch
- * 3 bytes per demand transfer but then only handle 1 byte,
- * which translates to audio playing at 3x the sample rate
- * it should be. NOT because the DAC is running any faster,
- * but because the chip is only playing back every 3rd sample!
- * This play only 3rds behavior is consistent across 8/16-bit
- * PCM and mono/stereo.
- */
-
- /* TODO: This should be one of the options the user can tinker with for testing! */
- if (cx->goldplay_mode)
- b = cx->buffer_16bit ? 1 : 0; /* demand transfer DMA 2 bytes (16-bit) or single transfer DMA (8-bit) */
- else
- b = 2; /* demand transfer DMA 4 bytes per request */
-
- if (sndsb_ess_write_controller(cx,0xB9,b) == -1) {
- _sti();
- return 0;
- }
-
- if (cx->buffer_rate > 22050) {
- /* bit 7: = 1
- * bit 6:0: = sample rate divider
- *
- * rate = 795.5KHz / (256 - x) */
- b = 256 - (795500UL / (unsigned long)cx->buffer_rate);
- if (b < 0x80) b = 0x80;
- }
- else {
- /* bit 7: = 0
- * bit 6:0: = sample rate divider
- *
- * rate = 397.7KHz / (128 - x) */
- b = 128 - (397700UL / (unsigned long)cx->buffer_rate);
- if (b < 0) b = 0;
- }
- if (sndsb_ess_write_controller(cx,0xA1,b) == -1) {
- _sti();
- return 0;
- }
-
- b = 256 - (7160000UL / ((unsigned long)cx->buffer_rate * 32UL)); /* 80% of rate/2 times 82 I think... */
- if (sndsb_ess_write_controller(cx,0xA2,b) == -1) {
- _sti();
- return 0;
- }
-
- t16 = -(lv+1);
- if (sndsb_ess_write_controller(cx,0xA4,t16) == -1 || /* DMA transfer count low */
- sndsb_ess_write_controller(cx,0xA5,t16>>8) == -1) { /* DMA transfer count high */
- _sti();
- return 0;
- }
-
- b = sndsb_ess_read_controller(cx,0xB1);
- if (b == -1) {
- _sti();
- return 0;
- }
- b &= ~0xA0; /* clear compat game IRQ, fifo half-empty IRQs */
- b |= 0x50; /* set overflow IRQ, and "no function" */
- if (sndsb_ess_write_controller(cx,0xB1,b) == -1) {
- _sti();
- return 0;
- }
-
- b = sndsb_ess_read_controller(cx,0xB2);
- if (b == -1) {
- _sti();
- return 0;
- }
- b &= ~0xA0; /* clear compat */
- b |= 0x50; /* set DRQ/DACKB inputs for DMA */
- if (sndsb_ess_write_controller(cx,0xB2,b) == -1) {
- _sti();
- return 0;
- }
-
- b = 0x51; /* enable FIFO+DMA, reserved, load signal */
- b |= (cx->buffer_16bit ^ cx->audio_data_flipped_sign) ? 0x20 : 0x00; /* signed complement mode or not */
- if (sndsb_ess_write_controller(cx,0xB7,b) == -1) {
- _sti();
- return 0;
- }
-
- b = 0x90; /* enable FIFO+DMA, reserved, load signal */
- b |= (cx->buffer_16bit ^ cx->audio_data_flipped_sign) ? 0x20 : 0x00; /* signed complement mode or not */
- b |= (cx->buffer_stereo) ? 0x08 : 0x40; /* [3]=stereo [6]=!stereo */
- b |= (cx->buffer_16bit) ? 0x04 : 0x00; /* [2]=16bit */
- if (sndsb_ess_write_controller(cx,0xB7,b) == -1) {
- _sti();
- return 0;
- }
-
- b = sndsb_ess_read_controller(cx,0xB8);
- if (b == -1) {
- _sti();
- return 0;
- }
- if (sndsb_ess_write_controller(cx,0xB8,b | 1) == -1) { /* enable DMA */
- _sti();
- return 0;
- }
- }
- else {
- if (cx->chose_autoinit_dsp) {
- /* preparation function has already transmitted block length, use autoinit commands */
- if (cx->buffer_hispeed)
- sndsb_write_dsp(cx,cx->dsp_record ? 0x98 : 0x90);
- else
- sndsb_write_dsp(cx,cx->dsp_record ? 0x2C : 0x1C);
- }
- else {
- /* send single-cycle command, then transmit length */
- if (cx->buffer_hispeed)
- sndsb_write_dsp(cx,cx->dsp_record ? 0x99 : 0x91);
- else {
- sndsb_write_dsp(cx,cx->dsp_record ? 0x24 : 0x14);
- sndsb_write_dsp(cx,lv);
- sndsb_write_dsp(cx,lv >> 8);
- }
- }
- }
- }
- else if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_4xx) {
- unsigned long lv = (cx->buffer_irq_interval * (cx->buffer_stereo?2:1)) - 1;
-
- if (lv > 65535UL) lv = 65535UL;
-
- sndsb_write_dsp(cx,(cx->buffer_16bit ? 0xB0 : 0xC0) | (cx->chose_autoinit_dsp?0x04:0x00) |
- ((!cx->chose_autoinit_dsp && cx->dsp_4xx_fifo_single_cycle) ? 0x02 : 0x00) |
- ((cx->chose_autoinit_dsp && cx->dsp_4xx_fifo_autoinit) ? 0x02 : 0x00) |
- (cx->dsp_record ? 0x08 : 0x00)); /* bCommand FIFO on */
- sndsb_write_dsp(cx,(cx->audio_data_flipped_sign ? 0x10 : 0x00) ^
- ((cx->buffer_stereo ? 0x20 : 0x00) | (cx->buffer_16bit ? 0x10 : 0x00))); /* bMode */
- sndsb_write_dsp(cx,lv);
- sndsb_write_dsp(cx,lv>>8);
- }
-
- cx->timer_tick_signal = 0;
- return 1;
-}
-
-int sndsb_stop_dsp_playback(struct sndsb_ctx *cx) {
- cx->gold_memcpy = 0;
- cx->dsp_stopping = 1;
- cx->windows_springwait = 0;
- cx->timer_tick_func = NULL;
- if (cx->direct_dac_sent_command) {
- if (cx->dsp_record)
- sndsb_read_dsp(cx);
- else
- sndsb_write_dsp(cx,0x80);
-
- cx->direct_dac_sent_command = 0;
- }
-
- /* NTS: As far as I can tell, the best way to stop the sound card is just reset the DSP.
- * The "Exit auto-init" commands don't seem to work */
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx)
- sndsb_reset_dsp(cx);
- if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_3xx && cx->dsp_record)
- sndsb_write_dsp(cx,0xA0);
-
- if ((cx->buffer_16bit && cx->dma16 >= 0) || (!cx->buffer_16bit && cx->dma8 >= 0)) {
- uint16_t pr,cr;
- unsigned int nonmove = 0;
- /* wait for the DMA channel to stop moving */
- if (cx->buffer_16bit) cr = d8237_read_count(cx->dma16);
- else cr = d8237_read_count(cx->dma8);
- do {
- t8254_wait(t8254_us2ticks(10000)); /* 10ms */
- pr = cr;
- if (cx->buffer_16bit) cr = d8237_read_count(cx->dma16);
- else cr = d8237_read_count(cx->dma8);
- if (pr == cr) nonmove++;
- else nonmove = 0;
- } while (nonmove < 3);
- }
-
- if (cx->dsp_play_method > SNDSB_DSPOUTMETHOD_DIRECT) {
- sndsb_shutdown_dma(cx);
- sndsb_write_mixer(cx,0x0E,0);
- }
-
- cx->timer_tick_signal = 0;
- sndsb_write_dsp(cx,0xD3); /* turn off speaker */
-
- if (cx->ess_extensions && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) {
- int b;
-
- b = sndsb_ess_read_controller(cx,0xB8);
- if (b != -1) {
- b &= ~0x01; /* stop DMA */
- sndsb_ess_write_controller(cx,0xB8,b);
- }
- }
-
- return 1;
-}
-
-void sndsb_send_buffer_again(struct sndsb_ctx *cx) {
- unsigned long lv;
- unsigned char ch;
-
- if (cx->dsp_stopping) return;
- if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) return;
- ch = cx->buffer_16bit ? cx->dma16 : cx->dma8;
-
- if (!cx->chose_autoinit_dma)
- outp(d8237_ioport(ch,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(ch) | D8237_MASK_SET); /* mask */
-
- /* ESS chipsets: I believe the reason non-auto-init DMA+DSP is halting is because
- * we first needs to stop DMA on the chip THEN reprogram the DMA controller.
- * Perhaps the FIFO is hardwired to refill at all times and reprogramming the
- * DMA controller THEN twiddling the DMA enable opens a window of opportunity
- * for refill to happen at the wrong time? */
- if (!cx->chose_autoinit_dsp) {
- if (cx->dsp_adpcm > 0) {
- }
- else if (cx->ess_extensions && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) {
- unsigned char b;
-
- /* stop DMA */
- b = sndsb_ess_read_controller(cx,0xB8);
- sndsb_ess_write_controller(cx,0xB8,b & ~1);
- }
- }
-
- /* if we're doing it the non-autoinit method, then we
- also need to update the DMA pointer */
- if (!cx->chose_autoinit_dma) {
- unsigned long npos = cx->buffer_dma_started;
- unsigned long rem = cx->buffer_dma_started;
-
- lv = cx->buffer_irq_interval;
- if (cx->dsp_adpcm == 0) {
- if (cx->buffer_16bit) lv <<= 1UL;
- if (cx->buffer_stereo) lv <<= 1UL;
- }
-
- if (cx->backwards) {
- if (rem == 0) {
- npos = cx->buffer_size - lv;
- rem = cx->buffer_size;
- }
- else {
- if (npos >= lv) npos -= lv;
- else npos = 0;
- }
- }
- else {
- npos += cx->buffer_dma_started_length;
- rem = npos + lv;
- if (npos >= cx->buffer_size) {
- npos = 0;
- rem = lv;
- }
- else if (rem > cx->buffer_size) {
- rem = cx->buffer_size;
- }
- }
-
- cx->buffer_dma_started = npos;
- cx->buffer_dma_started_length = lv = rem - npos;
- if (cx->backwards)
- d8237_write_base(ch,cx->buffer_phys+cx->buffer_dma_started+cx->buffer_dma_started_length-1); /* RAM location with not much around */
- else
- d8237_write_base(ch,cx->buffer_phys+cx->buffer_dma_started); /* RAM location with not much around */
- d8237_write_count(ch,cx->buffer_dma_started_length);
- outp(d8237_ioport(ch,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(ch)); /* unmask */
- if (lv != 0) lv--;
- }
- else {
- lv = cx->buffer_irq_interval;
- if (cx->dsp_adpcm == 0) {
- if (cx->buffer_16bit) lv <<= 1UL;
- if (cx->buffer_stereo) lv <<= 1UL;
- }
- if (lv != 0) lv--;
- }
-
- /* if we're doing the one-block-at-a-time 1.xx method, then start another right now */
- if (!cx->chose_autoinit_dsp) {
- if (cx->dsp_adpcm > 0) {
- if (cx->dsp_adpcm == ADPCM_4BIT)
- sndsb_write_dsp(cx,0x74); /* without ref. byte */
- else if (cx->dsp_adpcm == ADPCM_2_6BIT)
- sndsb_write_dsp(cx,0x76); /* without ref. byte */
- else if (cx->dsp_adpcm == ADPCM_2BIT)
- sndsb_write_dsp(cx,0x16); /* without ref. byte */
- sndsb_write_dsp(cx,lv);
- sndsb_write_dsp(cx,lv >> 8);
- }
- else if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_1xx && cx->dsp_play_method <= SNDSB_DSPOUTMETHOD_3xx) {
- /* send single-cycle command, then transmit length */
- if (cx->ess_extensions && cx->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx) {
- unsigned short t16;
- unsigned char b;
-
- t16 = -(lv+1);
- sndsb_ess_write_controller(cx,0xA4,t16); /* DMA transfer count low */
- sndsb_ess_write_controller(cx,0xA5,t16>>8); /* DMA transfer count high */
-
- /* start DMA again */
- b = sndsb_ess_read_controller(cx,0xB8);
- sndsb_ess_write_controller(cx,0xB8,b | 1);
- }
- else {
- if (cx->buffer_hispeed) {
- sndsb_write_dsp_blocksize(cx,lv+1);
- sndsb_write_dsp(cx,cx->dsp_record ? 0x99 : 0x91);
- }
- else {
- sndsb_write_dsp(cx,cx->dsp_record ? 0x24 : 0x14);
- sndsb_write_dsp(cx,lv);
- sndsb_write_dsp(cx,lv >> 8);
- }
- }
- }
- else if (cx->dsp_play_method == SNDSB_DSPOUTMETHOD_4xx) {
- lv++;
- if (cx->buffer_16bit) lv >>= 1UL;
- lv--;
- sndsb_write_dsp(cx,(cx->buffer_16bit ? 0xB0 : 0xC0) | (cx->chose_autoinit_dsp?0x04:0x00) |
- ((!cx->chose_autoinit_dsp && cx->dsp_4xx_fifo_single_cycle) ? 0x02 : 0x00) |
- ((cx->chose_autoinit_dsp && cx->dsp_4xx_fifo_autoinit) ? 0x02 : 0x00) |
- (cx->dsp_record ? 0x08 : 0x00)); /* bCommand FIFO on */
- sndsb_write_dsp(cx,(cx->audio_data_flipped_sign ? 0x10 : 0x00) ^
- ((cx->buffer_stereo ? 0x20 : 0x00) | (cx->buffer_16bit ? 0x10 : 0x00))); /* bMode */
- sndsb_write_dsp(cx,lv);
- sndsb_write_dsp(cx,lv>>8);
- }
- }
-}
-
-void sndsb_choose_mixer(struct sndsb_ctx *card,signed char override) {
- signed char idx;
-
- card->sb_mixer_items = 0;
- card->sb_mixer = NULL;
- idx = override >= 0 ? override : card->mixer_chip;
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
- if (idx == SNDSB_MIXER_CT1335) {
- card->sb_mixer = sndsb_mixer_ct1335;
- card->sb_mixer_items = (signed short)(sizeof(sndsb_mixer_ct1335) / sizeof(struct sndsb_mixer_control));
- }
- else if (idx == SNDSB_MIXER_CT1345) {
- card->sb_mixer = sndsb_mixer_ct1345;
- card->sb_mixer_items = (signed short)(sizeof(sndsb_mixer_ct1345) / sizeof(struct sndsb_mixer_control));
- }
- else if (idx == SNDSB_MIXER_CT1745) {
- card->sb_mixer = sndsb_mixer_ct1745;
- card->sb_mixer_items = (signed short)(sizeof(sndsb_mixer_ct1745) / sizeof(struct sndsb_mixer_control));
- }
-#endif
-}
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-/* CUT ADPCM encoding */
-#else
-/* NTS: This is the best documentation I could fine regarding the Sound Blaster ADPCM format.
- * Tables and method taken from DOSBox 0.74 SB emulation. The information on multimedia.cx's
- * Wiki is wrong. */
-unsigned char sndsb_encode_adpcm_4bit(unsigned char samp) {
- static const signed char scaleMap[64] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7,
- 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15,
- 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30,
- 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60
- };
- static const signed char adjustMap[32] = {
- 0, 0, 0, 0, 0, 1, 1, 1,
- -1, 0, 0, 0, 0, 1, 1, 1,
- -1, 0, 0, 0, 0, 1, 1, 1,
- -1, 0, 0, 0, 0, 0, 0, 0
- };
- signed int sdelta = (signed int)((signed char)(samp - adpcm_pred));
- unsigned char sign = 0;
-
- sdelta = (sdelta * 2) + (adpcm_step < 3 ? adpcm_error : 0);
- adpcm_error = sdelta & ((1 << (adpcm_step + 1)) - 1);
- sdelta >>= adpcm_step+1;
- if (sdelta < 0) {
- sdelta = -sdelta;
- sign = 8;
- }
- if (sdelta > 7) sdelta = 7;
- adpcm_pred += scaleMap[(adpcm_step*16)+sign+sdelta];
- if (adpcm_pred < 0) adpcm_pred = 0;
- else if (adpcm_pred > 0xFF) adpcm_pred = 0xFF;
- adpcm_step += adjustMap[(adpcm_step*8)+sdelta];
- if ((signed char)adpcm_step < 0) adpcm_step = 0;
- if (adpcm_step > 3) adpcm_step = 3;
- return (unsigned char)sdelta | sign;
-}
-
-/* NTS: This is the best documentation I could fine regarding the Sound Blaster ADPCM format.
- * Tables and method taken from DOSBox 0.74 SB emulation. The information on multimedia.cx's
- * Wiki is wrong. */
-unsigned char sndsb_encode_adpcm_2bit(unsigned char samp) {
- static const signed char scaleMap[24] = {
- 0, 1, 0, -1, 1, 3, -1, -3,
- 2, 6, -2, -6, 4, 12, -4, -12,
- 8, 24, -8, -24, 16, 48, -16, -48
-/* NTS: This table is correct as tested against real Creative SB
- hardware. DOSBox's version has a typo on the last row
- that will make the 2-bit playback sound WORSE in it. */
- };
- static const signed char adjustMap[12] = {
- 0, 1, -1, 1,
- -1, 1, -1, 1,
- -1, 1, -1, 0
- };
- signed int sdelta = (signed int)((signed char)(samp - adpcm_pred));
- unsigned char sign = 0;
-
- sdelta = (sdelta * 2) + (adpcm_step == 0 ? adpcm_error : 0);
- adpcm_error = sdelta & ((1 << adpcm_step) - 1);
- sdelta >>= adpcm_step+1;
-
- if (sdelta < 0) {
- sdelta = -sdelta;
- sign = 2;
- }
-
- /* "ring" suppression */
- if (adpcm_step == 5 && sdelta == 1 && adpcm_last == 3 && sign == 0)
- sdelta = 0;
-
- if (sdelta > 1) sdelta = 1;
- adpcm_last = sdelta + sign;
- adpcm_pred += scaleMap[(adpcm_step*4)+sign+sdelta];
- if (adpcm_pred < 0) adpcm_pred = 0;
- else if (adpcm_pred > 0xFF) adpcm_pred = 0xFF;
- adpcm_step += adjustMap[(adpcm_step*2)+sdelta];
- if ((signed char)adpcm_step < 0) adpcm_step = 0;
- if (adpcm_step > 5) adpcm_step = 5;
- return (unsigned char)sdelta | sign;
-}
-
-/* NTS: This is the best documentation I could fine regarding the Sound Blaster ADPCM format.
- * Tables and method taken from DOSBox 0.74 SB emulation. The information on multimedia.cx's
- * Wiki is wrong. */
-unsigned char sndsb_encode_adpcm_2_6bit(unsigned char samp,unsigned char b2) {
- static const signed char scaleMap[40] = {
- 0, 1, 2, 3, 0, -1, -2, -3,
- 1, 3, 5, 7, -1, -3, -5, -7,
- 2, 6, 10, 14, -2, -6, -10, -14,
- 4, 12, 20, 28, -4, -12, -20, -28,
- 5, 15, 25, 35, -5, -15, -25, -35
- };
- static const signed char adjustMap[20] = {
- 0, 0, 0, 1,
- -1, 0, 0, 1,
- -1, 0, 0, 1,
- -1, 0, 0, 1,
- -1, 0, 0, 0
- };
- signed int sdelta = (signed int)((signed char)(samp - adpcm_pred));
- unsigned char sign = 0;
-
- sdelta = (sdelta * 2) + (adpcm_step < 2 ? adpcm_error : 0);
- adpcm_error = sdelta & ((1 << (adpcm_step + (b2 ? 2 : 1))) - 1);
- sdelta >>= adpcm_step+1;
-
- if (sdelta < 0) {
- sdelta = -sdelta;
- sign = 4;
- }
-
- if (sdelta > 3) sdelta = 3;
- sdelta += sign;
- if (b2) sdelta &= 0x6;
- adpcm_pred += scaleMap[(adpcm_step*8)+sdelta];
- if (adpcm_pred < 0) adpcm_pred = 0;
- else if (adpcm_pred > 0xFF) adpcm_pred = 0xFF;
- adpcm_step += adjustMap[(adpcm_step*4)+(sdelta&3)];
- if ((signed char)adpcm_step < 0) adpcm_step = 0;
- if (adpcm_step > 5) adpcm_step = 5;
- return (unsigned char)sdelta;
-}
-
-void sndsb_encode_adpcm_set_reference(unsigned char c,unsigned char mode) {
- adpcm_pred = c;
- adpcm_step = 0;
- if (mode == ADPCM_4BIT)
- adpcm_lim = 5;
- else if (mode == ADPCM_2_6BIT)
- adpcm_lim = 3;
- else if (mode == ADPCM_2BIT)
- adpcm_lim = 1;
-}
-
-/* undocumented and not properly emulated by DOSBox either:
- when Creative said the non-reference ADPCM commands "continue
- using accumulated reference byte" they apparently meant that
- it resets the step value to max. Yes, even in auto-init
- ADPCM mode. Failure to follow this results in audible
- "fluttering" once per IRQ. */
-void sndsb_encode_adpcm_reset_wo_ref(unsigned char mode) {
- if (mode == ADPCM_4BIT)
- adpcm_step = 3;
- else if (mode == ADPCM_2_6BIT)
- adpcm_step = 4;
- else
- adpcm_step = 5; /* FIXME: Testing by ear seems to favor this one. Is this correct? */
-}
-#endif
-
-void sndsb_write_mixer_entry(struct sndsb_ctx *sb,struct sndsb_mixer_control *mc,unsigned char nb) {
- unsigned char b;
- if (mc->length == 0) return;
- else if (mc->length == 8) {
- sndsb_write_mixer(sb,mc->index,nb);
- }
- else {
- b = sndsb_read_mixer(sb,mc->index);
- b &= ~(((1 << mc->length) - 1) << mc->offset);
- b |= (nb & ((1 << mc->length) - 1)) << mc->offset;
- sndsb_write_mixer(sb,mc->index,b);
- }
-}
-
-unsigned char sndsb_read_mixer_entry(struct sndsb_ctx *sb,struct sndsb_mixer_control *mc) {
- unsigned char b;
- if (mc->length == 0) return 0;
- b = sndsb_read_mixer(sb,mc->index);
- return (b >> mc->offset) & ((1 << mc->length) - 1);
-}
-
-int sndsb_assign_dma_buffer(struct sndsb_ctx *cx,struct dma_8237_allocation *dma) {
- cx->buffer_size = dma->length;
- cx->buffer_phys = dma->phys;
- cx->buffer_lin = dma->lin;
- return 1;
-}
-
-uint32_t sndsb_recommended_dma_buffer_size(struct sndsb_ctx *ctx,uint32_t limit) {
- uint32_t ret = 60UL * 1024UL;
- if (limit != 0UL && ret > limit) ret = limit;
-
- /* Known constraint: Windows 3.1 Creative SB16 drivers don't like it when DOS apps
- * use too large a DMA buffer. It causes Windows to complain about
- * "a DOS program violating the integrity of the operating system".
- *
- * FIXME: Even with small buffers, it "violates the integrity" anyway.
- * So what the fuck is wrong then? */
- if (windows_mode == WINDOWS_ENHANCED && windows_version < 0x35F && /* Windows 3.1 and Creative SB16 drivers v3.57 */
- ctx->windows_creative_sb16_drivers && ctx->windows_creative_sb16_drivers_ver == (0x300 + 57)) {
- if (ret > (4UL * 1024UL)) ret = 4UL * 1024UL;
- }
-
- return ret;
-}
-
+++ /dev/null
-/* WARNING: As usual for performance reasons this library generally does not
- * enable/disable interrupts (cli/sti). To avoid contention with
- * interrupt handlers the calling program should do that. */
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#define SNDSB_MAX_CARDS 4
-
-/* 0x2x0 + const = I/O port */
-#define SNDSB_BIO_MIXER_INDEX 0x4
-#define SNDSB_BIO_MIXER_DATA 0x5
-#define SNDSB_BIO_DSP_RESET 0x6
-#define SNDSB_BIO_DSP_READ_DATA 0xA
-#define SNDSB_BIO_DSP_WRITE_DATA 0xC
-#define SNDSB_BIO_DSP_WRITE_STATUS 0xC
-#define SNDSB_BIO_DSP_READ_STATUS 0xE
-#define SNDSB_BIO_DSP_READ_STATUS16 0xF
-
-/* 0x3x0 + const = I/O port */
-#define SNDSB_MPUIO_DATA 0x0
-#define SNDSB_MPUIO_COMMAND 0x1
-#define SNDSB_MPUIO_STATUS 0x1
-
-/* DSP versions */
-#define SNDSB_DSPCMD_GET_VERSION 0xE1
-
-/* MPU commands */
-#define SNDSB_MPUCMD_RESET 0xFF
-#define SNDSB_MPUCMD_ENTER_UART 0x3F
-
-enum {
- SNDSB_MIXER_CT1335=1,
- SNDSB_MIXER_CT1345, /* Sound Blaster Pro chip */
- SNDSB_MIXER_CT1745, /* Sound Blaster 16 */
- SNDSB_MIXER_MAX
-};
-
-/* which method to use when playing audio through the DSP */
-enum {
- SNDSB_DSPOUTMETHOD_DIRECT=0, /* DSP command 0x10 single-byte playback */
- SNDSB_DSPOUTMETHOD_1xx, /* DSP command 0x14 8-bit mono (DSP 1.xx method) */
- SNDSB_DSPOUTMETHOD_200, /* DSP command 0x1C 8-bit auto-init (DSP 2.00) */
- SNDSB_DSPOUTMETHOD_201, /* DSP command 0x90 8-bit auto-init high speed (DSP 2.01+ using mixer bit to set stereo) */
- SNDSB_DSPOUTMETHOD_3xx, /* DSP command 0x90 8-bit stereo auto-init (3.xx only) */
- SNDSB_DSPOUTMETHOD_4xx, /* DSP command 0xBx/Cx 8/16-bit commands (DSP 4.xx) */
- SNDSB_DSPOUTMETHOD_MAX
-};
-
-enum {
- SNDSB_ESS_NONE=0,
- SNDSB_ESS_688,
- SNDSB_ESS_1869,
- SNDSB_ESS_MAX
-};
-
-enum {
- ADPCM_NONE=0,
- ADPCM_4BIT,
- ADPCM_2_6BIT,
- ADPCM_2BIT
-};
-
-/* NOTES: The length is the amount of data the DSP will transfer, before signalling the ISR via the SB IRQ. Usually most programs
- * will set this to an even subdivision of the total buffer size e.g. so that a 32KB playback buffer signals IRQ every 8KB.
- * The Sound Blaster API will take care of programming the DMA controller with the physical memory address.
- *
- * If auto-init or DSP 4.xx commands are used, the library will try it's best but depending on the clone hardware it cannot
- * guarantee that it can reprogram the physical memory address within the IRQ without causing one or two sample glitches,
- * i.e. that the DSP will wait up for us when we mask DMA. In an ideal world the DSP will have a FIFO so that the time we
- * spend DMA reprogramming is not an issue. It is said on true Creative SB16 hardware, that is precisely the case.
- *
- * Because the SB library has control, it will automatically subdivide submitted buffers if playback would cross a 64KB
- * boundary. But, if the physical memory address is beyond the reach of your DMA controller, the library will skip your
- * buffer and move on. This library will provide a convenience function to check for just that.
- *
- * Finally, remember that in 32-bit protected mode, linear addresses do not necessarily correspond to physical memory
- * addresses. The DOS extender may be running in a DPMI environment that remaps memory. You will need to provide translation
- * in that case. Keep in mind that when translating your linear address can be remapped in any order of physical pages, so
- * you cannot convert just the base and assume the rest. Don't forget also that the DPMI server and environment may very well
- * be paging memory to disk or otherwise moving it around. If you feed pages directly to this code, you must lock the pages.
- * But if you are using DOS memory, the environment will most likely translate the DMA controller for you.
- *
- * In most cases, the best way to handle SB playback is to use the 8237 library to allocate a fixed DMA buffer (usually in
- * lower DOS memory) and loop through that buffer in fragments, filling in behind the play pointer.
- *
- * the oplio variable is normally set to 0. if the Sound Blaster is Plug & Play compatible though, the OPL I/O port reported
- * by ISA PnP will be placed there. This means that if your program wants to use the OPL3 FM synth, it should first check
- * the oplio member and init the adlib library with that port. Else, it should assume port 0x388 and use that. Same rule
- * applies to the gameio (gameport) member.
- *
- * The 'aweio' variable is meant to represent the wavetable section of
- * the Sound Blaster AWE32 and AWE64 cards. It will be set by the ISA PnP
- * code (since those cards are ISA PnP compliant) else it will be zero. */
-
-struct sndsb_ctx {
- uint16_t baseio,mpuio,oplio,gameio,aweio;
- uint16_t wssio,opl3sax_controlio;
- int8_t dma8,dma16,irq;
- uint8_t dsp_adpcm;
- uint8_t audio_data_flipped_sign; /* DSP 4.xx command allows us to specify signed/unsigned */
- uint8_t dsp_play_method;
- uint8_t dsp_vmaj,dsp_vmin;
- uint8_t dsp_ok,mixer_ok;
- uint8_t dsp_stopping;
- uint8_t mixer_chip;
- uint8_t dsp_record;
- uint8_t mpu_ok;
- uint32_t buffer_size; /* length of the buffer IN BYTES */
- uint32_t buffer_rate;
- uint8_t buffer_16bit;
- uint8_t buffer_stereo;
- uint8_t buffer_hispeed;
- uint32_t buffer_dma_started; /* for 1.xx modes: the DMA offset the transfer started */
- uint32_t buffer_dma_started_length; /* ...and for how long */
- volatile uint32_t direct_dsp_io; /* for direct DAC/ADC mode: software I/O pointer */
- uint32_t buffer_irq_interval; /* samples per IRQ. The DSP will be instructed to play this many samples, then signal the IRQ. */
- /* ADPCM modes: This becomes "bytes per IRQ" which depending on the ADPCM encoding can be 1/2, 1/3, or 1/4 the sample count. The first ADPCM block is expected to have the reference byte. */
- /* Sound blaster 1.0 and 2.0: Short intervals may cause playback to audibly pop and stutter, since DSP playback requires reprogramming per block */
- volatile uint32_t buffer_last_io; /* EXTERNAL USE: where the calling program last wrote/read the buffer. prepare_dma sets this to zero, but program maintains it */
- unsigned char FAR* buffer_lin; /* linear (program accessible pointer) */
- uint32_t buffer_phys;
- char dsp_copyright[128];
- /* adjustment for known weird clones of the SB chipset */
- uint8_t is_gallant_sc6600:1; /* Reveal/Gallant SC6600: DSP v3.5 but supports SB16 commands except for the mixer register configuration stuff */
- uint8_t enable_adpcm_autoinit:1;/* Most emulators including DOSBox do not emulate auto-init ADPCM playback */
- uint8_t mega_em:1; /* Gravis MEGA-EM detected, tread very very carefully */
- uint8_t sbos:1; /* Gravis SBOS */
- /* options for calling library */
- uint8_t goldplay_mode:1; /* Goldplay mode: Set DMA transfer length to 1 (2 if stereo) and overwrite the same region of memory from timer.
- An early tracker/sound library released in 1991 called Goldplay does just that, which is why
- stuff from the demoscene using that library has compatibility issued on today's hardware.
- Sick hack, huh? */
- uint8_t dsp_autoinit_dma:1; /* in most cases, you can just setup the DMA buffer to auto-init loop
- and then re-issue the playback command as normal. But some emulations,
- especially Gravis UltraSound SBOS/MEGA-EM, don't handle that too well.
- the only way to play properly with them is to NOT do auto-init DMA
- and to set the DSP block size & DMA count to only precisely the IRQ
- interval. In which case, set this to 0 */
- uint8_t dsp_autoinit_command:1; /* whether or not to use the auto-init form of playback/recording */
- uint8_t dosbox_emulation:1; /* we're running from within DOSBox */
- uint8_t virtualbox_emulation:1; /* we're running from within Sun/Oracle Virtualbox */
- uint8_t windows_emulation:1; /* we're running under Windows where the implementation is probably shitty */
- uint8_t windows_xp_ntvdm:1; /* Microsoft's NTVDM.EXE based emulation in Windows XP requires some restrictive
- workarounds to buffer size, interval, etc. to work properly. Note this also
- applies to Windows Vista. */
- uint8_t dsp_alias_port:1; /* if set, use DSP alias I/O port 0x22D (SB DSP 1.x and 2.x only!) EMF_ID style */
- uint8_t backwards:1; /* play buffer in reverse. will instruct DMA controller to decrement addr */
- uint8_t windows_9x_me_sbemul_sys:1;/* Microsoft's SBEMUL.SYS driver, Windows 98/ME */
- uint8_t windows_creative_sb16_drivers:1;/* Creative Sound Blaster 16 drivers for Windows */
- uint8_t vdmsound:1; /* We're running under VDMSOUND.EXE */
- uint8_t do_not_probe_irq:1; /* if the card has known configuration registers, then do not probe */
- uint8_t do_not_probe_dma:1; /* ... */
- uint8_t ess_extensions:1; /* use ESS 688/1869 extended commands */
- uint8_t force_hispeed:1; /* always use highspeed DSP playback commands (except for DSP 4.xx) */
- uint8_t dsp_4xx_fifo_autoinit:1; /* SB16 use FIFO for auto-init playback */
- uint8_t dsp_4xx_fifo_single_cycle:1; /* SB16 use FIFO for single-cycle playback */
- uint8_t dsp_nag_mode:1; /* "Nag" the DSP during playback (Crystal Dream style) by reissuing playback while playback is active */
- uint8_t dsp_nag_hispeed:1; /* "Nag" even during highspeed DMA playback (NOT recommended) */
- uint8_t poll_ack_when_no_irq:1; /* If playing DMA without IRQ assignment, poll the "ack" register in idle call */
- uint8_t hispeed_matters:1; /* If set, playing at rates above 22050Hz requires hispeed DSP commands */
- uint8_t hispeed_blocking:1; /* DSP does not accept commands, requires reset, in hispeed DSP playback */
- uint8_t dsp_direct_dac_read_after_command; /* read the DSP write status N times after direct DAC commands */
- uint8_t dsp_direct_dac_poll_retry_timeout; /* poll DSP write status up to N times again before attempting DSP command */
- const char* reason_not_supported; /* from last call can_do() or is_supported() */
-/* array of mixer controls, determined by mixer chipset */
- struct sndsb_mixer_control* sb_mixer;
- signed short sb_mixer_items;
-/* max sample rate of the DSP */
- unsigned short max_sample_rate_dsp4xx; /* in Hz, maximum per sample frame */
- unsigned short max_sample_rate_sb_hispeed; /* in Hz, maximum per sample i.e. DSP maxes out at this value at mono, or half this value at stereo */
- unsigned short max_sample_rate_sb_hispeed_rec; /* in Hz, maximum per sample i.e. DSP maxes out at this value at mono, or half this value at stereo */
- unsigned short max_sample_rate_sb_play; /* in Hz, maximum playback rate in non-hispeed mode */
- unsigned short max_sample_rate_sb_rec; /* in Hz, maximum recording rate in non-hispeed mode */
- unsigned short max_sample_rate_sb_play_dac; /* in Hz, maximum playback rate through DSP command 0x10 (Direct DAC output) */
- unsigned short max_sample_rate_sb_rec_dac; /* in Hz, maximum recording rate through DSP command 0x20 (Direct DAC input) */
-/* function call. calling application should call this from the timer interrupt (usually IRQ 0) to
- * allow direct DAC and "goldplay" modes to work or other idle maintenance functions. if NULL, do not call. */
- void (*timer_tick_func)(struct sndsb_ctx *cx);
-/* goldplay mode DMA buffer */
-#if TARGET_MSDOS == 32
- struct dma_8237_allocation* goldplay_dma;
-#else
- uint8_t goldplay_dma[4];
-#endif
- uint8_t gold_memcpy;
-/* ISA PnP information */
- const char* pnp_name;
- uint32_t pnp_id;
- uint8_t pnp_csn; /* PnP Card Select Number */
- uint8_t pnp_bios_node; /* PnP BIOS device node (0xFF if none) */
- uint8_t ess_chipset; /* which ESS chipset */
-/* Windows compat hack */
- uint16_t windows_creative_sb16_drivers_ver;
- uint8_t windows_springwait; /* when windows_emulation == 1, defer actually starting a DSP block until
- the calling program has a chance to fill the buffer and check the position.
- assume the emulation provided by Windows is the kind that (more or less)
- directly converts DSP block commands to waveOutWrite() calls or some
- nonsense, therefore tracking the DMA pointer and writing to the buffer
- behind it will only cause audio glitches. Note that the test program's
- order of calls are incompatible with Windows in this way: setting up the
- DSP first and then setting up DMA only confuses the emulation. Doing this
- effectively defers DSP programming until after the host program has set up
- DMA, ensuring the minimalist emulation provided by Windows is not confused. */
- uint8_t chose_autoinit_dma:1; /* the library chooses to use autoinit DMA */
- uint8_t chose_autoinit_dsp:1; /* the library chooses to use auto-init commands */
- uint8_t chose_use_dma:1; /* the library chooses to run in a manner that uses DMA */
- uint8_t direct_dac_sent_command:1; /* direct DSP playback: we just sent the command, next is data */
- uint8_t ess_extended_mode:1; /* if set, ESS chip is in extended mode */
- uint8_t timer_tick_signal:1;
-};
-
-/* runtime "options" that affect sound blaster probing.
- * note that they are only advisory flags to the library.
- * all flags are initialized to zero even prior to init_sndsb() */
-struct sndsb_probe_opts {
- unsigned char disable_manual_irq_probing:1; /* don't use hardcore manual IRQ probing /nomirqp */
- unsigned char disable_alt_irq_probing:1; /* don't use alt "lite" IRQ probing /noairqp */
- unsigned char disable_sb16_read_config_byte:1; /* don't read configuration from SB16 mixer byte /nosb16cfg */
- unsigned char disable_manual_dma_probing:1; /* don't probe for DMA channel if unknown /nodmap */
- unsigned char disable_manual_high_dma_probing:1; /* don't probe for 16-bit DMA channel if unknown /nohdmap */
- unsigned char disable_windows_vxd_checks:1; /* don't try to identify Windows drivers /nowinvxd */
- unsigned char disable_ess_extensions:1; /* don't use/detect ESS688/ESS1869 commands /noess */
- unsigned char experimental_ess:1; /* use ESS extensions even on chips not yet supported /ex-ess */
- unsigned char use_dsp_alias:1; /* probe, initialize and default to alias 22Dh /sbalias:dsp */
-};
-
-extern struct sndsb_probe_opts sndsb_probe_options;
-
-#if TARGET_MSDOS == 32
-extern signed char sndsb_nmi_32_hook;
-#endif
-
-#if TARGET_MSDOS == 32 && !defined(TARGET_WINDOWS)
-/* TODO: This should be moved into the hw/DOS library */
-extern unsigned char nmi_32_hooked;
-extern void (interrupt *nmi_32_old_vec)();
-#endif
-
-struct sndsb_mixer_control {
- unsigned char index;
- unsigned char offset:4;
- unsigned char length:4;
- const char* name;
-};
-
-extern const char *sndsb_dspoutmethod_str[SNDSB_DSPOUTMETHOD_MAX];
-extern const char *sndsb_mixer_chip_name[SNDSB_MIXER_MAX];
-extern struct sndsb_ctx sndsb_card[SNDSB_MAX_CARDS];
-extern signed char gallant_sc6600_map_to_dma[4];
-extern signed char gallant_sc6600_map_to_irq[8];
-extern const char* sndsb_adpcm_mode_str[4];
-extern struct sndsb_ctx *sndsb_card_blaster;
-extern int sndsb_card_next;
-
-struct sndsb_ctx *sndsb_by_base(uint16_t x);
-struct sndsb_ctx *sndsb_by_mpu(uint16_t x);
-struct sndsb_ctx *sndsb_by_irq(int8_t x);
-struct sndsb_ctx *sndsb_by_dma(uint16_t x);
-struct sndsb_ctx *sndsb_alloc_card();
-int init_sndsb();
-void free_sndsb();
-void sndsb_free_card(struct sndsb_ctx *c);
-struct sndsb_ctx *sndsb_try_blaster_var();
-const char *sndsb_mixer_chip_str(uint8_t c);
-int sndsb_read_dsp(struct sndsb_ctx *cx);
-int sndsb_read_dsp_timeout(struct sndsb_ctx *cx,unsigned long timeout_ms);
-int sndsb_reset_dsp(struct sndsb_ctx *cx);
-int sndsb_read_mixer(struct sndsb_ctx *cx,uint8_t i);
-void sndsb_write_mixer(struct sndsb_ctx *cx,uint8_t i,uint8_t d);
-int sndsb_probe_mixer(struct sndsb_ctx *cx);
-int sndsb_mpu_command(struct sndsb_ctx *cx,uint8_t d);
-int sndsb_mpu_write(struct sndsb_ctx *cx,uint8_t d);
-int sndsb_mpu_read(struct sndsb_ctx *cx);
-int sndsb_probe_mpu401(struct sndsb_ctx *cx);
-int sndsb_write_dsp(struct sndsb_ctx *cx,uint8_t d);
-int sndsb_write_dsp_timeout(struct sndsb_ctx *cx,uint8_t d,unsigned long timeout_ms);
-int sndsb_write_dsp_timeconst(struct sndsb_ctx *cx,uint8_t tc);
-int sndsb_query_dsp_version(struct sndsb_ctx *cx);
-int sndsb_init_card(struct sndsb_ctx *cx);
-int sndsb_try_base(uint16_t iobase);
-int sndsb_interrupt_reason(struct sndsb_ctx *cx);
-int sndsb_reset_mixer(struct sndsb_ctx *cx);
-int sndsb_dsp_out_method_supported(struct sndsb_ctx *cx,unsigned long wav_sample_rate,unsigned char wav_stereo,unsigned char wav_16bit);
-int sndsb_write_dsp_blocksize(struct sndsb_ctx *cx,uint16_t tc);
-int sndsb_write_dsp_outrate(struct sndsb_ctx *cx,unsigned long rate);
-uint32_t sndsb_read_dma_buffer_position(struct sndsb_ctx *cx);
-int sndsb_shutdown_dma(struct sndsb_ctx *cx);
-int sndsb_setup_dma(struct sndsb_ctx *cx);
-int sndsb_prepare_dsp_playback(struct sndsb_ctx *cx,unsigned long rate,unsigned char stereo,unsigned char bit16);
-int sndsb_begin_dsp_playback(struct sndsb_ctx *cx);
-int sndsb_stop_dsp_playback(struct sndsb_ctx *cx);
-void sndsb_send_buffer_again(struct sndsb_ctx *cx);
-int sndsb_determine_ideal_dsp_play_method(struct sndsb_ctx *cx);
-void sndsb_choose_mixer(struct sndsb_ctx *card,signed char override);
-int sndsb_submit_buffer(struct sndsb_ctx *cx,unsigned char FAR *ptr,uint32_t phys,uint32_t len,uint32_t user,uint8_t loop);
-int sndsb_assign_dma_buffer(struct sndsb_ctx *cx,struct dma_8237_allocation *dma);
-unsigned char sndsb_rate_to_time_constant(struct sndsb_ctx *cx,unsigned long rate);
-unsigned int sndsb_ess_set_extended_mode(struct sndsb_ctx *cx,int enable);
-int sndsb_ess_read_controller(struct sndsb_ctx *cx,int reg);
-int sndsb_ess_write_controller(struct sndsb_ctx *cx,int reg,unsigned char value);
-void sndsb_irq_continue(struct sndsb_ctx *cx,unsigned char c);
-unsigned int sndsb_will_dsp_nag(struct sndsb_ctx *cx);
-
-int sb_nmi_32_auto_choose_hook();
-#if TARGET_MSDOS == 32
-void do_nmi_32_unhook();
-void do_nmi_32_hook();
-#else
-# define do_nmi_32_unhook()
-# define do_nmi_32_hook()
-#endif
-
-static inline unsigned char sndsb_ctx_to_index(struct sndsb_ctx *c) {
- return (unsigned char)(((size_t)c - (size_t)sndsb_card) / sizeof(struct sndsb_ctx));
-}
-
-static inline struct sndsb_ctx *sndsb_index_to_ctx(unsigned char c) {
- return sndsb_card + c;
-}
-
-static inline int sndsb_recommend_vm_wait(struct sndsb_ctx *cx) {
- /* Microsoft Windows XP and NTVDM.EXE Sound Blaster emulation:
- * - Emulation is terrible. Audio can skip and stutter slightly.
- * Giving up your timeslice only guarantees it will stutter a lot *WORSE* */
- if (cx->windows_emulation && cx->windows_xp_ntvdm) return 0;
-
- /* Microsoft Windows XP and VDMSOUND. Yielding is recommended,
- * but you will get very stuttery sound with small block sizes! */
- if (cx->windows_emulation && cx->buffer_irq_interval < (cx->buffer_rate/4)) return 0;
-
- /* otherwise, yes. go ahead */
- return 1;
-}
-
-static inline void sndsb_interrupt_ack(struct sndsb_ctx *cx,unsigned char c) {
- if (c & 1) inp(cx->baseio + SNDSB_BIO_DSP_READ_STATUS);
- if (c & 2) inp(cx->baseio + SNDSB_BIO_DSP_READ_STATUS16);
-}
-
-static inline void sndsb_dsp_direct_output(struct sndsb_ctx *cx,unsigned char c) {
- sndsb_write_dsp(cx,0x10);
- sndsb_write_dsp(cx,c);
-}
-
-void sndsb_main_idle(struct sndsb_ctx *cx);
-
-/* Sound Blaster ADPCM encoding routines */
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
-unsigned char sndsb_encode_adpcm_4bit(unsigned char samp);
-unsigned char sndsb_encode_adpcm_2bit(unsigned char samp);
-unsigned char sndsb_encode_adpcm_2_6bit(unsigned char samp,unsigned char b2);
-void sndsb_encode_adpcm_set_reference(unsigned char c,unsigned char mode);
-void sndsb_encode_adpcm_reset_wo_ref(unsigned char mode);
-void sndsb_alt_lite_probe_irq(struct sndsb_ctx *cx);
-void sndsb_manual_probe_irq(struct sndsb_ctx *cx);
-void sndsb_manual_probe_dma(struct sndsb_ctx *cx);
-#endif
-
-void sndsb_write_mixer_entry(struct sndsb_ctx *sb,struct sndsb_mixer_control *mc,unsigned char nb);
-unsigned char sndsb_read_mixer_entry(struct sndsb_ctx *sb,struct sndsb_mixer_control *mc);
-unsigned long sndsb_real_sample_rate(struct sndsb_ctx *cx);
-
-uint32_t sndsb_recommended_dma_buffer_size(struct sndsb_ctx *ctx,uint32_t limit);
-
-void sndsb_timer_tick_directi_data(struct sndsb_ctx *cx);
-void sndsb_timer_tick_directi_cmd(struct sndsb_ctx *cx);
-void sndsb_timer_tick_directo_data(struct sndsb_ctx *cx);
-void sndsb_timer_tick_directo_cmd(struct sndsb_ctx *cx);
-
-const char *sndsb_ess_chipset_str(unsigned int c);
-
-#if TARGET_MSDOS == 32
-int sb_nmi_32_auto_choose_hook();
-#endif
-
+++ /dev/null
-
-/* Additional support functions for Sound Blaster 16 ISA Plug & Play based cards.
- * This is compiled into a separate library (sndsbpnp.lib) so that a programmer
- * can include it only if they want to handle the cards directly. In most cases,
- * such as a game, the DOS user is expected to use an external utility such as
- * the Creative PnP utilities to setup and assign resources to the Sound Blaster
- * in a way that works with traditional DOS applications and/or the sndsb library.
- * The ISAPNP library can be a bit top heavy and can add significant bloat to
- * your program especially if you don't need it.
- *
- * This code requires at link time:
- * sndsb Sound Blaster library
- * isapnp ISA Plug & Play support library */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/sndsb/sndsb.h>
-#include <hw/isapnp/isapnp.h>
-#include <hw/sndsb/sndsbpnp.h>
-
-int isa_pnp_is_sound_blaster_compatible_id(uint32_t id,char const **whatis) {
- int r=0;
-
- /* if it's an ESS product... */
- if (ISAPNP_ID_FMATCH(id,'E','S','S')) {
- if (ISAPNP_ID_LMATCH(id,0x0100)) { /* ESS0100 */
- /* On an old Pentium 120MHz laptop this does not show
- * up in PnP enumeration but is instead reported as
- * a device node by the PnP BIOS.
- *
- * Port 0x220 length 0x10
- * Port 0x388 length 0x04
- * IRQ 9
- * DMA channel 1 */
- *whatis = "ES688 Plug And Play AudioDrive";
- r = 1;
- }
- }
- /* ESS/Compaq product */
- else if (ISAPNP_ID_FMATCH(id,'C','P','Q')) {
- if (ISAPNP_ID_LMATCH(id,0xB040)) { /* CPQB040 ES1887 (Compaq) */
- /* Seen on a late 90's Compaq */
- *whatis = "ES1887 Compaq";
- r = 1;
- }
- }
- /* Yamaha product */
- else if (ISAPNP_ID_FMATCH(id,'Y','M','H')) {
- if (ISAPNP_ID_LMATCH(id,0x0021)) { /* YMH0021 OPL3-SAx (TODO: Which one? SA2 or SA3) */
- /* Seen on a late 90's Toshiba laptop (1997-ish) */
- *whatis = "Yamaha OPL3-SAx";
- r = 1;
- }
- }
- /* if it's a creative product... */
- else if (ISAPNP_ID_FMATCH(id,'C','T','L')) {
- if (ISAPNP_ID_LMATCH(id,0x0070)) { /* CTL0070 */
- /* For ref (configuration regs):
- * IO[0] = Base I/O port
- * IO[1] = MPU I/O port
- * IO[2] = OPL3 I/O port
- * IRQ[0] = Interrupt request line
- * DMA[0] = 8-bit DMA channel
- * DMA[1] = 16-bit DMA channel
- */
- *whatis = "Creative ViBRA16C PnP";
- r = 1;
- }
- else if (ISAPNP_ID_LMATCH(id,0x00C3)) { /* CTL00C3 */
- /* For ref (configuration regs):
- * IO[0] = Base I/O port
- * IO[1] = MPU I/O port
- * IO[2] = OPL3 I/O port
- * IRQ[0] = Interrupt request line
- * DMA[0] = 8-bit DMA channel
- * DMA[1] = 16-bit DMA channel
- */
- *whatis = "Creative AWE64 PnP";
- r = 1;
- }
- else if (ISAPNP_ID_LMATCH(id,0x00B2)) { /* CTL00B2 */
- /* For ref (configuration regs):
- * IO[0] = Base I/O port
- * IO[1] = MPU I/O port
- * IO[2] = OPL3 I/O port
- * IRQ[0] = Interrupt request line
- * DMA[0] = 8-bit DMA channel
- * DMA[1] = 16-bit DMA channel
- */
- *whatis = "Creative AWE64 Gold PnP";
- r = 1;
- }
- else if (ISAPNP_ID_LMATCH(id,0x00F0)) { /* CTL00F0 */
- /* For ref (configuration regs):
- * IO[0] = Base I/O port
- * IO[1] = MPU I/O port
- * IO[2] = OPL3 I/O port
- * IRQ[0] = Interrupt request line
- * DMA[0] = 8-bit DMA channel
- * DMA[1] = 16-bit DMA channel
- */
- *whatis = "Creative ViBRA16X/XV PnP";
- r = 1;
- }
- }
-
- /* Microsoft Virtual PC SB16 PnP emulation? */
- if (ISAPNP_ID('T','B','A',0x0,0x3,0xB,0x0) == id) { /* TBA03B0 */
- *whatis = "Virtual PC Sound Blaster 16 PnP";
- r = 1;
- }
-
- return r;
-}
-
-int isa_pnp_iobase_typical_sb(uint16_t io) {
- return ((io&0xF) == 0) && (io >= 0x210 && io <= 0x280);
-}
-
-int isa_pnp_iobase_typical_mpu(uint16_t io) {
- return ((io&0xF) == 0) && (io == 0x300 || io == 0x330);
-}
-
-void pnp_opl3sax_ioport_chk(struct sndsb_ctx *cx,unsigned int iop,uint16_t base) {
- switch (iop) {
- case 0: cx->baseio = base; break;
- case 1: cx->wssio = base; break;
- case 2: cx->oplio = base; break;
- case 3: cx->mpuio = base; break;
- case 4: cx->opl3sax_controlio = base; break;
- };
-}
-
-int isa_pnp_bios_sound_blaster_get_resources(uint32_t id,unsigned char node,struct isa_pnp_device_node far *devn,unsigned int devn_size,struct sndsb_ctx *cx) {
- unsigned char far *rsc, far *rf;
- struct isapnp_tag tag;
- unsigned int i,iop=0;
-
- cx->baseio = 0;
- cx->gameio = 0;
- cx->aweio = 0;
- cx->oplio = 0;
- cx->mpuio = 0;
- cx->dma16 = -1;
- cx->dma8 = -1;
- cx->irq = -1;
-
- if (devn_size <= sizeof(*devn)) return 0;
- rsc = (unsigned char far*)devn + sizeof(*devn);
- rf = (unsigned char far*)devn + devn_size;
-
- /* NTS: Yamaha OPL3-SAx chipset:
- * - There are two DMA channels, the first one (we care about) is for Sound Blaster emulation
- * - The card also offers a Windows Sound System interface at 0x530, which we don't care about because we focus on Sound Blaster.
- * - I have no plans for this code to use the WSS interface because this library's focus is and should remain on the Sound Blaster
- * interface. I will use the WSS interface however for minor things like reading Sound Blaster emulation IRQ and DMA assignment.
- * I will write a separate library for Windows Sound System type audio playback. If your code wants to support both, it can link
- * to both libraries and pick the best one for your needs. */
- if ( (ISAPNP_ID_FMATCH(id,'E','S','S') && ISAPNP_ID_LMATCH(id,0x0100)) || /* ESS0100 ES688 Plug And Play AudioDrive */
- (ISAPNP_ID_FMATCH(id,'C','P','Q') && ISAPNP_ID_LMATCH(id,0xB040)) || /* CPQB040 ESS1887 Compaq */
- (ISAPNP_ID_FMATCH(id,'Y','M','H') && ISAPNP_ID_LMATCH(id,0x0021)) /* YMH0021 OPL3-SAx (TODO: Which one? SA2 or SA3) */) {
- do {
- if (!isapnp_read_tag(&rsc,rf,&tag))
- break;
- if (tag.tag == ISAPNP_TAG_END)
- break;
-
- switch (tag.tag) {
- case ISAPNP_TAG_IO_PORT: {
- struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
- if (ISAPNP_ID_FMATCH(id,'Y','M','H') && ISAPNP_ID_LMATCH(id,0x0021)) { /* OPL3-SAx */
- pnp_opl3sax_ioport_chk(cx,iop,x->min_range);
- }
- else {
- if (x->min_range == x->max_range) {
- if (x->min_range >= 0x210 && x->min_range <= 0x260 && (x->min_range&0xF) == 0 && x->length == 0x10)
- cx->baseio = x->min_range;
- else if (x->min_range >= 0x388 && x->min_range <= 0x38C && (x->min_range&3) == 0 && x->length == 4)
- cx->oplio = x->min_range;
- else if (x->min_range >= 0x300 && x->min_range <= 0x330 && (x->min_range&0xF) == 0 && x->length >= 2 && x->length <= 4)
- cx->mpuio = x->min_range;
- }
- }
- iop++;
- } break;
- case ISAPNP_TAG_FIXED_IO_PORT: {
- struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
- if (ISAPNP_ID_FMATCH(id,'Y','M','H') && ISAPNP_ID_LMATCH(id,0x0021)) { /* OPL3-SAx */
- pnp_opl3sax_ioport_chk(cx,iop,x->base);
- }
- else {
- if (x->base >= 0x210 && x->base <= 0x280 && (x->base&0xF) == 0 && x->length == 0x10)
- cx->baseio = x->base;
- else if (x->base >= 0x388 && x->base <= 0x38C && (x->base&3) == 0 && x->length == 4)
- cx->oplio = x->base;
- else if (x->base >= 0x300 && x->base <= 0x330 && (x->base&0xF) == 0 && x->length >= 2 && x->length <= 4)
- cx->mpuio = x->base;
- }
- iop++;
- } break;
- case ISAPNP_TAG_IRQ_FORMAT: {
- struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
- for (i=0;i < 16;i++) {
- if (x->irq_mask & (1U << (unsigned int)i)) { /* NTS: PnP devices usually support odd IRQs like IRQ 9 */
- if (cx->irq < 0) cx->irq = i;
- }
- }
- } break;
- case ISAPNP_TAG_DMA_FORMAT: {
- struct isapnp_tag_dma_format far *x = (struct isapnp_tag_dma_format far*)tag.data;
- if (ISAPNP_ID_FMATCH(id,'Y','M','H') && ISAPNP_ID_LMATCH(id,0x0021)) {
- /* the OPL3-SAx lists two DMA channels, the second one marked as bytecount and
- * related to Sound Blaster emulation (Toshiba BIOS) */
- for (i=0;i < 8;i++) {
- if (x->dma_mask & (1U << (unsigned int)i)) {
- if (cx->dma8 < 0 && i < 4 && x->byte_count) cx->dma8 = i;
- }
- }
- }
- else { /* ESS */
- /* the PnP BIOS on the Compaq unit I have for the ESS 1868 lists two
- * DMA channels (second one being DMA channel 5) but only the first
- * one is used for 8 and 16-bit (so then the second one is the 2nd
- * channel for full duplex?) */
- for (i=0;i < 8;i++) {
- if (x->dma_mask & (1U << (unsigned int)i)) {
- if (cx->dma8 < 0 && i < 4) cx->dma8 = i;
- }
- }
- }
- } break;
- }
- } while (1);
-
- if (ISAPNP_ID_FMATCH(id,'Y','M','H') && ISAPNP_ID_LMATCH(id,0x0021)) {
- /* The OPL3-SAx does not have a 16-bit DMA channel */
- }
- else {
- if (cx->dma8 >= 0 && cx->dma16 < 0)
- cx->dma16 = cx->dma8;
- }
- }
- else if (ISAPNP_ID_FMATCH(id,'C','T','L')) {
- /* Do nothing: Creative cards are usually probed from the ISA bus and not reported by the BIOS */
- }
-
- if (cx->baseio == 0) return ISAPNPSB_NO_RESOURCES;
- return 1;
-}
-
-/* NTS: The caller is expected to pnp_wake_scn() then siphon off the device id */
-int isa_pnp_sound_blaster_get_resources(uint32_t id,unsigned char csn,struct sndsb_ctx *cx) {
- cx->baseio = 0;
- cx->gameio = 0;
- cx->aweio = 0;
- cx->oplio = 0;
- cx->mpuio = 0;
- cx->dma16 = -1;
- cx->dma8 = -1;
- cx->irq = -1;
-
- if (ISAPNP_ID_FMATCH(id,'E','S','S')) {
- if (ISAPNP_ID_LMATCH(id,0x0100)) { /* ESS0100 ES688 Plug And Play AudioDrive */
- /* TODO: I don't have any ISA cards of this type, only one integrated into a laptop */
- }
- }
- else if (ISAPNP_ID_FMATCH(id,'C','P','Q')) {
- if (ISAPNP_ID_LMATCH(id,0xB040)) { /* CPQB040 ES1887 (Compaq) */
- /* TODO: I don't have any ISA cards of this type, only one integrated into a laptop */
- }
- }
- else if (ISAPNP_ID_FMATCH(id,'Y','M','H')) {
- if (ISAPNP_ID_LMATCH(id,0x0021)) { /* YMH0021 OPL3-SAx (TODO: Which one? SA2 or SA3) */
- /* TODO: I don't have any ISA cards of this type, only one integrated into a laptop */
- }
- }
- else if (ISAPNP_ID_FMATCH(id,'C','T','L')) {
- /* Creative SB PnP cards are fairly consistent on the resource layout. If you have one that this
- * code fails to match, feel free to add it here */
- if ( ISAPNP_ID_LMATCH(id,0x0070) || /* CTL0070 Creative ViBRA16C PnP */
- ISAPNP_ID_LMATCH(id,0x00B2) || /* CTL00B2 Creative AWE64 Gold PnP */
- ISAPNP_ID_LMATCH(id,0x00C3) || /* CTL00C3 Creative AWE64 PnP */
- ISAPNP_ID_LMATCH(id,0x00F0)) { /* CTL00F0 Creative ViBRA16X/XV PnP */
- /* For ref (configuration regs):
- * IO[0] = Base I/O port
- * IO[1] = MPU I/O port
- * IO[2] = OPL3 I/O port
- * IRQ[0] = Interrupt request line
- * DMA[0] = 8-bit DMA channel
- * DMA[1] = 16-bit DMA channel
- */
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x00); /* main device */
-
- cx->baseio = isa_pnp_read_io_resource(0);
- if (cx->baseio == 0 || cx->baseio == 0xFFFF) cx->baseio = 0;
- cx->mpuio = isa_pnp_read_io_resource(1);
- if (cx->mpuio == 0 || cx->mpuio == 0xFFFF) cx->mpuio = 0;
- cx->oplio = isa_pnp_read_io_resource(2);
- if (cx->oplio == 0 || cx->oplio == 0xFFFF) cx->oplio = 0;
- cx->dma8 = isa_pnp_read_dma(0);
- if ((cx->dma8&7) == 4) cx->dma8 = -1;
- cx->dma16 = isa_pnp_read_dma(1);
- if ((cx->dma16&7) == 4) cx->dma16 = -1;
- cx->irq = isa_pnp_read_irq(0);
- if ((cx->irq&0xF) == 0) cx->irq = -1;
-
- /* logical device #1: gameport */
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x01); /* main device */
-
- cx->gameio = isa_pnp_read_io_resource(0);
- if (cx->gameio == cx->baseio || cx->gameio == 0 || cx->gameio == 0xFFFF) cx->gameio = 0;
-
- /* SB AWE: logical device #2: wavetable */
- if (ISAPNP_ID_LMATCH(id,0x00C3) || ISAPNP_ID_LMATCH(id,0x00B2)) {
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x02); /* main device */
-
- cx->aweio = isa_pnp_read_io_resource(0);
- if (cx->aweio == cx->baseio || cx->aweio == 0 || cx->aweio == 0xFFFF) cx->aweio = 0;
- }
- }
- }
-
- if (cx->baseio == 0) return ISAPNPSB_NO_RESOURCES;
- return 1;
-}
-
-/* try device from ISA PnP BIOS device node (reported by BIOS not probed directly by us) */
-int sndsb_try_isa_pnp_bios(uint32_t id,uint8_t node,struct isa_pnp_device_node far *devn,unsigned int devn_size) {
- struct sndsb_ctx *cx;
- int ok = 0;
-
- cx = sndsb_alloc_card();
- if (cx == NULL) return ISAPNPSB_TOO_MANY_CARDS;
-
- /* now extract ISA resources and init the card */
- ok = isa_pnp_bios_sound_blaster_get_resources(id,node,devn,devn_size,cx);
- if (ok < 1) {
- sndsb_free_card(cx);
- return ok;
- }
-
- /* try to init. note the init_card() function needs to know this is a PnP device. */
- cx->pnp_id = id;
- cx->pnp_bios_node = node;
- if (!sndsb_init_card(cx)) {
- sndsb_free_card(cx);
- return ISAPNPSB_FAILED;
- }
-
- isa_pnp_is_sound_blaster_compatible_id(cx->pnp_id,&cx->pnp_name);
- return 1;
-}
-
-/* try device from ISA PnP device by CSN (card select number) */
-int sndsb_try_isa_pnp(uint32_t id,uint8_t csn) {
- struct sndsb_ctx *cx;
- int ok = 0;
-
- cx = sndsb_alloc_card();
- if (cx == NULL) return ISAPNPSB_TOO_MANY_CARDS;
-
- /* now extract ISA resources and init the card */
- ok = isa_pnp_sound_blaster_get_resources(id,csn,cx);
- if (ok < 1) {
- sndsb_free_card(cx);
- return ok;
- }
-
- /* try to init. note the init_card() function needs to know this is a PnP device. */
- cx->pnp_id = id;
- cx->pnp_csn = csn;
- if (!sndsb_init_card(cx)) {
- sndsb_free_card(cx);
- return ISAPNPSB_FAILED;
- }
-
- isa_pnp_is_sound_blaster_compatible_id(cx->pnp_id,&cx->pnp_name);
- return 1;
-}
-
+++ /dev/null
-
-/* NTS: The caller is expected to pnp_wake_scn() then siphon off the device id */
-int isa_pnp_sound_blaster_get_resources(uint32_t id,unsigned char csn,struct sndsb_ctx *cx);
-int isa_pnp_bios_sound_blaster_get_resources(uint32_t id,unsigned char node,struct isa_pnp_device_node far *devn,unsigned int devn_size,struct sndsb_ctx *cx);
-/* NTS: same for this function */
-int sndsb_try_isa_pnp(uint32_t id,uint8_t csn);
-int sndsb_try_isa_pnp_bios(uint32_t id,uint8_t node,struct isa_pnp_device_node far *devn,unsigned int devn_size);
-
-/* possible error codes (zero or negative) from try_isa_pnp and get_resources */
-
-/* Error: The Sound Blaster failed the I/O and DSP checks */
-#define ISAPNPSB_FAILED 0
-/* Error: PnP card found but none or insufficient resources are assigned to it (and this library by default will not auto-assign for OBVIOUS SAFETY REASONS) */
-#define ISAPNPSB_NO_RESOURCES -1
-/* Error: There are already too many cards being tracked by the library */
-#define ISAPNPSB_TOO_MANY_CARDS -2
-
-/* end error codes */
-
-int isa_pnp_is_sound_blaster_compatible_id(uint32_t id,char const **whatis);
-int isa_pnp_iobase_typical_mpu(uint16_t io);
-int isa_pnp_iobase_typical_sb(uint16_t io);
-
+++ /dev/null
-
-/* TODO: The ESS control register dump should show text on the side that provides a
- * visual "guide" on what the bits are supposed to mean (slightly different
- * text for ESS 688 vs ESS 1887, etc.) so the user has more guidance in poking
- * around those control registers */
-
-/* Notes:
- * ESS 688 PnP AudioDrive:
- * - Plug and Play enumerated from the BIOS on a Sharp laptop (uses IRQ 9?!?)
- * - Supports most Sound Blaster Pro commands and emulates the mixer
- * - Nag mode works
- * - No DSP copyright string
- * - DSP does not wait if IRQ is not ACKed
- * - Supports ADPCM single-cycle commands!
- * - Does NOT support ADPCM auto-init commands
- * - DSP direct DAC commands are not rate-limited, it's possible to play up to
- * about 60KHz using direct DAC output!
- * - Also carries or emulates Adlib (OPL3) and joystick port
- *
- * Gallant SC-660 clone:
- * - Does not support auto-init ADPCM, though all single-cycle ADPCM commands are
- * correctly supported.
- * - DSP time constant is rate limited, but there's a minor bug in how it does it:
- *
- * If you submit 4000...25000Hz -> You get 4000...25000Hz
- * If you submit 25000...35000Hz -> You get 25000Hz
- * If you submit 35000...44100Hz -> You get 24000Hz?
- *
- * This bug does not affect DSP 4.xx SB16 commands and does not affect
- * high-speed DSP commands.
- * - SB16 commands are supported... kind of. The card is obviously coded to expect
- * only the auto-init + FIFO form of the DSP 4.xx commands (any other combination,
- * such as single-cycle with/without FIFO or auto-init without FIFO, is ignored by
- * the card).
- * - Nag mode has no effect for DSP 4.xx commands, since single-cycle is impossible.
- * - Does not stop playback if IRQ not acknowledged.
- *
- * Sound Blaster 2.0 (Creative):
- * - DSP 1.xx playback maxes out at 22050Hz (not 23KHz documented by Creative)
- * - DSP 2.xx playback maxes out at 46000Hz (not 44.1KHz documented by Creative)
- * - DSP auto-init ADPCM supported
- * - ADPCM 4-bit maxes out at 12KHz
- * - ADPCM 2.6-bit maxes out at 12KHz (not 13KHz documented by Creative)
- * - ADPCM 2-bit maxes out at 15KHz (not 11KHz documented by Creative)
- */
-
-/*=========================================OLD===================================================*/
-/* Emulator testing:
- * Sun/Oracle VirtualBox:
- * - Works perfectly
- * - Does not emulate ADPCM playback
- * - Does not do recording... AT ALL
- * - Supports changing the SB16 configuration byte, but only the IRQ. Changing the DMA
- * channel has no effect apparently
- * Microsoft Virtual PC:
- * - Works perfectly, except for DSP 1.xx single-cycle playback where
- * it signals the IRQ immediately after playback begins, and can cause
- * an IRQ storm that overflows the stack and crashes us
- * - Does not emulate ADPCM playback
- * - Does record, using local system mic in
- * - Supports changing the SB16 configuration byte, but changes apparently have no effect
- * on the resources assigned to the card. This is understandable since according to
- * the isapnp test program Virtual PC is emulating a Plug & Play type Sound Blaster.
- * But for some strange reason, the ISA PnP BIOS and PNP emulation then reports the
- * I/O port as fixed and only lists one possible IRQ and DMA combination. The PnP
- * device is also active by default, contrary to actual PnP Sound Blaster cards.
- * DOSBox 0.74
- * - Works perfectly (with sbtype = sb1, sb2, sbpro1, sbpro2, and sb16)
- * - Emulates ADPCM playback perfectly, except for auto-init versions of the command
- * - Fails to emulate recording commands. Command 0x24 is emulated only enough to
- * return silence immediately, so DONT play with recording under DOSBox unless you
- * want your (emulated) C: drive to quickly fill up with silence!
- * - Changing SB16 configuration works (though for some reason, you get noise and garbage
- * if you attempt to assign the SB16 to DMA channel 0)
- *
- * Real hardware testing:
- * VIA EPIA motherboard with BIOS Sound Blaster emulation:
- * - Emulates a Pro only (DSP v3.xx)
- * - Actual hardware is PCI device, a proprietary VIA interface
- * - For some reason, no sound can be heard on the output, even if we play with the mixer
- * - Audio hardware doesn't record anything except silence. Either it's faking the record
- * commands by filling the buffer with 0x7F or it takes proprietary commands to connect
- * the audio source within the chip
- * Toshiba Satellite 465CDX laptop:
- * - Chipset is Yamaha OPL3-SA2 PCI chipset that emulates a Sound Blaster
- * - Emulates a Pro only (DSP v3.1 and CT1345 mixer)
- * - Mixer seems to ignore almost every setting except stereo bit and master+voice volume
- * controls, and even then, seems to support either full volume or (if any set to zero)
- * full silence.
- * - Has Windows Sound System on 0x5x0 (x=3,4,5,6)
- * - Supports ADPCM playback, but only the 4-bit version. If asked to do the 2.6 and 3-bit
- * versions, the card cycles DMA as if playing uncompressed 8-bit but does not make any
- * noise.
- * - Does not return copyright string
- * - Supports auto-init ADPCM playback
- * - Emulates recording commands, but does not actually record (it "records" samples of 0x00)
- * - Otherwise works perfectly
- * - Interesting hardware bug: If you use Sound Blaster Pro stereo and set a time interval to
- * try to play 8-bit 44010Hz stereo (beyond what an actual Sound Blaster is supposed to be
- * able to do) and the main loop is polling the DMA channel, the output runs at something
- * like 320000Hz (like a Sound Blaster) but it has a noisy sound to it as if the constant
- * polling is causing serious jitter in the hardware. When the main loop stops polling, the
- * jitter seems to go away.
- * Old Pentium/386/486 system with Reveal v1.10 SC-6600 card (ISA)
- * - Marked as Reveal, apparently referred to in Linux kernel as Gallant SC-6600
- * - Has a Crystal Semiconductor CS4321 chip
- * - Emulates a weird hybrid of Sound Blaster functions: It reports itself as a Sound Blaster
- * Pro (DSP v3.5) yet it supports Sound Blaster 16 DSP functions, but unlike a SB16 it only
- * emulates the Sound Blaster Pro mixer settings and lacks the SB16 "configuration byte"
- * mixer registers (0x80-0x81)
- * - Is is "plug and play" in the sense that through the Sound Blaster interface there are
- * secret DSP commands you can issue to read and set the hardware configuration (such as,
- * IRQ and DMA channels)
- * - Emulates recording and playback perfectly
- * - Emulates ADPCM playback, does NOT emulate auto-init ADPCM commands
- * - Sample rate maxes out at 44.1KHz even though the DSP command set could conceiveably support
- * rates up to 64KHz
- * - Supports nonstandard "flipped sign" 8-bit and 16-bit PCM via DSP 4.xx playback commands
- * - Supports DSP 4.xx recording commands
- * - Unlike the SB16, it plays both 8-bit and 16-bit on the same DMA channel (and only on the
- * same DMA channel)
- * - Also has Windows Sounds System at 0x530 (or other ports if configured so)
- * - Raw view of the mixer registers suggests their Pro mixer emulation only decodes the lower
- * 6 bits of the index register. This means for whatever index you write the actual value
- * is (index % 64).
- * - Fully supports IRQ and DMA reassignment from this program
- * - The DSP on this one is slightly slower than normal. In fact this card motivated me to
- * extend the timeout values in the DSP read/write functions because the previous values
- * would time out too soon and fail communication with the DSP on this card
- * - On the Pentium MMX 200MHz system: Apparently DMA channel 3 is not a good choice. It seems
- * to play 1000-2000 samples or so then stall out completely. Not sure what that's about.
- * All IRQ choices work though, except of course for IRQ 9 (which is probably taken by the
- * motherboard or PCI device anyway).
- * Old Pentium/386/486 system with Creative CT1350B Sound Blaster (ISA 8-bit)
- * - A Sound Blaster 2.0, but not a Sound Blaster Pro
- * - DSP v2.2
- * - No mixer chip. Nothing responds to base+4 and base+5
- * - The DSP has a hardware bug where attempting to play >= 17KHz without using hispeed mode
- * causes audible warbling if anything else is using DMA (such as: reading from the floppy
- * drive). It's almost like the DSP in non-hispeed mode is sloppy on when to initiate
- * another DMA transfer of a sample, hence, the reason Creative went about implementing
- * hispeed mode in the first place? Perhaps, if the DSP is a specialized CPU, hispeed mode
- * means that it goes into a tight loop that focuses only on the playback (instead of a
- * more general loop that listens for certain DSP commands while playing), which is why
- * Creative says it needs a DSP reset to break out. Right?
- * - Supports ADPCM playback and auto-init
- * - Playback maxes out at 44.1KHz, recording at 22.05Hz
- * - The old detection code failed on this card, would not work until sndsb.c added code
- * to reset the DSP per IRQ and DMA test
- * - Question: If the sound card has a mic in and line in, but no mixer chip to choose, then
- * how does it pick the input to capture from? Does it amplify the mic in and digitize the
- * mix of the two? Or does it have one of the jacks wired to cut out the other when something
- * is inserted? (some equipment has a metal piece that when displaced by the plug, shorts to
- * another metal piece and that short is sensed by the equipment as a signal that something
- * is plugged in)
- * - The mic in works (I accidentally recorded loud distorted music from my radio because
- * the jacks aren't labeled and had the patch cable in the mic in jack) but it doesn't seem
- * to like modern computer mics, hmm... Line in works perfectly fine however.
- * - Lack of input filters definitely means you don't want to record on this DSP at anything
- * below 8KHz, it will sound like crap. In fact, playback below 8KHz isn't really worth it
- * either...
- * - Despite being a genuine Creative product, the DSP copyright command does not return a string
- * - Does not appear to have MPU401 MIDI I/O, the large plug on the back is most likely only
- * a joystick port
- * - This is the older variety of Sound Blaster where for DSP playback (even "direct" mode)
- * you MUST use DSP commands 0xD1 and 0xD3 (Speaker On/Off) to turn the DSP on for playback
- * and DSP off when done. Playing sound while the speaker is off seems to yield only quiet
- * staticky noise from the speakers that somewhat resembles what you are trying to play
- * (when it's supposed to be silent!).
- * - Recording seems to cause a high-pitched but quiet whining sound from the speaker output.
- * This software mitigates that somewhat by shutting off the speakers during capture, but
- * it's still kind of there.
- * Old Pentium/386/486 system with Creative CT4170 Sound Blaster 16 ViBRA16XV (Plug & Play)
- * - PnP ID CTL00F0
- * - DSP v4.16
- * - SB16 mixer
- * - All PnP resources are like a Sound Blaster, except that at boot the card leaves them
- * disabled until a PnP configuration utility assigns resources and enables them
- * - Contains DSP copyright string as expected
- * - Just as documented by Creative, the card is PnP based and the configuration bytes in
- * the mixer are read only, not changeable
- * - The DSP appears to max out at 48KHz. Apparently 48KHz is also possible when using the
- * DSP 2/3.xx "high speed" commands. DSP 1.xx commands however max out at 24KHz.
- * - Auto-init ADPCM and all ADPCM modes are supported
- * - The DSP can be instructed to play non-standard "flipped sign" formats (16-bit unsigned
- * and 8-bit signed) via the DSP 4.xx commands
- * - Card appears to allow bass/treble controls but they have no noticeable effect on the
- * sound as far as I can tell
- * - Speaks PnP protocol to list 0x2x0-0x2xF (x=2,4,6,8) DSP and mixer region, 0x388 OPL3
- * region. and 0x3x0-0x3x1 (x=0,3) MPU MIDI region, as well as a second "logical" device
- * that is the game port (0x200-0x207) (CTL7005). According to PnP configuration data,
- * it supports moving the OPL3 interface to 0x394 (?).
- * - When Intel/Microsoft's ISA PnP spec said to wait 250us per I/O pair read during
- * the configuration read, they weren't kidding. The isapnp test program could not
- * properly read the VIBRA's PnP configuration until the 250 delay was added. So whatever
- * hardware Creative added is not fast enough for a Pentium Pro to read configuration
- * from it full-speed?
- * - There appear to be extra mysterious mixer bytes at the 0xFD-0xFE range. What are they?
- * Old Pentium/386/486 system with Creative CT4180 Sound Blaster 16 ViBRA16C (Plug & Play)
- * - PnP ID CTL0070
- * - DSP v4.13
- * - Same comments as the ViBRA16X listed above
- * Old Pentium/386/486 system with Creative CT4500 Sound Blaster AWE64 (Plug & Play)
- * - PnP ID CTL00C3
- * - DSP v4.16
- * - For some interesting reason the hardware mixer defaults to 75% master & PCM volume
- * - The bass & treble mixer controls actually work!
- * - The raw mixer dump shows a whole row of mystery bytes at 0x88-0x8E and 0xFD-0xFF
- * - Supports flipped sign nonstandard PCM formats (8-bit signed, 16-bit unsigned)
- * - DSP maxes out at 48KHz (4.xx commands and 2/3.xx high-speed mode commands), or
- * 24KHz (1.xx commands)
- * - Supports ADPCM modes and auto-init
- * - Also has the AWE WaveTable interface on PnP ID CTL0022 logical device #2 (just after the GamePort)
- * where the WaveTable interface can be assigned to I/O port 0x6x0-0x6x3 (4 I/O ports long)
- * where x is 2, 4, 6, or 8
- * Old Pentium/386/486 system with Creative CT4540 Sound Blaster AWE64 Gold (Plug & Play)
- * - PnP ID CTL00B2
- * - DSP v4.16
- * - Also has the AWE WaveTable interface on PnP ID CTL0023 logical device #2 (just after the GamePort)
- * where the WaveTable interface can be assigned to I/O port 0x6x0-0x6x3 (4 I/O ports long)
- * where x is 2, 4, 6, or 8
- * - Same comments as for AWE64 CT4500 listed above
- * Old Pentium system with Gravis Ultrasound MAX and SBOS (Sound Blaster emulation)
- * - DSP v2.1
- * - Quality is OK, emulation is terrible
- * - Does not properly emulate auto-init DMA playback
- * - Sound Blaster 1.x style playback (manual-init via IRQ) shows
- * DMA playback pointer by too fast before the IRQ actually fires.
- * So much for any accurate timing, eh?
- * - Does not emulate Sound Blaster Pro stereo
- * - Does not emulate ADPCM playback. And if you try, further audio
- * output is corrupted/unusable.
- * - Obviously doesn't know the "DSP copyright string" command, we read
- * back a string of smileys (ascii code 0x01)
- * Old Pentium system with Gravis Ultrasound MAX and MEGA-EM SoundBlaster emulation
- * - Can't say for sure, MEGA-EM doesn't recognize DSP command 0xE3.
- * But rather than kindly emulate a "I dunno" response it chooses
- * to hard-lock the machine and display an error message complaining
- * about not understanding the DSP command. Thanks >:(
- * - But MEGA-EM itself is very crashy. So crashy that if you EMUSET
- * and then run anything that uses a DOS extender like DOS4G/W your
- * computer will hard-crash and reset. (FIXME: Or perhaps this is a
- * problem with using EMM386.EXE from a Windows 95 bootdisk?)
- * - I was only able to do some semblance of SB testing by temporarily
- * commenting out the DSP copyright string part of the code.
- * - MEGA-EM reports itself as DSP version 1.3. Seriously?!?
- * For a "Sound Blaster compatible" in the 1993-1997 timeframe
- * that's pretty pathetic!
- * - MEGA-EM does not emulate anything above Sound Blaster. Not even
- * Pro commands. It will do the same hard-crash on commands 0x1C and
- * on SB16 commands like 0x41.
- * - DMA runs too fast relative to IRQ activity, just like SBOS.
- * - Does not emulate any mixer chip.
- * - Doesn't really understand Creative's ADPCM format, but fakes it...
- * badly. Doesn't decode it right.
- * - Unloading MEGA-EM doesn't resolve the crashing. But not running
- * SMARTDRV, and unloading MEGA-EM prior to using a DOS extender
- * does resolve it. If SMARTDRV is already loaded, you can tell
- * SMARTDRV to disable caching on all drives and that will have the
- * same effect. So basically, the hard crash is a combination of
- * EMM386.EXE virtualization and programs trying to use extended RAM.
- * Hmm...
- * Microsoft Windows XP with SB emulation enabled [applies also to Windows Vista & Windows 7]
- * - Emulates a Sound Blaster 2.1. In other words, the lazy asses at Microsoft
- * couldn't be bothered to emulate Pro stereo, or 16-bit playback.
- * - Buffer intervals must be a struct integer subdivision of the total buffer
- * when doing auto-init playback. Or else, the implementation will just run
- * off into the weeds. Pathetic.
- * - Mixer emulation provides the absolute bare minimum of Sound Blaster controls.
- * Just the master volume, voice control, and CD volume. The lazy asses also
- * didn't bother to emulate the combined effect of Master and Voice volume
- * levels, meaning; if you write the master volume, then the voice volume,
- * the voice volume takes effect, regardless what the master volume was.
- * - Their implementation makes no attempt at emulating the DMA transfer actually
- * happening. So if a program were to watch the DMA counter it would see it
- * abruptly "jump" down by the DMA block size. Pathetic. That's worse than
- * Gravis's SBOS emulation, at least a program there would see DMA moving!
- * - You can't make DMA block sizes too small, or their code sputters and
- * underruns. You can't make it too large (4K or more!) or it audibly drops
- * samples and the audio seems to play too fast! What the fuck Microsoft?
- * - Against every attempt otherwise, it manages to play the prior buffer
- * contents before finally playing what my code is trying to play. Why?
- * - Under Windows XP, something causes this program to eventually hang. Why?
- * Microsoft Windows XP with VDMSOUND.EXE
- * - Works perfectly!
- * - Although, even VDMSOUND.EXE stutters a bit when this program uses the 'tiny'
- * IRQ interval setting, but... that's understandable.
- * - Emulates SB16 mixer byte that stores configuration, but you cause all IRQ
- * activity to stop when you write to it.
- *
- * Card notes:
- * I have a Creative ViBRA16X/XV that is apparently unable to use it's
- * high DMA channel. Independent testing across some Pentium and 486
- * motherboards shows that the card is at fault, on NONE of them am I
- * able to use DMA channels 5, 6, or 7 for 16-bit playback.
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <direct.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/vga/vga.h>
-#include <hw/dos/dos.h>
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/sndsb/sndsb.h>
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/tgusmega.h>
-#include <hw/dos/tgussbos.h>
-#include <hw/dos/tgusumid.h>
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- /* chop features out of the Compact memory model build to ensure all code fits inside 64KB */
- /* don't include FX */
- /* don't include live config */
- /* don't include mixer */
-#else
-# define INCLUDE_FX
-# define SB_MIXER
-# define CARD_INFO_AND_CHOOSER
-# define LIVE_CFG
-# define ISAPNP
-#endif
-
-#ifdef ISAPNP
-#include <hw/isapnp/isapnp.h>
-#include <hw/sndsb/sndsbpnp.h>
-#endif
-
-static struct dma_8237_allocation *sb_dma = NULL; /* DMA buffer */
-
-static struct sndsb_ctx* sb_card = NULL;
-
-enum {
- GOLDRATE_MATCH=0,
- GOLDRATE_DOUBLE,
- GOLDRATE_MAX
-};
-
-static unsigned char animator = 0;
-static int wav_fd = -1;
-static char temp_str[512];
-#ifdef ISAPNP
-static unsigned char far devnode_raw[4096];
-#endif
-static char wav_file[130] = {0};
-static unsigned char wav_stereo = 0,wav_16bit = 0,wav_bytes_per_sample = 1;
-static unsigned long wav_data_offset = 44,wav_data_length = 0,wav_sample_rate = 8000,wav_position = 0,wav_buffer_filepos = 0;
-static unsigned long wav_sample_rate_by_timer_ticks = 1;
-static unsigned long wav_sample_rate_by_timer = 1;
-static unsigned char dont_sb_idle = 0;
-static unsigned char dont_chain_irq = 0;
-static unsigned char wav_playing = 0;
-static unsigned char wav_record = 0;
-static signed char reduced_irq_interval = 0;
-static unsigned char sample_rate_timer_clamp = 0;
-static unsigned char goldplay_samplerate_choice = GOLDRATE_MATCH;
-
-/* fun with Creative ADPCM */
-static unsigned char do_adpcm_ai_warning = 1;
-
-static volatile unsigned char IRQ_anim = 0;
-static volatile unsigned char sb_irq_count = 0;
-
-#ifdef INCLUDE_FX
-/* effects */
-static unsigned int fx_volume = 256; /* 256 = 100% */
-static unsigned int fx_echo_delay = 0; /* number of samples to delay echo */
-#endif
-
-static inline unsigned char xdigit2int(char c) {
- if (c >= '0' && c <= '9')
- return (unsigned char)(c - '0');
- else if (c >= 'a' && c <= 'f')
- return (unsigned char)(c - 'a' + 10);
- else if (c >= 'A' && c <= 'F')
- return (unsigned char)(c - 'A' + 10);
- return 0;
-}
-
-#ifdef INCLUDE_FX
-/*----------------------------- FX: echo ------------------- */
-static uint8_t FAR *fx_echo_buf = NULL;
-static unsigned int fx_echo_ptr = 0;
-static unsigned int fx_echo_alloc = 0;
-static void fx_echo_free() {
- if (fx_echo_buf != NULL) {
-#if TARGET_MSDOS == 32
- free(fx_echo_buf);
-#else
- _ffree(fx_echo_buf);
-#endif
- fx_echo_buf = NULL;
- fx_echo_ptr = 0;
- fx_echo_alloc = 0;
- }
-}
-
-static void fx_echo_check() {
- unsigned int ns;
-
-#if TARGET_MSDOS == 16
- if (fx_echo_delay > 14000)
- fx_echo_delay = 14000;
-#endif
-
- ns = fx_echo_delay * (wav_16bit?2:1) * (wav_stereo?2:1);
- if (ns == fx_echo_alloc) return;
-
- if (fx_echo_buf == NULL) {
-#if TARGET_MSDOS == 32
- fx_echo_buf = malloc(ns);
-#else
- fx_echo_buf = _fmalloc(ns);
-#endif
- }
- else {
-#if TARGET_MSDOS == 32
- free(fx_echo_buf);
- fx_echo_buf = malloc(ns);
-#else
- _ffree(fx_echo_buf);
- fx_echo_buf = _fmalloc(ns);
-#endif
- }
-
- if (fx_echo_buf == NULL)
- return;
-
- fx_echo_alloc = ns;
- fx_echo_ptr = 0;
-
-#if TARGET_MSDOS == 32
- memset(fx_echo_buf,wav_16bit ? 0 : 128,ns);
-#else
- _fmemset(fx_echo_buf,wav_16bit ? 0: 128,ns);
-#endif
-}
-
-static void fx_echo16(int16_t FAR *d,unsigned int samp/*samples x channels*/) {
- long L,R;
-
- if (fx_echo_delay == 0) {
- fx_echo_free();
- return;
- }
- fx_echo_check();
- if (fx_echo_buf == NULL) return;
-
- if (wav_stereo) {
- samp >>= 1;
- while (samp-- != 0) {
- L = (long)d[0] + (((long) *((int16_t FAR*)(&fx_echo_buf[fx_echo_ptr+0])) )*3)/4;
- if (L < -32768L) L = -32768L; else if (L > 32767L) L = 32767L;
- R = (long)d[1] + (((long) *((int16_t FAR*)(&fx_echo_buf[fx_echo_ptr+2])) )*3)/4;
- if (R < -32768L) R = -32768L; else if (R > 32767L) R = 32767L;
- *d++ = *((int16_t FAR*)(&fx_echo_buf[fx_echo_ptr+0])) = L;
- *d++ = *((int16_t FAR*)(&fx_echo_buf[fx_echo_ptr+2])) = R;
- fx_echo_ptr += 4;
- if (fx_echo_ptr >= fx_echo_alloc) fx_echo_ptr = 0;
- }
- }
- else {
- while (samp-- != 0) {
- L = (long)*d + (((long) *((int16_t FAR*)(&fx_echo_buf[fx_echo_ptr])) )*3)/4;
- if (L < -32768L) L = -32768L; else if (L > 32767L) L = 32767L;
- *d++ = *((int16_t FAR*)(&fx_echo_buf[fx_echo_ptr])) = L;
- fx_echo_ptr += 2;
- if (fx_echo_ptr >= fx_echo_alloc) fx_echo_ptr = 0;
- }
- }
-}
-
-static void fx_echo8(unsigned char FAR *d,unsigned int samp/*samples x channels*/) {
- int L,R;
-
- if (fx_echo_delay == 0) {
- fx_echo_free();
- return;
- }
- fx_echo_check();
- if (fx_echo_buf == NULL) return;
-
- if (wav_stereo) {
- samp >>= 1;
- while (samp-- != 0) {
- L = ((int)d[0] - 128) + (((int)fx_echo_buf[fx_echo_ptr] - 128)*3)/4;
- if (L < -128) L = -128; else if (L > 127) L = 127;
- R = ((int)d[1] - 128) + (((int)fx_echo_buf[fx_echo_ptr+1] - 128)*3)/4;
- if (R < -128) R = -128; else if (R > 127) R = 127;
- *d++ = fx_echo_buf[fx_echo_ptr++] = L + 128;
- *d++ = fx_echo_buf[fx_echo_ptr++] = R + 128;
- if (fx_echo_ptr >= fx_echo_alloc) fx_echo_ptr = 0;
- }
- }
- else {
- while (samp-- != 0) {
- L = ((int)*d - 128) + (((int)fx_echo_buf[fx_echo_ptr] - 128)*3)/4;
- if (L < -128) L = -128; else if (L > 127) L = 127;
- *d++ = fx_echo_buf[fx_echo_ptr] = L + 128;
- if (++fx_echo_ptr >= fx_echo_alloc) fx_echo_ptr = 0;
- }
- }
-}
-
-
-/*----------------------------- FX: volume ------------------- */
-static void fx_vol16(int16_t FAR *d,unsigned int samp/*samples x channels*/) {
- long res;
-
- if (fx_volume == 256)
- return;
-
- while (samp-- != 0) {
- res = (((long)*d * (long)fx_volume) >> 8L);
- if (res > 32767)
- *d++ = 32767;
- else if (res < -32768)
- *d++ = -32768;
- else
- *d++ = (int16_t)res;
- }
-}
-
-static void fx_vol8(unsigned char FAR *d,unsigned int samp/*samples x channels*/) {
- long res;
-
- if (fx_volume == 256)
- return;
-
- while (samp-- != 0) {
- res = ((((long)*d - 128L) * (long)fx_volume) >> 8L);
- if (res > 127)
- *d++ = 255;
- else if (res < -128)
- *d++ = 0;
- else
- *d++ = (unsigned char)(res + 0x80L);
- }
-}
-
-/*-----------------------------------------------------------------*/
-static void fx_proc(unsigned char FAR *d,unsigned int samp) {
- if (wav_16bit) {
- fx_echo16((int16_t FAR*)d,samp*(wav_stereo?2:1));
- fx_vol16((int16_t FAR*)d,samp*(wav_stereo?2:1));
- }
- else {
- fx_echo8(d,samp*(wav_stereo?2:1));
- fx_vol8(d,samp*(wav_stereo?2:1));
- }
-}
-#endif /* INCLUDE_FX */
-
-void stop_play();
-
-static void draw_irq_indicator() {
- VGA_ALPHA_PTR wr = vga_alpha_ram;
- unsigned char i;
-
- wr[0] = 0x1E00 | 'S';
- wr[1] = 0x1E00 | 'B';
- wr[2] = 0x1E00 | '-';
- wr[3] = 0x1E00 | 'I';
- wr[4] = 0x1E00 | 'R';
- wr[5] = 0x1E00 | 'Q';
- for (i=0;i < 4;i++) wr[i+6] = (uint16_t)(i == IRQ_anim ? 'x' : '-') | 0x1E00;
-}
-
-static uint32_t irq_0_count = 0;
-static uint32_t irq_0_adv = 1;
-static uint32_t irq_0_max = 1;
-#if TARGET_MSDOS == 32
-static unsigned char irq_0_had_warned = 0;
-#endif
-
-/* IRQ 0 watchdog: when playing audio it is possible to exceed the rate
- that the CPU can possibly handle servicing the interrupt. This results
- in audio that still plays but the UI is "frozen" because no CPU time
- is available. If the UI is not there to reset the watchdog, the ISR
- will auto-stop playback, allowing the user to regain control without
- hitting the RESET button. */
-static volatile uint32_t irq_0_watchdog = 0x10000UL;
-static void irq_0_watchdog_ack() {
- if (irq_0_watchdog != 0UL) {
- irq_0_watchdog += 0x800UL; /* 1/32 of max. This should trigger even if UI is only reduced to tar speeds by ISR */
- if (irq_0_watchdog > 0x10000UL) irq_0_watchdog = 0x10000UL;
- }
-}
-
-static void irq_0_watchdog_reset() {
- irq_0_watchdog = 0x10000UL;
-}
-
-/* WARNING!!! This interrupt handler calls subroutines. To avoid system
- * instability in the event the IRQ fires while, say, executing a routine
- * in the DOS kernel, you must compile this code with the -zu flag in
- * 16-bit real mode Large and Compact memory models! Without -zu, minor
- * memory corruption in the DOS kernel will result and the system will
- * hang and/or crash. */
-static unsigned char old_irq_masked = 0;
-static void (interrupt *old_irq_0)() = NULL;
-static void interrupt irq_0() { /* timer IRQ */
- /* if we're playing the DSP in direct mode, then it's our job to do the direct DAC/ADC commands */
- if (wav_playing && irq_0_watchdog > 0UL) {
- if (sb_card && sb_card->timer_tick_func != NULL)
- sb_card->timer_tick_func(sb_card);
-
- if (--irq_0_watchdog == 0UL) {
- /* try to help by setting the timer rate back down */
- write_8254_system_timer(0); /* restore 18.2 tick/sec */
- irq_0_count = 0;
- irq_0_adv = 1;
- irq_0_max = 1;
- }
- }
-
- /* tick rate conversion. we may run the timer at a faster tick rate but the BIOS may have problems
- * unless we chain through it's ISR at the 18.2 ticks/sec it expects to be called. If we don't,
- * most BIOS services will work fine but some parts usually involving the floppy drive will have
- * problems and premature timeouts, or may turn the motor off too soon. */
- irq_0_count += irq_0_adv;
- if (irq_0_count >= irq_0_max) {
- /* NOTE TO SELF: Apparently the 32-bit protmode version
- has to chain back to the BIOS or else keyboard input
- doesn't work?!? */
- irq_0_count -= irq_0_max;
- old_irq_0(); /* call BIOS underneath at 18.2 ticks/sec */
- }
- else {
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
- }
-}
-
-/* WARNING!!! This interrupt handler calls subroutines. To avoid system
- * instability in the event the IRQ fires while, say, executing a routine
- * in the DOS kernel, you must compile this code with the -zu flag in
- * 16-bit real mode Large and Compact memory models! Without -zu, minor
- * memory corruption in the DOS kernel will result and the system will
- * hang and/or crash. */
-static void (interrupt *old_irq)() = NULL;
-static void interrupt sb_irq() {
- unsigned char c;
-
- sb_irq_count++;
- if (++IRQ_anim >= 4) IRQ_anim = 0;
- draw_irq_indicator();
-
- /* ack soundblaster DSP if DSP was the cause of the interrupt */
- /* NTS: Experience says if you ack the wrong event on DSP 4.xx it
- will just re-fire the IRQ until you ack it correctly...
- or until your program crashes from stack overflow, whichever
- comes first */
- c = sndsb_interrupt_reason(sb_card);
- sndsb_interrupt_ack(sb_card,c);
-
- /* FIXME: The sndsb library should NOT do anything in
- send_buffer_again() if it knows playback has not started! */
- /* for non-auto-init modes, start another buffer */
- if (wav_playing) sndsb_irq_continue(sb_card,c);
-
- /* NTS: we assume that if the IRQ was masked when we took it, that we must not
- * chain to the previous IRQ handler. This is very important considering
- * that on most DOS systems an IRQ is masked for a very good reason---the
- * interrupt handler doesn't exist! In fact, the IRQ vector could easily
- * be unitialized or 0000:0000 for it! CALLing to that address is obviously
- * not advised! */
- if (old_irq_masked || old_irq == NULL || dont_chain_irq) {
- /* ack the interrupt ourself, do not chain */
- if (sb_card->irq >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
- }
- else {
- /* chain to the previous IRQ, who will acknowledge the interrupt */
- old_irq();
- }
-}
-
-static void save_audio(struct sndsb_ctx *cx,uint32_t up_to,uint32_t min,uint32_t max,uint8_t initial) { /* load audio up to point or max */
- unsigned char FAR *buffer = sb_dma->lin;
- VGA_ALPHA_PTR wr = vga_alpha_ram + 80 - 6;
- unsigned char load=0;
- uint16_t prev[6];
- int rd,i,bufe=0;
- uint32_t how;
-
- /* caller should be rounding! */
- assert((up_to & 3UL) == 0UL);
- if (up_to >= cx->buffer_size) return;
- if (cx->buffer_size < 32) return;
- if (cx->backwards) return; /* NTS: When we do support backwards DMA recording, this code will need to reverse the audio then write forwards in WAV */
- if (cx->buffer_last_io == up_to) return;
- if (sb_card->dsp_adpcm != 0) return;
- if (max == 0) max = cx->buffer_size/4;
- if (max < 16) return;
- lseek(wav_fd,wav_data_offset + (wav_position * (unsigned long)wav_bytes_per_sample),SEEK_SET);
-
- if (cx->buffer_last_io == 0)
- wav_buffer_filepos = wav_position;
-
- while (max > 0UL) {
- /* the most common "hang" apparently is when IRQ 0 triggers too much
- and then somehow execution gets stuck here */
- if (irq_0_watchdog < 16UL)
- break;
-
- if (up_to < cx->buffer_last_io) {
- how = (cx->buffer_size - cx->buffer_last_io); /* from last IO to end of buffer */
- bufe = 1;
- }
- else {
- if (up_to <= 8UL) break;
- how = ((up_to-8UL) - cx->buffer_last_io); /* from last IO to up_to */
- bufe = 0;
- }
-
- if (how > max)
- how = max;
- else if (how > 16384UL)
- how = 16384UL;
- else if (!bufe && how < min)
- break;
- else if (how == 0UL)
- break;
-
- if (!load) {
- load = 1;
- prev[0] = wr[0];
- wr[0] = '[' | 0x0400;
- prev[1] = wr[1];
- wr[1] = 'S' | 0x0400;
- prev[2] = wr[2];
- wr[2] = 'A' | 0x0400;
- prev[3] = wr[3];
- wr[3] = 'V' | 0x0400;
- prev[4] = wr[4];
- wr[4] = 'E' | 0x0400;
- prev[5] = wr[5];
- wr[5] = ']' | 0x0400;
- }
-
- if (cx->buffer_last_io == 0)
- wav_buffer_filepos = wav_position;
-
- if (sb_card->audio_data_flipped_sign) {
- if (wav_16bit)
- for (i=0;i < ((int)how-1);i += 2) buffer[cx->buffer_last_io+i+1] ^= 0x80;
- else
- for (i=0;i < (int)how;i++) buffer[cx->buffer_last_io+i] ^= 0x80;
- }
-
- rd = _dos_xwrite(wav_fd,buffer + cx->buffer_last_io,how);
- if (rd <= 0 || (uint32_t)rd < how) {
- fprintf(stderr,"write() failed, %d < %d\n",
- rd,(int)how);
- stop_play();
- break;
- }
-
- assert((cx->buffer_last_io+((uint32_t)rd)) <= cx->buffer_size);
- wav_position += (uint32_t)rd / wav_bytes_per_sample;
- cx->buffer_last_io += (uint32_t)rd;
-
- assert(cx->buffer_last_io <= cx->buffer_size);
- if (cx->buffer_last_io == cx->buffer_size) cx->buffer_last_io = 0;
- max -= (uint32_t)rd;
- }
-
- if (cx->buffer_last_io == 0)
- wav_buffer_filepos = wav_position;
-
- if (load) {
- for (i=0;i < 6;i++)
- wr[i] = prev[i];
- }
-}
-
-static unsigned char adpcm_do_reset_interval=1;
-static unsigned long adpcm_reset_interval=0;
-static unsigned long adpcm_counter=0;
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
-static unsigned char adpcm_tmp[4096];
-#endif
-static void load_audio(struct sndsb_ctx *cx,uint32_t up_to,uint32_t min,uint32_t max,uint8_t initial) { /* load audio up to point or max */
- unsigned char FAR *buffer = sb_dma->lin;
- VGA_ALPHA_PTR wr = vga_alpha_ram + 80 - 6;
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
- unsigned char c;
-#endif
- unsigned char load=0;
- uint16_t prev[6];
- int rd,i,bufe=0;
- uint32_t how;
-
- /* caller should be rounding! */
- assert((up_to & 3UL) == 0UL);
- if (up_to >= cx->buffer_size) return;
- if (cx->buffer_size < 32) return;
- if (cx->buffer_last_io == up_to) return;
-
- if (sb_card->dsp_adpcm > 0 && (wav_16bit || wav_stereo)) return;
- if (max == 0) max = cx->buffer_size/4;
- if (max < 16) return;
- lseek(wav_fd,wav_data_offset + (wav_position * (unsigned long)wav_bytes_per_sample),SEEK_SET);
-
- if (cx->buffer_last_io == 0)
- wav_buffer_filepos = wav_position;
-
- while (max > 0UL) {
- /* the most common "hang" apparently is when IRQ 0 triggers too much
- and then somehow execution gets stuck here */
- if (irq_0_watchdog < 16UL)
- break;
-
- if (cx->backwards) {
- if (up_to > cx->buffer_last_io) {
- how = cx->buffer_last_io;
- if (how == 0) how = cx->buffer_size - up_to;
- bufe = 1;
- }
- else {
- how = (cx->buffer_last_io - up_to);
- bufe = 0;
- }
- }
- else {
- if (up_to < cx->buffer_last_io) {
- how = (cx->buffer_size - cx->buffer_last_io); /* from last IO to end of buffer */
- bufe = 1;
- }
- else {
- how = (up_to - cx->buffer_last_io); /* from last IO to up_to */
- bufe = 0;
- }
- }
-
- if (how == 0UL)
- break;
- else if (how > max)
- how = max;
- else if (how > 16384UL)
- how = 16384UL;
- else if (!bufe && how < min)
- break;
-
- if (!load) {
- load = 1;
- prev[0] = wr[0];
- wr[0] = '[' | 0x0400;
- prev[1] = wr[1];
- wr[1] = 'L' | 0x0400;
- prev[2] = wr[2];
- wr[2] = 'O' | 0x0400;
- prev[3] = wr[3];
- wr[3] = 'A' | 0x0400;
- prev[4] = wr[4];
- wr[4] = 'D' | 0x0400;
- prev[5] = wr[5];
- wr[5] = ']' | 0x0400;
- }
-
- if (cx->buffer_last_io == 0)
- wav_buffer_filepos = wav_position;
-
- if (sb_card->dsp_adpcm > 0) {
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- break; /* cut */
-#else
- unsigned int src;
-
- /* FIXME: Would be neat to demonstrate ADPCM playback with backwards DMA */
- if (cx->backwards) break;
-
- /* 16-bit mode: avoid integer overflow below */
- if (how > 2048)
- how = 2048;
-
- /* ADPCM encoding does mono 8-bit only */
- if (initial) {
- /* reference byte */
- rd = _dos_xread(wav_fd,buffer + cx->buffer_last_io,1);
- sndsb_encode_adpcm_set_reference(buffer[cx->buffer_last_io],sb_card->dsp_adpcm);
- cx->buffer_last_io++;
- adpcm_counter++;
- wav_position++;
- initial = 0;
- max--;
- how--;
- }
-
- /* number of samples */
- if (sb_card->dsp_adpcm == ADPCM_4BIT)
- src = how * 2;
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT)
- src = how * 3;
- else if (sb_card->dsp_adpcm == ADPCM_2BIT)
- src = how * 4;
-
- if (src > sizeof(adpcm_tmp)) {
- src = sizeof(adpcm_tmp);
- if (sb_card->dsp_adpcm == ADPCM_2_6BIT)
- src -= src % 3;
- }
-
- rd = read(wav_fd,adpcm_tmp,src);
- if (rd == 0 || rd == -1) {
- wav_position = 0;
- lseek(wav_fd,wav_data_offset + (wav_position * (unsigned long)wav_bytes_per_sample),SEEK_SET);
- rd = read(wav_fd,adpcm_tmp,src);
- if (rd == 0 || rd == -1) {
-#if TARGET_MSDOS == 32
- memset(adpcm_tmp,128,src);
-#else
- _fmemset(adpcm_tmp,128,src);
-#endif
- rd = src;
- }
- }
-
-#ifdef INCLUDE_FX
- if (!sb_card->backwards) fx_proc(adpcm_tmp,rd / wav_bytes_per_sample);
-#endif
- wav_position += (uint32_t)rd;
- if (sb_card->dsp_adpcm == ADPCM_4BIT) {
- rd /= 2;
- for (i=0;i < rd;i++) {
- c = sndsb_encode_adpcm_4bit(adpcm_tmp[(i*2) ]) << 4;
- c |= sndsb_encode_adpcm_4bit(adpcm_tmp[(i*2)+1]);
- buffer[cx->buffer_last_io+i] = c;
-
- if (adpcm_reset_interval != 0) {
- if (++adpcm_counter >= adpcm_reset_interval) {
- adpcm_counter -= adpcm_reset_interval;
- sndsb_encode_adpcm_reset_wo_ref(sb_card->dsp_adpcm);
- }
- }
- }
- }
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT) {
- rd /= 3;
- for (i=0;i < rd;i++) {
- c = sndsb_encode_adpcm_2_6bit(adpcm_tmp[(i*3) ],0) << 5;
- c |= sndsb_encode_adpcm_2_6bit(adpcm_tmp[(i*3)+1],0) << 2;
- c |= sndsb_encode_adpcm_2_6bit(adpcm_tmp[(i*3)+2],1) >> 1;
- buffer[cx->buffer_last_io+i] = c;
-
- if (adpcm_reset_interval != 0) {
- if (++adpcm_counter >= adpcm_reset_interval) {
- adpcm_counter -= adpcm_reset_interval;
- sndsb_encode_adpcm_reset_wo_ref(sb_card->dsp_adpcm);
- }
- }
- }
- }
- else if (sb_card->dsp_adpcm == ADPCM_2BIT) {
- rd /= 4;
- for (i=0;i < rd;i++) {
- c = sndsb_encode_adpcm_2bit(adpcm_tmp[(i*4) ]) << 6;
- c |= sndsb_encode_adpcm_2bit(adpcm_tmp[(i*4)+1]) << 4;
- c |= sndsb_encode_adpcm_2bit(adpcm_tmp[(i*4)+2]) << 2;
- c |= sndsb_encode_adpcm_2bit(adpcm_tmp[(i*4)+3]);
- buffer[cx->buffer_last_io+i] = c;
-
- if (adpcm_reset_interval != 0) {
- if (++adpcm_counter >= adpcm_reset_interval) {
- adpcm_counter -= adpcm_reset_interval;
- sndsb_encode_adpcm_reset_wo_ref(sb_card->dsp_adpcm);
- }
- }
- }
- }
- else {
- abort();
- }
-
- cx->buffer_last_io += (uint32_t)rd;
-#endif
- }
- else {
- uint32_t oa,adj;
-
- oa = cx->buffer_last_io;
- if (cx->backwards) {
- if (cx->buffer_last_io == 0) {
- cx->buffer_last_io = cx->buffer_size - how;
- }
- else if (cx->buffer_last_io >= how) {
- cx->buffer_last_io -= how;
- }
- else {
- abort();
- }
-
- adj = (uint32_t)how / wav_bytes_per_sample;
- if (wav_position >= adj) wav_position -= adj;
- else if (wav_position != 0UL) wav_position = 0;
- else {
- wav_position = lseek(wav_fd,0,SEEK_END);
- if (wav_position >= adj) wav_position -= adj;
- else if (wav_position != 0UL) wav_position = 0;
- wav_position /= wav_bytes_per_sample;
- }
-
- lseek(wav_fd,wav_data_offset + (wav_position * (unsigned long)wav_bytes_per_sample),SEEK_SET);
- }
-
- assert(cx->buffer_last_io <= cx->buffer_size);
- rd = _dos_xread(wav_fd,buffer + cx->buffer_last_io,how);
- if (rd == 0 || rd == -1) {
- if (!cx->backwards) {
- wav_position = 0;
- lseek(wav_fd,wav_data_offset + (wav_position * (unsigned long)wav_bytes_per_sample),SEEK_SET);
- rd = _dos_xread(wav_fd,buffer + cx->buffer_last_io,how);
- if (rd == 0 || rd == -1) {
- /* hmph, fine */
-#if TARGET_MSDOS == 32
- memset(buffer+cx->buffer_last_io,128,how);
-#else
- _fmemset(buffer+cx->buffer_last_io,128,how);
-#endif
- rd = (int)how;
- }
- }
- else {
- rd = (int)how;
- }
- }
-
- assert((cx->buffer_last_io+((uint32_t)rd)) <= cx->buffer_size);
-#ifdef INCLUDE_FX
- if (!sb_card->backwards) fx_proc(buffer + cx->buffer_last_io,rd / wav_bytes_per_sample);
-#endif
- if (sb_card->audio_data_flipped_sign) {
- if (wav_16bit)
- for (i=0;i < (rd-1);i += 2) buffer[cx->buffer_last_io+i+1] ^= 0x80;
- else
- for (i=0;i < rd;i++) buffer[cx->buffer_last_io+i] ^= 0x80;
- }
-
- if (!cx->backwards) {
- cx->buffer_last_io += (uint32_t)rd;
- wav_position += (uint32_t)rd / wav_bytes_per_sample;
- }
- }
-
- assert(cx->buffer_last_io <= cx->buffer_size);
- if (!cx->backwards) {
- if (cx->buffer_last_io == cx->buffer_size) cx->buffer_last_io = 0;
- }
- max -= (uint32_t)rd;
- }
-
- if (cx->buffer_last_io == 0)
- wav_buffer_filepos = wav_position;
-
- if (load) {
- for (i=0;i < 6;i++)
- wr[i] = prev[i];
- }
-}
-
-static void rec_vu(uint32_t pos) {
- VGA_ALPHA_PTR wr = vga_alpha_ram + (vga_width * (vga_height - 1));
- const unsigned int leeway = 256;
- unsigned int x,L=0,R=0,max;
- uint16_t sample;
-
- if (pos == (~0UL)) {
- for (x=0;x < (unsigned int)vga_width;x++)
- wr[x] = 0x1E00 | 177;
-
- return;
- }
-
- /* caller should be sample-aligning the position! */
- assert((pos & 3UL) == 0UL);
-
- if ((pos+(leeway*wav_bytes_per_sample)) < sb_card->buffer_size) {
- if (wav_16bit) {
- int16_t FAR *ptr = (int16_t FAR*)(sb_dma->lin + pos);
- max = 32767;
- if (wav_stereo) {
- /* 16-bit PCM stereo */
- for (x=0;x < leeway;x++) {
- sample = ptr[x*2];
- if (sb_card->audio_data_flipped_sign) sample = abs((uint16_t)sample - 32768);
- else sample = abs((int16_t)sample);
- if (L < sample) L = sample;
-
- sample = ptr[x*2 + 1];
- if (sb_card->audio_data_flipped_sign) sample = abs((uint16_t)sample - 32768);
- else sample = abs((int16_t)sample);
- if (R < sample) R = sample;
- }
- }
- else {
- /* 16-bit PCM mono */
- for (x=0;x < leeway;x++) {
- sample = ptr[x];
- if (sb_card->audio_data_flipped_sign) sample = abs((uint16_t)sample - 32768);
- else sample = abs((int16_t)sample);
- if (L < sample) L = sample;
- }
- }
- }
- else {
- max = 127;
- if (wav_stereo) {
- /* 8-bit PCM stereo */
- for (x=0;x < leeway;x++) {
- sample = sb_dma->lin[x*2 + pos];
- if (sb_card->audio_data_flipped_sign) sample = abs((signed char)sample);
- else sample = abs((int)sample - 128);
- if (L < sample) L = sample;
-
- sample = sb_dma->lin[x*2 + 1 + pos];
- if (sb_card->audio_data_flipped_sign) sample = abs((signed char)sample);
- else sample = abs((int)sample - 128);
- if (R < sample) R = sample;
- }
- }
- else {
- /* 8-bit PCM mono */
- for (x=0;x < leeway;x++) {
- sample = sb_dma->lin[x + pos];
- if (sb_card->audio_data_flipped_sign) sample = abs((signed char)sample);
- else sample = abs((int)sample - 128);
- if (L < sample) L = sample;
- }
- }
- }
-
- L = (unsigned int)(((unsigned long)L * 80UL) / (unsigned long)max);
- if (wav_stereo)
- R = (unsigned int)(((unsigned long)R * 80UL) / (unsigned long)max);
- else
- R = L;
-
- if (L > 80) L = 80;
- if (R > 80) R = 80;
- for (x=0;x < 80;x++) {
- if (x < L && x < R)
- wr[x] = 0x0F00 | 219;
- else if (x < L)
- wr[x] = 0x0F00 | 223;
- else if (x < R)
- wr[x] = 0x0F00 | 220;
- else
- wr[x] = 0x0F00 | 32;
- }
- }
-}
-
-#define DMA_WRAP_DEBUG
-
-static void wav_idle() {
- const unsigned int leeway = sb_card->buffer_size / 100;
- uint32_t pos;
-#ifdef DMA_WRAP_DEBUG
- uint32_t pos2;
-#endif
-
- if (!wav_playing || wav_fd < 0)
- return;
-
- /* if we're playing without an IRQ handler, then we'll want this function
- * to poll the sound card's IRQ status and handle it directly so playback
- * continues to work. if we don't, playback will halt on actual Creative
- * Sound Blaster 16 hardware until it gets the I/O read to ack the IRQ */
- if (!dont_sb_idle) sndsb_main_idle(sb_card);
-
- _cli();
-#ifdef DMA_WRAP_DEBUG
- pos2 = sndsb_read_dma_buffer_position(sb_card);
-#endif
- pos = sndsb_read_dma_buffer_position(sb_card);
-#ifdef DMA_WRAP_DEBUG
- if (sb_card->backwards) {
- if (pos2 < 0x1000 && pos >= (sb_card->buffer_size-0x1000)) {
- /* normal DMA wrap-around, no problem */
- }
- else {
- if (pos > pos2) fprintf(stderr,"DMA glitch! 0x%04lx 0x%04lx\n",pos,pos2);
- else pos = max(pos,pos2);
- }
-
- pos += leeway;
- if (pos >= sb_card->buffer_size) pos -= sb_card->buffer_size;
- }
- else {
- if (pos < 0x1000 && pos2 >= (sb_card->buffer_size-0x1000)) {
- /* normal DMA wrap-around, no problem */
- }
- else {
- if (pos < pos2) fprintf(stderr,"DMA glitch! 0x%04lx 0x%04lx\n",pos,pos2);
- else pos = min(pos,pos2);
- }
-
- if (pos < leeway) pos += sb_card->buffer_size - leeway;
- else pos -= leeway;
- }
-#endif
- pos &= (~3UL); /* round down */
- _sti();
-
- if (wav_record) {
- /* read audio samples just behind DMA and render as VU meter */
- rec_vu(pos);
-
- /* write to disk */
- save_audio(sb_card,pos,min(wav_sample_rate/4,4096)/*min*/,
- sb_card->buffer_size/2/*max*/,0/*first block*/);
- }
- else {
- /* load from disk */
- load_audio(sb_card,pos,min(wav_sample_rate/8,4096)/*min*/,
- sb_card->buffer_size/4/*max*/,0/*first block*/);
- }
-}
-
-static void update_cfg();
-
-static unsigned long playback_live_position() {
- signed long xx = (signed long)sndsb_read_dma_buffer_position(sb_card);
-
- if (sb_card->backwards) {
- if (sb_card->buffer_last_io >= (unsigned long)xx)
- xx += sb_card->buffer_size;
-
- xx -= sb_card->buffer_size; /* because we started from the end */
- }
- else {
- if (sb_card->buffer_last_io <= (unsigned long)xx)
- xx -= sb_card->buffer_size;
- }
-
- if (sb_card->dsp_adpcm == ADPCM_4BIT) xx *= 2;
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT) xx *= 3;
- else if (sb_card->dsp_adpcm == ADPCM_2BIT) xx *= 4;
- xx += wav_buffer_filepos * wav_bytes_per_sample;
- if (xx < 0) xx += wav_data_length;
- return ((unsigned long)xx) / wav_bytes_per_sample;
-}
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-static unsigned char dos_vm_yield_counter = 0;
-#endif
-
-static uint32_t last_dma_position = 1;
-static void ui_anim(int force) {
- VGA_ALPHA_PTR wr = vga_alpha_ram + 10;
- const unsigned int width = 70 - 4;
- unsigned long temp;
- unsigned int i,rem,rem2,cc;
- unsigned int pH,pM,pS,pSS;
- const char *msg = "DMA:";
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- /* Under Windows, yield every so often. Under Windows NT/2000/XP this prevents
- * NTVDM.EXE from pegging the CPU at 100%, allowing the rest of the OS to run
- * smoother. */
- if (windows_mode == WINDOWS_NT || windows_mode == WINDOWS_ENHANCED) {
- unsigned char do_yield = 1;
-
- if (sb_card != NULL && wav_playing)
- do_yield = sndsb_recommend_vm_wait(sb_card);
-
- if (do_yield) {
- if (dos_vm_yield_counter == 0)
- dos_vm_yield();
-
- if (++dos_vm_yield_counter >= 10)
- dos_vm_yield_counter = 0;
- }
- }
-#endif
-
- wav_idle();
-
- rem = 0;
- if (sb_card != NULL) rem = sndsb_read_dma_buffer_position(sb_card);
- if (force || last_dma_position != rem) {
- last_dma_position = rem;
- if (rem != 0) rem--;
- rem = (unsigned int)(((unsigned long)rem * (unsigned long)width) / (unsigned long)sb_card->buffer_size);
-
- rem2 = 0;
- if (sb_card != NULL) rem2 = sb_card->buffer_last_io;
- if (rem2 != 0) rem2--;
- rem2 = (unsigned int)(((unsigned long)rem2 * (unsigned long)width) / (unsigned long)sb_card->buffer_size);
-
- while (*msg) *wr++ = (uint16_t)(*msg++) | 0x1E00;
- for (i=0;i < width;i++) {
- if (i == rem2)
- wr[i] = (uint16_t)(i == rem ? 'x' : (i < rem ? '-' : ' ')) | 0x7000;
- else
- wr[i] = (uint16_t)(i == rem ? 'x' : (i < rem ? '-' : ' ')) | 0x1E00;
- }
-
- if (wav_playing) temp = playback_live_position();
- else temp = wav_position;
- pSS = (unsigned int)(((temp % wav_sample_rate) * 100) / wav_sample_rate);
- temp /= wav_sample_rate;
- pS = (unsigned int)(temp % 60UL);
- pM = (unsigned int)((temp / 60UL) % 60UL);
- pH = (unsigned int)((temp / 3600UL) % 24UL);
-
- msg = temp_str;
- sprintf(temp_str,"%ub %s %5luHz @%c%u:%02u:%02u.%02u",wav_16bit ? 16 : 8,wav_stereo ? "ST" : "MO",
- wav_sample_rate,wav_playing ? (wav_record ? 'r' : 'p') : 's',pH,pM,pS,pSS);
- for (wr=vga_alpha_ram+(80*1),cc=0;cc < 29 && *msg != 0;cc++) *wr++ = 0x1F00 | ((unsigned char)(*msg++));
- for (;cc < 29;cc++) *wr++ = 0x1F20;
- msg = sndsb_dspoutmethod_str[sb_card->dsp_play_method];
- rem = sndsb_dsp_out_method_supported(sb_card,wav_sample_rate,wav_stereo,wav_16bit) ? 0x1A : 0x1C;
- for (;cc < 36 && *msg != 0;cc++) *wr++ = (rem << 8) | ((unsigned char)(*msg++));
- if (cc < 36) {
- if (rem == 0x1C) *wr++ = 0x1E00 + '?';
- else if (sb_card->reason_not_supported) *wr++ = 0x1A00 + '?';
- }
- for (;cc < 36;cc++) *wr++ = 0x1F20;
-
- if (sb_card->dsp_adpcm != 0) {
- msg = sndsb_adpcm_mode_str[sb_card->dsp_adpcm];
- for (;cc < 52 && *msg != 0;cc++) *wr++ = 0x1F00 | ((unsigned char)(*msg++));
- }
- else if (sb_card->audio_data_flipped_sign) {
- msg = "[flipsign]";
- for (;cc < 52 && *msg != 0;cc++) *wr++ = 0x1F00 | ((unsigned char)(*msg++));
- }
-
- /* fill */
- for (;cc < 67;cc++) *wr++ = 0x1F20;
-
- msg = temp_str;
- temp = sndsb_read_dma_buffer_position(sb_card);
- sprintf(temp_str,"%05lx/%05lx",
- (unsigned long)temp,
- (unsigned long)sb_card->buffer_size);
- for (;cc < 80 && *msg != 0;cc++) *wr++ = 0x1F00 | ((unsigned char)(*msg++));
-
- /* finish */
- for (;cc < 80;cc++) *wr++ = 0x1F20;
- }
-
- irq_0_watchdog_ack();
-
- {
- static const unsigned char anims[] = {'-','/','|','\\'};
- if (++animator >= 4) animator = 0;
- wr = vga_alpha_ram + 80 + 79;
- *wr = anims[animator] | 0x1E00;
- }
-}
-
-static void close_wav() {
- if (wav_fd >= 0) {
- close(wav_fd);
- wav_fd = -1;
- }
-}
-
-static void open_wav() {
- char tmp[64];
-
- wav_position = 0;
- if (wav_fd < 0) {
- if (strlen(wav_file) < 1) return;
- wav_fd = open(wav_file,O_RDONLY|O_BINARY);
- if (wav_fd < 0) return;
- wav_data_offset = 0;
- wav_data_length = (unsigned long)lseek(wav_fd,0,SEEK_END);
- lseek(wav_fd,0,SEEK_SET);
- read(wav_fd,tmp,sizeof(tmp));
-
- /* FIXME: This is a dumb quick and dirty WAVE header reader */
- if (!memcmp(tmp,"RIFF",4) && !memcmp(tmp+8,"WAVEfmt ",8) && wav_data_length > 44) {
- unsigned char *fmtc = tmp + 20;
- /* fmt chunk at 12, where 'fmt '@12 and length of fmt @ 16, fmt data @ 20, 16 bytes long */
- /* WORD wFormatTag
- * WORD nChannels
- * DWORD nSamplesPerSec
- * DWORD nAvgBytesPerSec
- * WORD nBlockAlign
- * WORD wBitsPerSample */
- wav_sample_rate = *((uint32_t*)(fmtc + 4));
- wav_stereo = *((uint16_t*)(fmtc + 2)) > 1;
- wav_16bit = *((uint16_t*)(fmtc + 14)) > 8;
- wav_bytes_per_sample = (wav_stereo ? 2 : 1) * (wav_16bit ? 2 : 1);
- wav_data_offset = 44;
- wav_data_length -= 44;
- wav_data_length -= wav_data_length % wav_bytes_per_sample;
- }
- }
-}
-
-void open_wav_unique_name() {
- int patience = 1000;
- char *p,*q;
-
- if (wav_fd >= 0) close(wav_fd);
- wav_fd = -1;
-
- do {
- p = strrchr(wav_file,'.');
- if (p == NULL) p = wav_file + strlen(wav_file) - 1;
- else if (p > wav_file) p--;
-
- if (p == wav_file) {
- strcpy(wav_file,"untitled.wav");
- }
- else if (p >= wav_file) {
- if (!isdigit(*p)) {
- *p = '0';
- break;
- }
- else if (*p == '9') {
- *p = '0';
- /* carry the 1 */
- for (q=p-1;q >= wav_file;q--) {
- if (isdigit(*q)) {
- if (*q == '9') {
- *q = '0';
- continue;
- }
- else {
- (*q)++;
- }
- }
- else {
- *q = '0';
- break;
- }
- }
- }
- else {
- (*p)++;
- }
- }
-
- /* if the file already exists, then reject the name */
- if ((wav_fd = open(wav_file,O_RDONLY|O_BINARY)) >= 0) {
- close(wav_fd);
- wav_fd = -1;
- }
- /* unless we are able to create the file, we don't want it */
- else if ((wav_fd = open(wav_file,O_RDWR|O_BINARY|O_CREAT|O_EXCL|O_TRUNC,0644)) >= 0) {
- break; /* works for me */
- }
-
- if (--patience == 0)
- break;
- } while (1);
-}
-
-void begin_play() {
- unsigned long choice_rate;
-
- if (wav_playing)
- return;
-
- /* sorry, lock out unimplemented modes */
- {
- const char *why = NULL;
- int i;
-
- if (sb_card->backwards && sb_card->dsp_adpcm != 0)
- why = "Backwards playback and ADPCM not implemented";
- else if (sb_card->backwards && wav_record) /* NTS: When we do support this, code will need to reverse audio before writing to WAV */
- why = "Backwards recording not implemented";
-
- if (why) {
- struct vga_msg_box box;
- vga_msg_box_create(&box,why,0,0);
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) break;
- }
- }
- vga_msg_box_destroy(&box);
-
- return;
- }
- }
-
- if (wav_record)
- open_wav_unique_name();
-
- if (wav_fd < 0)
- return;
-
- choice_rate = sample_rate_timer_clamp ? wav_sample_rate_by_timer : wav_sample_rate;
- if (sb_card->goldplay_mode) {
- if (goldplay_samplerate_choice == GOLDRATE_DOUBLE)
- choice_rate *= 2;
- else if (goldplay_samplerate_choice == GOLDRATE_MAX) {
- /* basically the maximum the DSP will run at */
- if (sb_card->dsp_play_method <= SNDSB_DSPOUTMETHOD_200)
- choice_rate = 22050;
- else if (sb_card->dsp_play_method == SNDSB_DSPOUTMETHOD_201)
- choice_rate = 44100;
- else if (sb_card->dsp_play_method == SNDSB_DSPOUTMETHOD_3xx)
- choice_rate = wav_stereo ? 22050 : 44100;
- else if (sb_card->pnp_name == NULL)
- choice_rate = 44100; /* Most clones and non-PnP SB16 cards max out at 44.1KHz */
- else
- choice_rate = 48000; /* SB16 ViBRA (PnP-era) cards max out at 48Khz */
- }
- }
-
- update_cfg();
- irq_0_watchdog_reset();
- if (!sndsb_prepare_dsp_playback(sb_card,choice_rate,wav_stereo,wav_16bit))
- return;
-
- sndsb_setup_dma(sb_card);
-
- if (!wav_record)
- load_audio(sb_card,sb_card->buffer_size/2,0/*min*/,0/*max*/,1/*first block*/);
- else { /* create RIFF structure for recording */
- uint32_t dw;
- uint16_t w;
-
- write(wav_fd,"RIFF",4);
- dw = 44 - 8; write(wav_fd,&dw,4);
- write(wav_fd,"WAVEfmt ",8);
- dw = 0x10; write(wav_fd,&dw,4);
-
- w = 1; /* PCM */ write(wav_fd,&w,2);
- w = wav_stereo ? 2 : 1; write(wav_fd,&w,2);
- dw = wav_sample_rate; write(wav_fd,&dw,4);
- dw = wav_sample_rate * wav_bytes_per_sample;
- write(wav_fd,&dw,4);
- w = wav_bytes_per_sample; write(wav_fd,&w,2);
- w = wav_16bit ? 16 : 8; write(wav_fd,&w,2);
-
- write(wav_fd,"data",4);
- dw = 0; write(wav_fd,&dw,4);
-
- wav_data_offset = 44;
- wav_position = 0;
- }
-
- /* make sure the IRQ is acked */
- if (sb_card->irq >= 8) {
- p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7));
- p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2);
- }
- else if (sb_card->irq >= 0) {
- p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq);
- }
- if (sb_card->irq >= 0)
- p8259_unmask(sb_card->irq);
-
- if (!sndsb_begin_dsp_playback(sb_card))
- return;
-
- _cli();
- if (sb_card->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) {
- unsigned long nr = (unsigned long)sb_card->buffer_rate * 2UL;
- write_8254_system_timer(T8254_REF_CLOCK_HZ / nr);
- irq_0_count = 0;
- irq_0_adv = 182UL; /* 18.2Hz */
- irq_0_max = nr * 10UL; /* sample rate */
- }
- else if (sb_card->goldplay_mode) {
- write_8254_system_timer(wav_sample_rate_by_timer_ticks);
- irq_0_count = 0;
- irq_0_adv = 182UL; /* 18.2Hz */
- irq_0_max = wav_sample_rate_by_timer * 10UL;
- }
- wav_playing = 1;
- _sti();
-}
-
-void stop_play() {
- if (!wav_playing) return;
- draw_irq_indicator();
- if (!wav_record) {
- wav_position = playback_live_position();
- wav_position -= wav_position % (unsigned long)wav_bytes_per_sample;
- }
-
- _cli();
- if (sb_card->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT || sb_card->goldplay_mode) {
- irq_0_count = 0;
- irq_0_adv = 1;
- irq_0_max = 1;
- write_8254_system_timer(0); /* restore 18.2 tick/sec */
- }
- sndsb_stop_dsp_playback(sb_card);
- wav_playing = 0;
- _sti();
-
- ui_anim(1);
- if (wav_fd >= 0 && wav_record) {
- uint32_t dw;
-
- unsigned long len = lseek(wav_fd,0,SEEK_END);
-
- lseek(wav_fd,4,SEEK_SET);
- dw = len - 8; write(wav_fd,&dw,4);
-
- lseek(wav_fd,40,SEEK_SET);
- dw = len - 44; write(wav_fd,&dw,4);
-
- close(wav_fd);
- wav_fd = -1;
-
- wav_fd = open(wav_file,O_RDONLY|O_BINARY);
- wav_data_offset = 44;
- wav_data_length = len - 44;
- wav_position = 0;
- rec_vu(~0UL);
- }
-}
-
-static void vga_write_until(unsigned int x) {
- while (vga_pos_x < x)
- vga_writec(' ');
-}
-
-static int change_param_idx = 0;
-
-/* NTS: the 13000, 15000, 23000 values come from Creative documentation */
-static const unsigned short param_preset_rates[] = {
- 4000, 5512, 5675, 6000,
- 8000, 11025, 11111, 12000,
- 13000, 15000, 16000, 22050,
- 22222, 23000, 24000, 32000,
- 44100, 48000, 54000, 58000};
-
-#if TARGET_MSDOS == 32
-static const char *dos32_irq_0_warning =
- "WARNING: The timer is made to run at the sample rate. Depending on your\n"
- " DOS extender there may be enough overhead to overwhelm the CPU\n"
- " and possibly cause a crash.\n"
- " Enable?";
-#endif
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-static int change_alias_idx = 0;
-static unsigned char dsp_alias_had_warned = 0;
-static const char *dsp_alias_warning =
- "WARNING: DSP alias port will not work unless you are using an original\n"
- " Sound Blaster (DSP 1.xx or 2.xx) and NOT a clone. See the\n"
- " README file for more information.\n"
- " Enable anyway?";
-#endif
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-void change_alias_menu() {
- unsigned char loop=1;
- unsigned char redraw=1;
- unsigned char uiredraw=1;
- unsigned char selector=change_alias_idx;
- VGA_ALPHA_PTR vga;
- unsigned int cc;
- char tmp[128];
-
- while (loop) {
- if (redraw || uiredraw) {
- _cli();
- if (redraw) {
- for (vga=vga_alpha_ram+(80*2),cc=0;cc < (80*23);cc++) *vga++ = 0x1E00 | 177;
- ui_anim(1);
- }
- vga_moveto(0,4);
-
- vga_write_color(selector == 0 ? 0x70 : 0x1F);
- sprintf(tmp,"DSP alias: %u",sb_card->dsp_alias_port);
- vga_write(tmp);
- vga_write_until(30);
- vga_write("\n");
-
- vga_write_sync();
- _sti();
- redraw = 0;
- uiredraw = 0;
- }
-
- if (kbhit()) {
- int c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27 || c == 13)
- loop = 0;
- else if (c == 0x4800) { /* up arrow */
-// if (selector > 0) selector--;
-// else selector=0;
- uiredraw=1;
- }
- else if (c == 0x5000) { /* down arrow */
-// if (selector < -1) selector++;
-// else selector=0;
- uiredraw=1;
- }
- else if (c == 0x4B00) { /* left arrow */
- switch (selector) {
- case 0: /* sample rate */
- sb_card->dsp_alias_port ^= 1;
- break;
- };
- update_cfg();
- uiredraw=1;
- }
- else if (c == 0x4D00) { /* right arrow */
- switch (selector) {
- case 0: /* sample rate */
- sb_card->dsp_alias_port ^= 1;
- break;
- };
- update_cfg();
- uiredraw=1;
- }
- }
-
- ui_anim(0);
- }
-
- if (!dsp_alias_had_warned && sb_card->dsp_alias_port) {
- /* NOTE TO SELF: It can overwhelm the UI in DOSBox too, but DOSBox seems able to
- recover if you manage to hit CTRL+F12 to speed up the CPU cycles in the virtual machine.
- On real hardware, even with the recovery method the machine remains hung :( */
- if (confirm_yes_no_dialog(dsp_alias_warning))
- dsp_alias_had_warned = 1;
- else
- sb_card->dsp_alias_port = 0;
- }
-
- change_param_idx = selector;
-}
-#endif
-
-void change_param_menu() {
- unsigned char loop=1;
- unsigned char redraw=1;
- unsigned char uiredraw=1;
- unsigned char selector=change_param_idx;
-#if TARGET_MSDOS == 32
- unsigned char oldmethod=sb_card->dsp_play_method;
-#endif
- unsigned int cc,ra;
- VGA_ALPHA_PTR vga;
- char tmp[128];
-
- while (loop) {
- if (redraw || uiredraw) {
- _cli();
- if (redraw) {
- for (vga=vga_alpha_ram+(80*2),cc=0;cc < (80*23);cc++) *vga++ = 0x1E00 | 177;
- ui_anim(1);
- }
- vga_moveto(0,4);
-
- vga_write_color(selector == 0 ? 0x70 : 0x1F);
- sprintf(tmp,"Sample rate: %uHz",wav_sample_rate);
- vga_write(tmp);
- vga_write_until(30);
- vga_write("\n");
-
- vga_write_color(selector == 1 ? 0x70 : 0x1F);
- sprintf(tmp,"Channels: %s",wav_stereo ? "stereo" : "mono");
- vga_write(tmp);
- vga_write_until(30);
- vga_write("\n");
-
- vga_write_color(selector == 2 ? 0x70 : 0x1F);
- sprintf(tmp,"Bits: %u-bit",wav_16bit ? 16 : 8);
- vga_write(tmp);
- vga_write_until(30);
- vga_write("\n");
-
- vga_write_color(selector == 3 ? 0x70 : 0x1F);
- vga_write( "Translation: ");
- if (sb_card->dsp_adpcm > 0) vga_write(sndsb_adpcm_mode_str[sb_card->dsp_adpcm]);
- else if (sb_card->audio_data_flipped_sign) vga_write("Flip sign");
- else vga_write("None");
- vga_write_until(30);
- vga_write("\n");
-
- vga_write_color(selector == 4 ? 0x70 : 0x1F);
- vga_write( "DSP mode: ");
- if (sndsb_dsp_out_method_supported(sb_card,wav_sample_rate,wav_stereo,wav_16bit))
- vga_write_color(selector == 4 ? 0x70 : 0x1F);
- else
- vga_write_color(selector == 4 ? 0x74 : 0x1C);
- vga_write(sndsb_dspoutmethod_str[sb_card->dsp_play_method]);
- vga_write_until(30);
- vga_write("\n");
-
- sprintf(tmp,"%u",sb_card->dsp_direct_dac_read_after_command);
- vga_write_color(selector == 5 ? 0x70 : 0x1F);
- vga_write( "DDAC read aft: ");
- if (sndsb_dsp_out_method_supported(sb_card,wav_sample_rate,wav_stereo,wav_16bit))
- vga_write_color(selector == 5 ? 0x70 : 0x1F);
- else
- vga_write_color(selector == 5 ? 0x74 : 0x1C);
- vga_write(tmp);
- vga_write_until(30);
- vga_write("\n");
-
- sprintf(tmp,"%u",sb_card->dsp_direct_dac_poll_retry_timeout);
- vga_write_color(selector == 6 ? 0x70 : 0x1F);
- vga_write( "DDAC poll retry");
- if (sndsb_dsp_out_method_supported(sb_card,wav_sample_rate,wav_stereo,wav_16bit))
- vga_write_color(selector == 6 ? 0x70 : 0x1F);
- else
- vga_write_color(selector == 6 ? 0x74 : 0x1C);
- vga_write(tmp);
- vga_write_until(30);
- vga_write("\n");
-
- sprintf(tmp,"%s",sb_card->backwards?"Backwards":"Forwards");
- vga_write_color(selector == 7 ? 0x70 : 0x1F);
- vga_write( "Direction: ");
- if (sndsb_dsp_out_method_supported(sb_card,wav_sample_rate,wav_stereo,wav_16bit))
- vga_write_color(selector == 7 ? 0x70 : 0x1F);
- else
- vga_write_color(selector == 7 ? 0x74 : 0x1C);
- vga_write(tmp);
- vga_write_until(30);
- vga_write("\n");
-
- vga_moveto(0,13);
- vga_write_color(0x1F);
- vga_write_until(80);
- vga_write("\n");
- vga_write_until(80);
- vga_write("\n");
- vga_write_until(80);
- vga_write("\n");
- vga_moveto(0,13);
- if (sb_card->reason_not_supported) vga_write(sb_card->reason_not_supported);
-
- vga_moveto(0,16);
- vga_write("\n");
- vga_write_sync();
- _sti();
- redraw = 0;
- uiredraw = 0;
- }
-
- if (kbhit()) {
- int c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27 || c == 13)
- loop = 0;
- else if (isdigit(c)) {
- if (selector == 0) { /* sample rate, allow typing in sample rate */
- int i=0;
- VGA_ALPHA_PTR sco;
- struct vga_msg_box box;
- vga_msg_box_create(&box,"Custom sample rate",2,0);
- sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- while (1) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27)
- break;
- else if (c == 13) {
- if (i == 0) break;
- temp_str[i] = 0;
- wav_sample_rate = strtol(temp_str,NULL,0);
- if (wav_sample_rate < 2000) wav_sample_rate = 2000;
- else if (wav_sample_rate > 64000) wav_sample_rate = 64000;
- uiredraw=1;
- break;
- }
- else if (isdigit(c)) {
- if (i < 5) {
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- }
- }
- else if (c == 8) {
- if (i > 0) i--;
- sco[i] = ' ' | 0x1E00;
- }
- }
- vga_msg_box_destroy(&box);
- }
- }
- else if (c == 0x4800) { /* up arrow */
- if (selector > 0) selector--;
- else selector=7;
- uiredraw=1;
- }
- else if (c == 0x5000) { /* down arrow */
- if (selector < 7) selector++;
- else selector=0;
- uiredraw=1;
- }
- else if (c == 0x4B00) { /* left arrow */
- switch (selector) {
- case 0: /* sample rate */
- ra = param_preset_rates[0];
- for (cc=0;cc < (sizeof(param_preset_rates)/sizeof(param_preset_rates[0]));cc++) {
- if (param_preset_rates[cc] < wav_sample_rate)
- ra = param_preset_rates[cc];
- }
- wav_sample_rate = ra;
- break;
- case 1: /* stereo/mono */
- wav_stereo = !wav_stereo;
- break;
- case 2: /* 8/16-bit */
- wav_16bit = !wav_16bit;
- break;
- case 3: /* translatin */
- if (sb_card->dsp_adpcm == ADPCM_2BIT) {
- sb_card->dsp_adpcm = ADPCM_2_6BIT;
- }
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT) {
- sb_card->dsp_adpcm = ADPCM_4BIT;
- }
- else if (sb_card->dsp_adpcm == ADPCM_4BIT) {
- sb_card->dsp_adpcm = 0;
- }
- else {
- sb_card->dsp_adpcm = ADPCM_2BIT;
- }
- break;
- case 4: /* DSP mode */
- if (sb_card->dsp_play_method == 0)
- sb_card->dsp_play_method = SNDSB_DSPOUTMETHOD_MAX - 1;
- else
- sb_card->dsp_play_method--;
- break;
- case 5: /* Direct DAC read after command/data */
- if (sb_card->dsp_direct_dac_read_after_command != 0)
- sb_card->dsp_direct_dac_read_after_command--;
- break;
- case 6: /* Direct DAC read poll retry timeout */
- if (sb_card->dsp_direct_dac_poll_retry_timeout != 0)
- sb_card->dsp_direct_dac_poll_retry_timeout--;
- break;
- case 7:
- sb_card->backwards ^= 1;
- break;
- };
- update_cfg();
- uiredraw=1;
- }
- else if (c == 0x4D00) { /* right arrow */
- switch (selector) {
- case 0: /* sample rate */
- for (cc=0;cc < ((sizeof(param_preset_rates)/sizeof(param_preset_rates[0]))-1);) {
- if (param_preset_rates[cc] > wav_sample_rate) break;
- cc++;
- }
- wav_sample_rate = param_preset_rates[cc];
- break;
- case 1: /* stereo/mono */
- wav_stereo = !wav_stereo;
- break;
- case 2: /* 8/16-bit */
- wav_16bit = !wav_16bit;
- break;
- case 3: /* translatin */
- if (sb_card->dsp_adpcm == ADPCM_2BIT) {
- sb_card->dsp_adpcm = 0;
- }
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT) {
- sb_card->dsp_adpcm = ADPCM_2BIT;
- }
- else if (sb_card->dsp_adpcm == ADPCM_4BIT) {
- sb_card->dsp_adpcm = ADPCM_2_6BIT;
- }
- else {
- sb_card->dsp_adpcm = ADPCM_4BIT;
- }
- break;
- case 4: /* DSP mode */
- if (++sb_card->dsp_play_method == SNDSB_DSPOUTMETHOD_MAX)
- sb_card->dsp_play_method = 0;
- break;
- case 5: /* Direct DAC read after command/data */
- if (sb_card->dsp_direct_dac_read_after_command < 255)
- sb_card->dsp_direct_dac_read_after_command++;
- break;
- case 6: /* Direct DAC read poll retry timeout */
- if (sb_card->dsp_direct_dac_poll_retry_timeout < 255)
- sb_card->dsp_direct_dac_poll_retry_timeout++;
- break;
- case 7:
- sb_card->backwards ^= 1;
- break;
- };
- update_cfg();
- uiredraw=1;
- }
- }
-
- ui_anim(0);
- }
-
-#if TARGET_MSDOS == 32
- if (!irq_0_had_warned && sb_card->dsp_play_method == SNDSB_DSPOUTMETHOD_DIRECT) {
- /* NOTE TO SELF: It can overwhelm the UI in DOSBox too, but DOSBox seems able to
- recover if you manage to hit CTRL+F12 to speed up the CPU cycles in the virtual machine.
- On real hardware, even with the recovery method the machine remains hung :( */
- if (confirm_yes_no_dialog(dos32_irq_0_warning))
- irq_0_had_warned = 1;
- else
- sb_card->dsp_play_method = oldmethod;
- }
-#endif
-
-#ifdef INCLUDE_FX
- fx_echo_free();
-#endif
- change_param_idx = selector;
- wav_bytes_per_sample = (wav_stereo ? 2 : 1) * (wav_16bit ? 2 : 1);
-}
-
-#ifdef SB_MIXER
-static unsigned char ess688_not_present_init=1;
-static unsigned char ess688_not_present[0x100];
-void play_with_ess() {
- unsigned char bb;
- unsigned char loop=1;
- unsigned char redraw=1;
- unsigned char uiredraw=1;
- signed short offset=0;
- signed short selector=0xA0;
- signed short cc,x,y;
- VGA_ALPHA_PTR vga;
- int bbi;
-
- if (!sb_card->ess_extensions) return;
-
- if (ess688_not_present_init) {
- ess688_not_present_init = 0;
- if (sb_card->ess_chipset == SNDSB_ESS_688) {
- for (cc=0x00;cc < 0xFF;cc++) ess688_not_present[cc] = 1;
- for (cc=0xA0;cc < 0xBA;cc++) ess688_not_present[cc] = 0;
- }
- else {
- for (cc=0x00;cc < 0xFF;cc++) ess688_not_present[cc] = 0;
- }
- }
-
- while (loop) {
- if (redraw || uiredraw) {
- _cli();
- if (redraw) {
- for (vga=vga_alpha_ram+(80*2),cc=0;cc < (80*23);cc++) *vga++ = 0x1E00 | 177;
- ui_anim(1);
- }
- vga_moveto(0,2);
- vga_write_color(0x1F);
- sprintf(temp_str,"x=enter byte value p=re-detect\n");
- vga_write(temp_str);
- vga_write("\n");
-
- redraw = uiredraw = 0;
- if (selector > 0xFF) selector = 0xFF;
- else if (selector < 0) selector = 0;
- offset = 0;
-
- /* reading ESS controllers involves the DSP so avoid conflicts by clearing interrupts */
- _cli();
-
- for (cc=0;cc < 256;cc++) {
- x = ((cc & 15)*3)+4;
- y = (cc >> 4)+4;
- if (ess688_not_present[cc])
- bbi = -1;
- else {
- bbi = sndsb_ess_read_controller(sb_card,(unsigned char)cc);
- if (bbi < 0) ess688_not_present[cc] = 1;
- }
- bb = (unsigned char)bbi;
- vga_moveto(x,y);
- vga_write_color(cc == selector ? 0x70 : (ess688_not_present[cc] ? 0x16 : 0x1E));
- sprintf(temp_str,"%02X ",bb);
- vga_write(temp_str);
-
- if ((cc&15) == 0) {
- sprintf(temp_str,"%02x ",cc&0xF0);
- vga_write_color(0x1F);
- vga_moveto(0,y);
- vga_write(temp_str);
- }
- if (cc <= 15) {
- sprintf(temp_str,"%02x ",cc);
- vga_write_color(0x1F);
- vga_moveto(x,y-1);
- vga_write(temp_str);
- }
- }
-
- _sti();
- }
-
- if (kbhit()) {
- int c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 'p') {
- for (cc=0;cc < 256;cc++) ess688_not_present[cc] = 0;
- redraw = 1;
- }
- else if (c == 'x') {
- int a,b;
-
- vga_moveto(0,2);
- vga_write_color(0x1F);
- vga_write("Type hex value: \n");
- vga_write_sync();
-
- a = getch();
- vga_moveto(20,2);
- vga_write_color(0x1E);
- vga_writec((char)a);
- vga_write_sync();
-
- b = getch();
- vga_moveto(21,2);
- vga_write_color(0x1E);
- vga_writec((char)b);
- vga_write_sync();
-
- if (isxdigit(a) && isxdigit(b)) {
- unsigned char nb;
- nb = (unsigned char)xdigit2int(a) << 4;
- nb |= (unsigned char)xdigit2int(b);
-
- /* reading ESS controllers involves the DSP so avoid conflicts by clearing interrupts */
- _cli();
-
- sndsb_ess_write_controller(sb_card,(unsigned char)selector,nb);
- ess688_not_present[selector] = 0;
-
- _sti();
- }
-
- uiredraw = 1;
- }
- else if (c == ' ')
- uiredraw = 1;
- else if (c == 27)
- loop = 0;
- else if (c == 0x4800) { /* up arrow */
- selector -= 0x10;
- selector &= 0xFF;
- uiredraw=1;
- }
- else if (c == 0x4B00) { /* left arrow */
- selector--;
- selector &= 0xFF;
- uiredraw=1;
- }
- else if (c == 0x4D00) { /* right arrow */
- selector++;
- selector &= 0xFF;
- uiredraw=1;
- }
- else if (c == 0x5000) { /* down arrow */
- selector += 0x10;
- selector &= 0xFF;
- uiredraw=1;
- }
- }
-
- ui_anim(0);
- }
-}
-
-void play_with_mixer() {
- signed short visrows=25-(4+1);
- signed short visy=4;
- signed char mixer=-1;
- unsigned char bb;
- unsigned char loop=1;
- unsigned char redraw=1;
- unsigned char uiredraw=1;
- signed short offset=0;
- signed short selector=0;
- struct sndsb_mixer_control* ent;
- unsigned char rawmode=0;
- signed short cc,x,y;
- VGA_ALPHA_PTR vga;
-
- while (loop) {
- if (redraw || uiredraw) {
- _cli();
- if (redraw) {
- for (vga=vga_alpha_ram+(80*2),cc=0;cc < (80*23);cc++) *vga++ = 0x1E00 | 177;
- ui_anim(1);
- }
- vga_moveto(0,2);
- vga_write_color(0x1F);
- if (rawmode) {
- sprintf(temp_str,"Raw mixer: R=leave raw x=enter byte value\n");
- vga_write(temp_str);
- vga_write("\n");
-
- if (selector > 0xFF) selector = 0xFF;
- else if (selector < 0) selector = 0;
- offset = 0;
- for (cc=0;cc < 256;cc++) {
- x = ((cc & 15)*3)+4;
- y = (cc >> 4)+4;
- bb = sndsb_read_mixer(sb_card,(unsigned char)cc);
- vga_moveto(x,y);
- vga_write_color(cc == selector ? 0x70 : 0x1E);
- sprintf(temp_str,"%02X ",bb);
- vga_write(temp_str);
-
- if ((cc&15) == 0) {
- sprintf(temp_str,"%02x ",cc&0xF0);
- vga_write_color(0x1F);
- vga_moveto(0,y);
- vga_write(temp_str);
- }
- if (cc <= 15) {
- sprintf(temp_str,"%02x ",cc);
- vga_write_color(0x1F);
- vga_moveto(x,y-1);
- vga_write(temp_str);
- }
- }
- }
- else {
- sprintf(temp_str,"Mixer: %s as %s M=toggle mixer R=raw\n",sndsb_mixer_chip_str(sb_card->mixer_chip),
- mixer >= 0 ? sndsb_mixer_chip_str(mixer) : "(same)");
- vga_write(temp_str);
- vga_write("\n");
-
- if (selector >= sb_card->sb_mixer_items)
- selector = sb_card->sb_mixer_items - 1;
- if (offset >= sb_card->sb_mixer_items)
- offset = sb_card->sb_mixer_items - 1;
- if (offset < 0)
- offset = 0;
-
- for (y=0;y < visrows;y++) {
- if ((y+offset) >= sb_card->sb_mixer_items)
- break;
- if (!sb_card->sb_mixer)
- break;
-
- ent = sb_card->sb_mixer + offset + y;
- vga_moveto(0,y+visy);
- vga_write_color((y+offset) == selector ? 0x70 : 0x1E);
- if (ent->length == 1)
- x=sprintf(temp_str,"%s %s",
- sndsb_read_mixer_entry(sb_card,ent) ? "On " : "Off",ent->name);
- else
- x=sprintf(temp_str,"%-3u/%-3u %s",sndsb_read_mixer_entry(sb_card,ent),
- (1 << ent->length) - 1,ent->name);
-
- while (x < 80) temp_str[x++] = ' '; temp_str[x] = 0;
- vga_write(temp_str);
- }
- }
-
- vga_write_sync();
- _sti();
- redraw = 0;
- uiredraw = 0;
- }
-
- if (kbhit()) {
- int c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 'M' || c == 'm') {
- selector = 0;
- offset = 0;
- mixer++;
- if (mixer == 0) mixer++;
- if (mixer == sb_card->mixer_chip) mixer++;
- if (mixer >= SNDSB_MIXER_MAX) mixer = -1;
- sndsb_choose_mixer(sb_card,mixer);
- redraw=1;
- }
- else if (isdigit(c) && !rawmode) {
- int i=0;
- char temp_str[7];
- unsigned int val;
- VGA_ALPHA_PTR sco;
- struct vga_msg_box box;
- vga_msg_box_create(&box,"Custom value",2,0);
- sco = vga_alpha_ram + ((box.y+2) * vga_width) + box.x + 2;
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27)
- break;
- else if (c == 13) {
- if (i == 0) break;
- temp_str[i] = 0;
- val = (unsigned int)strtol(temp_str,NULL,0);
- val &= (1 << sb_card->sb_mixer[selector].length) - 1;
- sndsb_write_mixer_entry(sb_card,sb_card->sb_mixer+selector,val);
- break;
- }
- else if (isdigit(c)) {
- if (i < 5) {
- sco[i] = c | 0x1E00;
- temp_str[i++] = c;
- }
- }
- else if (c == 8) {
- if (i > 0) i--;
- sco[i] = ' ' | 0x1E00;
- }
- }
- }
- vga_msg_box_destroy(&box);
- uiredraw=1;
- }
- else if (c == 'x') {
- int a,b;
-
- vga_moveto(0,2);
- vga_write_color(0x1F);
- vga_write("Type hex value: \n");
- vga_write_sync();
-
- a = getch();
- vga_moveto(20,2);
- vga_write_color(0x1E);
- vga_writec((char)a);
- vga_write_sync();
-
- b = getch();
- vga_moveto(21,2);
- vga_write_color(0x1E);
- vga_writec((char)b);
- vga_write_sync();
-
- if (isxdigit(a) && isxdigit(b)) {
- unsigned char nb;
- nb = (unsigned char)xdigit2int(a) << 4;
- nb |= (unsigned char)xdigit2int(b);
- sndsb_write_mixer(sb_card,(unsigned char)selector,nb);
- }
-
- uiredraw = 1;
- }
- else if (c == 'r' || c == 'R') {
- rawmode = !rawmode;
- selector = 0;
- offset = 0;
- redraw = 1;
- }
- else if (c == 27)
- loop = 0;
- else if (c == ' ')
- uiredraw = 1;
- else if (c == 0x4800) { /* up arrow */
- if (rawmode) {
- selector -= 0x10;
- selector &= 0xFF;
- uiredraw=1;
- }
- else {
- if (selector > 0) {
- uiredraw=1;
- selector--;
- if (offset > selector)
- offset = selector;
- }
- }
- }
- else if (c == 0x4B00) { /* left arrow */
- if (rawmode) {
- selector--;
- selector &= 0xFF;
- uiredraw=1;
- }
- else {
- if (selector >= 0 && selector < sb_card->sb_mixer_items &&
- sb_card->sb_mixer != NULL) {
- unsigned char v = sndsb_read_mixer_entry(sb_card,sb_card->sb_mixer+selector);
- if (v > 0) v--;
- sndsb_write_mixer_entry(sb_card,sb_card->sb_mixer+selector,v);
- uiredraw=1;
- }
- }
- }
- else if (c == 0x4D00) { /* right arrow */
- if (rawmode) {
- selector++;
- selector &= 0xFF;
- uiredraw=1;
- }
- else {
- if (selector >= 0 && selector < sb_card->sb_mixer_items &&
- sb_card->sb_mixer != NULL) {
- unsigned char v = sndsb_read_mixer_entry(sb_card,sb_card->sb_mixer+selector);
- if (v < ((1 << sb_card->sb_mixer[selector].length)-1)) v++;
- sndsb_write_mixer_entry(sb_card,sb_card->sb_mixer+selector,v);
- uiredraw=1;
- }
- }
- }
- else if (c == 0x4900) { /* page up */
- if (rawmode) {
- }
- else {
- if (selector > 0) {
- selector -= visrows-1;
- if (selector < 0) selector = 0;
- if (selector < offset) offset = selector;
- uiredraw=1;
- }
- }
- }
- else if (c == 0x5000) { /* down arrow */
- if (rawmode) {
- selector += 0x10;
- selector &= 0xFF;
- uiredraw=1;
- }
- else {
- if ((selector+1) < sb_card->sb_mixer_items) {
- uiredraw=1;
- selector++;
- if (selector >= (offset+visrows)) {
- offset = selector-(visrows-1);
- }
- }
- }
- }
- else if (c == 0x5100) { /* page down */
- if (rawmode) {
- }
- else {
- if ((selector+1) < sb_card->sb_mixer_items) {
- selector += visrows-1;
- if (selector >= sb_card->sb_mixer_items)
- selector = sb_card->sb_mixer_items-1;
- if (selector >= (offset+visrows))
- offset = selector-(visrows-1);
- uiredraw=1;
- }
- }
- }
- else if (c == '<') {
- if (rawmode) {
- }
- else {
- if (selector >= 0 && selector < sb_card->sb_mixer_items &&
- sb_card->sb_mixer != NULL) {
- sndsb_write_mixer_entry(sb_card,sb_card->sb_mixer+selector,0);
- uiredraw=1;
- }
- }
- }
- else if (c == '>') {
- if (rawmode) {
- }
- else {
- if (selector >= 0 && selector < sb_card->sb_mixer_items &&
- sb_card->sb_mixer != NULL) {
- sndsb_write_mixer_entry(sb_card,sb_card->sb_mixer+selector,
- (1 << sb_card->sb_mixer[selector].length) - 1);
- uiredraw=1;
- }
- }
- }
- }
-
- ui_anim(0);
- }
-}
-#endif
-
-static const struct vga_menu_item menu_separator =
- {(char*)1, 's', 0, 0};
-
-static const struct vga_menu_item main_menu_file_set =
- {"Set file...", 's', 0, 0};
-static const struct vga_menu_item main_menu_file_quit =
- {"Quit", 'q', 0, 0};
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-static const struct vga_menu_item main_menu_windows_fullscreen =
- {"Windows fullscreen", 'f', 0, 0};
-#endif
-
-static const struct vga_menu_item* main_menu_file[] = {
- &main_menu_file_set,
- &main_menu_file_quit,
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- &menu_separator,
- &main_menu_windows_fullscreen,
-#endif
- NULL
-};
-
-static const struct vga_menu_item main_menu_playback_play =
- {"Play", 'p', 0, 0};
-static const struct vga_menu_item main_menu_playback_record =
- {"Record", 'r', 0, 0};
-static const struct vga_menu_item main_menu_playback_stop =
- {"Stop", 's', 0, 0};
-static const struct vga_menu_item main_menu_playback_params =
- {"Parameters", 'a', 0, 0};
-static struct vga_menu_item main_menu_playback_reduced_irq =
- {"xxx", 'i', 0, 0};
-static struct vga_menu_item main_menu_playback_autoinit_adpcm =
- {"xxx", 'd', 0, 0};
-static struct vga_menu_item main_menu_playback_goldplay =
- {"xxx", 'g', 0, 0};
-static struct vga_menu_item main_menu_playback_goldplay_mode =
- {"xxx", 'm', 0, 0};
-static struct vga_menu_item main_menu_playback_dsp_autoinit_dma =
- {"xxx", 't', 0, 0};
-static struct vga_menu_item main_menu_playback_dsp_autoinit_command =
- {"xxx", 'c', 0, 0};
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-static struct vga_menu_item main_menu_playback_noreset_adpcm =
- {"xxx", 'n', 0, 0};
-static struct vga_menu_item main_menu_playback_timer_clamp =
- {"xxx", 0, 0, 0};
-static struct vga_menu_item main_menu_playback_force_hispeed =
- {"xxx", 'h', 0, 0};
-static struct vga_menu_item main_menu_playback_flip_sign =
- {"xxx", 'l', 0, 0};
-static struct vga_menu_item main_menu_playback_dsp4_fifo_autoinit =
- {"xxx", 'f', 0, 0};
-static struct vga_menu_item main_menu_playback_dsp4_fifo_single =
- {"xxx", 'e', 0, 0};
-static struct vga_menu_item main_menu_playback_dsp_nag_mode =
- {"xxx", 'o', 0, 0};
-static struct vga_menu_item main_menu_playback_dsp_poll_ack_no_irq =
- {"xxx", 'q', 0, 0};
-#endif
-
-static const struct vga_menu_item* main_menu_playback[] = {
- &main_menu_playback_play,
- &main_menu_playback_record,
- &main_menu_playback_stop,
- &menu_separator,
- &main_menu_playback_params,
- &main_menu_playback_reduced_irq,
- &main_menu_playback_autoinit_adpcm,
- &main_menu_playback_goldplay,
- &main_menu_playback_goldplay_mode,
- &main_menu_playback_dsp_autoinit_dma,
- &main_menu_playback_dsp_autoinit_command,
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- &main_menu_playback_noreset_adpcm,
- &main_menu_playback_timer_clamp,
- &main_menu_playback_force_hispeed,
- &main_menu_playback_flip_sign,
- &main_menu_playback_dsp4_fifo_autoinit,
- &main_menu_playback_dsp4_fifo_single,
- &main_menu_playback_dsp_nag_mode,
- &main_menu_playback_dsp_poll_ack_no_irq,
-#endif
- NULL
-};
-
-static const struct vga_menu_item main_menu_device_dsp_reset =
- {"DSP reset", 'r', 0, 0};
-static const struct vga_menu_item main_menu_device_mixer_reset =
- {"Mixer reset", 'r', 0, 0};
-static const struct vga_menu_item main_menu_device_trigger_irq =
- {"Trigger IRQ", 't', 0, 0};
-#ifdef SB_MIXER
-static const struct vga_menu_item main_menu_device_mixer_controls =
- {"Mixer controls", 'm', 0, 0};
-static const struct vga_menu_item main_menu_device_ess_controls =
- {"ESS 688/1868 controls",'e', 0, 0};
-#endif
-#ifdef CARD_INFO_AND_CHOOSER
-static const struct vga_menu_item main_menu_device_info =
- {"Information", 'i', 0, 0};
-static const struct vga_menu_item main_menu_device_choose_sound_card =
- {"Choose sound card", 'c', 0, 0};
-#endif
-#ifdef LIVE_CFG
-static const struct vga_menu_item main_menu_device_configure_sound_card =
- {"Configure sound card",'o', 0, 0};
-#endif
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-static struct vga_menu_item main_menu_device_dsp_alias =
- {"Alias ports", 'a', 0, 0};
-#endif
-
-static const struct vga_menu_item* main_menu_device[] = {
- &main_menu_device_dsp_reset,
- &main_menu_device_mixer_reset,
- &main_menu_device_trigger_irq,
-#ifdef SB_MIXER
- &main_menu_device_mixer_controls,
- &main_menu_device_ess_controls,
-#endif
-#ifdef CARD_INFO_AND_CHOOSER
- &main_menu_device_info,
- &main_menu_device_choose_sound_card,
-#endif
-#ifdef LIVE_CFG
- &main_menu_device_configure_sound_card,
-#endif
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- &main_menu_device_dsp_alias,
-#endif
- NULL
-};
-
-static const struct vga_menu_item main_menu_help_about =
- {"About", 'r', 0, 0};
-
-
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
-static const struct vga_menu_item main_menu_help_dsp_modes =
- {"DSP modes", 'd', 0, 0};
-#endif
-static const struct vga_menu_item* main_menu_help[] = {
- &main_menu_help_about,
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- &menu_separator,
- &main_menu_help_dsp_modes,
-#endif
- NULL
-};
-
-#ifdef INCLUDE_FX
-static const struct vga_menu_item main_menu_effects_reset =
- {"Reset", 'r', 0, 0};
-
-static const struct vga_menu_item main_menu_effects_vol =
- {"Volume", 'v', 0, 0};
-
-static const struct vga_menu_item main_menu_effects_echo =
- {"Echo", 'e', 0, 0};
-
-static const struct vga_menu_item* main_menu_effects[] = {
- &main_menu_effects_reset,
- &main_menu_effects_vol,
- &main_menu_effects_echo,
- NULL
-};
-#endif
-
-static const struct vga_menu_bar_item main_menu_bar[] = {
- /* name key scan x w id */
- {" File ", 'F', 0x21, 0, 6, &main_menu_file}, /* ALT-F */
- {" Playback ", 'P', 0x19, 6, 10, &main_menu_playback}, /* ALT-P */
- {" Device ", 'D', 0x20, 16, 8, &main_menu_device}, /* ALT-D */
-#ifdef INCLUDE_FX
- {" Effects ", 'E', 0x12, 24, 9, &main_menu_effects}, /* ALT-E */
- {" Help ", 'H', 0x23, 33, 6, &main_menu_help}, /* ALT-H */
-#else
- {" Help ", 'H', 0x23, 24, 6, &main_menu_help}, /* ALT-H */
-#endif
- {NULL, 0, 0x00, 0, 0, 0}
-};
-
-static void my_vga_menu_idle() {
- ui_anim(0);
-}
-
-int confirm_quit() {
- /* FIXME: Why does this cause Direct DSP playback to horrifically slow down? */
- return confirm_yes_no_dialog("Are you sure you want to exit to DOS?");
-}
-
-int adpcm_warning_prompt() {
- return confirm_yes_no_dialog("Most Sound Blaster clones do not support auto-init ADPCM playback.\nIf nothing plays when enabled, your sound card is one of them.\n\nEnable?");
-}
-
-void update_cfg() {
- unsigned int r;
-
- wav_sample_rate_by_timer_ticks = T8254_REF_CLOCK_HZ / wav_sample_rate;
- if (wav_sample_rate_by_timer_ticks == 0) wav_sample_rate_by_timer_ticks = 1;
- wav_sample_rate_by_timer = T8254_REF_CLOCK_HZ / wav_sample_rate_by_timer_ticks;
-
- sb_card->dsp_adpcm = sb_card->dsp_adpcm;
- sb_card->dsp_record = wav_record;
- r = wav_sample_rate;
- if (sb_card->dsp_adpcm == ADPCM_4BIT) r /= 2;
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT) r /= 3;
- else if (sb_card->dsp_adpcm == ADPCM_2BIT) r /= 4;
- adpcm_counter = 0;
- adpcm_reset_interval = 0;
- if (sb_card->dsp_adpcm > 0) {
- if (sb_card->dsp_adpcm == ADPCM_4BIT)
- sb_card->buffer_irq_interval = wav_sample_rate / 2;
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT)
- sb_card->buffer_irq_interval = wav_sample_rate / 3;
- else if (sb_card->dsp_adpcm == ADPCM_2BIT)
- sb_card->buffer_irq_interval = wav_sample_rate / 4;
-
- if (reduced_irq_interval == 2)
- sb_card->buffer_irq_interval = sb_card->buffer_size;
- else if (reduced_irq_interval == 0)
- sb_card->buffer_irq_interval /= 15;
- else if (reduced_irq_interval == -1)
- sb_card->buffer_irq_interval /= 100;
-
- if (sb_card->dsp_adpcm == ADPCM_4BIT)
- sb_card->buffer_irq_interval &= ~1UL;
- else if (sb_card->dsp_adpcm == ADPCM_2_6BIT)
- sb_card->buffer_irq_interval -=
- sb_card->buffer_irq_interval % 3;
- else if (sb_card->dsp_adpcm == ADPCM_2BIT)
- sb_card->buffer_irq_interval &= ~3UL;
-
- if (adpcm_do_reset_interval)
- adpcm_reset_interval = sb_card->buffer_irq_interval;
- }
- else {
- sb_card->buffer_irq_interval = r;
- if (reduced_irq_interval == 2)
- sb_card->buffer_irq_interval =
- sb_card->buffer_size / wav_bytes_per_sample;
- else if (reduced_irq_interval == 0)
- sb_card->buffer_irq_interval /= 15;
- else if (reduced_irq_interval == -1)
- sb_card->buffer_irq_interval /= 100;
- }
-
- if (reduced_irq_interval == 2)
- main_menu_playback_reduced_irq.text =
- "IRQ interval: full length";
- else if (reduced_irq_interval == 1)
- main_menu_playback_reduced_irq.text =
- "IRQ interval: large";
- else if (reduced_irq_interval == 0)
- main_menu_playback_reduced_irq.text =
- "IRQ interval: small";
- else /* -1 */
- main_menu_playback_reduced_irq.text =
- "IRQ interval: tiny";
-
- if (goldplay_samplerate_choice == GOLDRATE_MATCH)
- main_menu_playback_goldplay_mode.text =
- "Goldplay sample rate: Match";
- else if (goldplay_samplerate_choice == GOLDRATE_DOUBLE)
- main_menu_playback_goldplay_mode.text =
- "Goldplay sample rate: Double";
- else if (goldplay_samplerate_choice == GOLDRATE_MAX)
- main_menu_playback_goldplay_mode.text =
- "Goldplay sample rate: Max";
- else
- main_menu_playback_goldplay_mode.text =
- "?";
-
- main_menu_playback_autoinit_adpcm.text =
- sb_card->enable_adpcm_autoinit ? "ADPCM Auto-init: On" : "ADPCM Auto-init: Off";
- main_menu_playback_goldplay.text =
- sb_card->goldplay_mode ? "Goldplay mode: On" : "Goldplay mode: Off";
- main_menu_playback_dsp_autoinit_dma.text =
- sb_card->dsp_autoinit_dma ? "DMA autoinit: On" : "DMA autoinit: Off";
- main_menu_playback_dsp_autoinit_command.text =
- sb_card->dsp_autoinit_command ? "DSP playback: auto-init" : "DSP playback: single-cycle";
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- main_menu_playback_force_hispeed.text =
- sb_card->force_hispeed ? "Force hispeed: On" : "Force hispeed: Off";
- main_menu_playback_noreset_adpcm.text =
- adpcm_do_reset_interval ? "ADPCM reset step/interval: On" : "ADPCM reset step/interval: Off";
- main_menu_playback_timer_clamp.text =
- sample_rate_timer_clamp ? "Clamp samplerate to timer: On" : "Clamp samplerate to timer: Off";
- main_menu_playback_flip_sign.text =
- sb_card->audio_data_flipped_sign ? "Flipped sign: On" : "Flipped sign: Off";
- main_menu_playback_dsp4_fifo_autoinit.text =
- sb_card->dsp_4xx_fifo_autoinit ? "DSP 4.xx autoinit FIFO: On" : "DSP 4.xx autoinit FIFO: Off";
- main_menu_playback_dsp4_fifo_single.text =
- sb_card->dsp_4xx_fifo_single_cycle ? "DSP 4.xx single FIFO: On" : "DSP 4.xx single FIFO: Off";
- main_menu_playback_dsp_nag_mode.text =
- sb_card->dsp_nag_mode ?
- (sb_card->dsp_nag_hispeed ? "DSP nag mode: All" : "DSP nag mode: Non-highspeed")
- : "DSP nag mode: Off";
- main_menu_playback_dsp_poll_ack_no_irq.text =
- sb_card->poll_ack_when_no_irq ? "Poll ack when no IRQ: On" : "Poll ack when no IRQ: Off";
-
-#endif
-}
-
-void prompt_play_wav(unsigned char rec) {
- unsigned char gredraw = 1;
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
- struct find_t ft;
-#endif
-
- {
- const char *rp;
- char temp[sizeof(wav_file)];
- int cursor = strlen(wav_file),i,c,redraw=1,ok=0;
- memcpy(temp,wav_file,strlen(wav_file)+1);
- while (!ok) {
- if (gredraw) {
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
- char *cwd;
-#endif
-
- gredraw = 0;
- vga_clear();
- vga_moveto(0,4);
- vga_write_color(0x07);
- vga_write("Enter WAV file path:\n");
- vga_write_sync();
- draw_irq_indicator();
- ui_anim(1);
- redraw = 1;
-
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
- cwd = getcwd(NULL,0);
- if (cwd) {
- vga_moveto(0,6);
- vga_write_color(0x0B);
- vga_write(cwd);
- vga_write_sync();
- }
-
- if (_dos_findfirst("*.*",_A_NORMAL|_A_RDONLY,&ft) == 0) {
- int x=0,y=7,cw = 14,i;
- char *ex;
-
- do {
- ex = strrchr(ft.name,'.');
- if (!ex) ex = "";
-
- if (ft.attrib&_A_SUBDIR) {
- vga_write_color(0x0F);
- }
- else if (!strcasecmp(ex,".wav")) {
- vga_write_color(0x1E);
- }
- else {
- vga_write_color(0x07);
- }
- vga_moveto(x,y);
- for (i=0;i < 13 && ft.name[i] != 0;) vga_writec(ft.name[i++]);
- for (;i < 14;i++) vga_writec(' ');
-
- x += cw;
- if ((x+cw) > vga_width) {
- x = 0;
- if (y >= vga_height) break;
- y++;
- }
- } while (_dos_findnext(&ft) == 0);
-
- _dos_findclose(&ft);
- }
-#endif
- }
- if (redraw) {
- rp = (const char*)temp;
- vga_moveto(0,5);
- vga_write_color(0x0E);
- for (i=0;i < 80;i++) {
- if (*rp != 0) vga_writec(*rp++);
- else vga_writec(' ');
- }
- vga_moveto(cursor,5);
- vga_write_sync();
- redraw=0;
- }
-
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- ok = -1;
- }
- else if (c == 13) {
-#if TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
- ok = 1;
-#else
- struct stat st;
-
- if (isalpha(temp[0]) && temp[1] == ':' && temp[2] == 0) {
- unsigned int total;
-
- _dos_setdrive(tolower(temp[0])+1-'a',&total);
- temp[0] = 0;
- gredraw = 1;
- cursor = 0;
- }
- else if (stat(temp,&st) == 0) {
- if (S_ISDIR(st.st_mode)) {
- chdir(temp);
- temp[0] = 0;
- gredraw = 1;
- cursor = 0;
- }
- else {
- ok = 1;
- }
- }
- else {
- ok = 1;
- }
-#endif
- }
- else if (c == 8) {
- if (cursor != 0) {
- temp[--cursor] = 0;
- redraw = 1;
- }
- }
- else if (c >= 32 && c < 256) {
- if (cursor < 79) {
- temp[cursor++] = (char)c;
- temp[cursor ] = (char)0;
- redraw = 1;
- }
- }
- }
- else {
- ui_anim(0);
- }
- }
-
- if (ok == 1) {
- unsigned char wp = wav_playing;
- stop_play();
- close_wav();
- memcpy(wav_file,temp,strlen(temp)+1);
- open_wav();
- if (wp) begin_play();
- }
- }
-}
-
-static void help() {
- printf("test [options]\n");
-#if !(TARGET_MSDOS == 16 && defined(__COMPACT__)) /* this is too much to cram into a small model EXE */
- printf(" /h /help This help\n");
- printf(" /nopnp Don't scan for ISA Plug & Play devices\n");
- printf(" /noprobe Don't probe ISA I/O ports for non PnP devices\n");
- printf(" /noenv Don't use BLASTER environment variable\n");
- printf(" /wav=<file> Open with specified WAV file\n");
- printf(" /play Automatically start playing WAV file\n");
- printf(" /sc=<N> Automatically pick Nth sound card (first card=1)\n");
- printf(" /ddac Force DSP Direct DAC output mode\n");
- printf(" /16k /8k /4k Limit DMA buffer to 16k, 8k, or 4k\n");
- printf(" /nomirqp Disable 'manual' IRQ probing\n");
- printf(" /noairqp Disable 'alt' IRQ probing\n");
- printf(" /nosb16cfg Don't read configuration from SB16 config byte\n");
- printf(" /nodmap Disable DMA probing\n");
- printf(" /nohdmap Disable 16-bit DMA probing\n");
- printf(" /nowinvxd don't try to identify Windows drivers\n");
- printf(" /nochain Don't chain to previous IRQ (sound blaster IRQ)\n");
- printf(" /noidle Don't use sndsb library idle function\n");
- printf(" /adma Assume DMA controllers are present\n");
- printf(" /noess Do not use/detect ESS 688/1869 extensions\n");
- printf(" /sbalias:dsp Use DSP alias port 0x22D by default\n");
- printf(" /ex-ess Experimentally use ESS extensions for ESS chips\n");
- printf(" not directly supported.\n");
-#endif
-
-#if TARGET_MSDOS == 32
- printf("The following option affects hooking the NMI interrupt. Hooking is\n");
- printf("required to work with Gravis Ultrasound SBOS/MEGA-EM SB emulation\n");
- printf("and to work around problems with common DOS extenders. If not specified,\n");
- printf("the program will only hook NMI if SBOS/MEGA-EM is resident.\n");
- printf(" /-nmi or /+nmi Don't / Do hook NMI interrupt, reflect to real mode.\n");
-#endif
-}
-
-#ifdef CARD_INFO_AND_CHOOSER
-void draw_device_info(struct sndsb_ctx *cx,int x,int y,int w,int h) {
- int row = 2;
-
- /* clear prior contents */
- {
- VGA_ALPHA_PTR p = vga_alpha_ram + (y * vga_width) + x;
- unsigned int a,b;
-
- for (b=0;b < h;b++) {
- for (a=0;a < w;a++) {
- *p++ = 0x1E20;
- }
- p += vga_width - w;
- }
- }
-
- vga_write_color(0x1E);
-
- vga_moveto(x,y + 0);
- sprintf(temp_str,"BASE:%03Xh MPU:%03Xh DMA:%-2d DMA16:%-2d IRQ:%-2d ",
- cx->baseio, cx->mpuio, cx->dma8, cx->dma16, cx->irq);
- vga_write(temp_str);
- if (cx->dsp_ok) {
- sprintf(temp_str,"DSP: v%u.%u ",
- cx->dsp_vmaj, cx->dsp_vmin);
- vga_write(temp_str);
- }
- else {
- vga_write("DSP: No ");
- }
-
- if (cx->mixer_ok) {
- sprintf(temp_str,"MIXER: %s",sndsb_mixer_chip_str(cx->mixer_chip));
- vga_write(temp_str);
- }
- else {
- vga_write("MIXER: No");
- }
-
- vga_moveto(x,y + 1);
- if (cx->dsp_ok) {
- sprintf(temp_str,"DSP String: %s",cx->dsp_copyright);
- vga_write(temp_str);
- }
-
- if (row < h && (cx->is_gallant_sc6600 || cx->mega_em || cx->sbos)) {
- vga_moveto(x,y + (row++));
- if (cx->is_gallant_sc6600) vga_write("SC-6600 ");
- if (cx->mega_em) vga_write("MEGA-EM ");
- if (cx->sbos) vga_write("SBOS ");
- }
- if (row < h) {
- vga_moveto(x,y + (row++));
- if (cx->pnp_name != NULL) {
- isa_pnp_product_id_to_str(temp_str,cx->pnp_id);
- vga_write("ISA PnP: ");
- vga_write(temp_str);
- vga_write(" ");
- vga_write(cx->pnp_name);
- }
- }
-}
-
-void show_device_info() {
- int c,rows=2,cols=70;
- struct vga_msg_box box;
-
- if (sb_card->is_gallant_sc6600 || sb_card->mega_em || sb_card->sbos)
- rows++;
- if (sb_card->pnp_id != 0 || sb_card->pnp_name != NULL)
- rows++;
-
- vga_msg_box_create(&box,"",rows,cols); /* 3 rows 70 cols */
- draw_device_info(sb_card,box.x+2,box.y+1,cols-4,rows);
-
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27 || c == 13)
- break;
- }
- }
-
- vga_msg_box_destroy(&box);
-}
-
-void draw_sound_card_choice(unsigned int x,unsigned int y,unsigned int w,struct sndsb_ctx *cx,int sel) {
- const char *msg = cx->dsp_copyright;
-
- vga_moveto(x,y);
- if (cx->baseio != 0) {
- vga_write_color(sel ? 0x70 : 0x1F);
- sprintf(temp_str,"%03Xh IRQ%-2d DMA%d DMA%d MPU:%03Xh ",
- cx->baseio, cx->irq, cx->dma8, cx->dma16, cx->mpuio);
- vga_write(temp_str);
- while (vga_pos_x < (x+w) && *msg != 0) vga_writec(*msg++);
- }
- else {
- vga_write_color(sel ? 0x70 : 0x18);
- vga_write("(none)");
- }
- while (vga_pos_x < (x+w)) vga_writec(' ');
-}
-#endif
-
-#ifdef LIVE_CFG
-static const signed char sc6600_irq[] = { -1,5,7,9,10,11 };
-static const signed char sc6600_dma[] = { -1,0,1,3 };
-
-static const signed char sb16_non_pnp_irq[] = { -1,2,5,7,10 };
-static const signed char sb16_non_pnp_dma[] = { -1,0,1,3 };
-static const signed char sb16_non_pnp_dma16[] = { -1,0,1,3,5,6,7 };
-
-static const int16_t sb16_pnp_base[] = { 0x220,0x240,0x260,0x280 };
-static const signed char sb16_pnp_irq[] = { -1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
-static const signed char sb16_pnp_dma[] = { -1,0,1,3 };
-static const signed char sb16_pnp_dma16[] = { -1,0,1,3,5,6,7 };
-
-static const signed char ess_688_irq[] = { -1,5,7,9,10 }; /* NTS: The datasheet says 2/9/"all others". Since PCs map IRQ 2 to IRQ 9 we'll just say "IRQ 9" */
-static const signed char ess_688_dma[] = { -1,0,1,3 };
-
-signed char ess_688_map_to_dma[4] = {-1, 0, 1, 3}; /* NTS: Not sure what the datasheet means by "all others" when value == 0x0 */
-signed char ess_688_map_to_irq[8] = { 9, 5, 7, 10}; /* NTS: Doesn't seem to be a way to say "no IRQ". value == 0x0 is 2/9/"all others" and IRQ 2 on ISA is mapped to IRQ 9, so.. */
-
-struct conf_list_item {
- unsigned char etype;
- unsigned char name;
- unsigned char setting;
- unsigned char listlen;
- void* list;
-};
-
-enum {
- ET_SCHAR,
- ET_SINTX
-};
-
-enum {
- ER_IRQ, /* 0 */
- ER_DMA,
- ER_DMA16,
- ER_BASE
-};
-
-static const char *ER_NAMES[] = {
- "IRQ", /* 0 */
- "DMA",
- "DMA16",
- "BASE"
-};
-
-static struct conf_list_item ess_688[] = {
- {ET_SCHAR, ER_IRQ, 0, sizeof(ess_688_irq), (void*)ess_688_irq},
- {ET_SCHAR, ER_DMA, 0, sizeof(ess_688_dma), (void*)ess_688_dma},
-};
-
-static struct conf_list_item sc6600[] = {
- {ET_SCHAR, ER_IRQ, 0, sizeof(sc6600_irq), (void*)sc6600_irq},
- {ET_SCHAR, ER_DMA, 0, sizeof(sc6600_dma), (void*)sc6600_dma},
-};
-
-static struct conf_list_item sb16_non_pnp[] = {
- {ET_SCHAR, ER_IRQ, 0, sizeof(sb16_non_pnp_irq), (void*)sb16_non_pnp_irq},
- {ET_SCHAR, ER_DMA, 0, sizeof(sb16_non_pnp_dma), (void*)sb16_non_pnp_dma},
- {ET_SCHAR, ER_DMA16, 0, sizeof(sb16_non_pnp_dma16), (void*)sb16_non_pnp_dma16}
-};
-
-static struct conf_list_item sb16_pnp[] = {
- {ET_SINTX, ER_BASE, 0, sizeof(sb16_pnp_base)/2, (void*)sb16_pnp_base},
- {ET_SCHAR, ER_IRQ, 0, sizeof(sb16_pnp_irq), (void*)sb16_pnp_irq},
- {ET_SCHAR, ER_DMA, 0, sizeof(sb16_pnp_dma), (void*)sb16_pnp_dma},
- {ET_SCHAR, ER_DMA16, 0, sizeof(sb16_pnp_dma16), (void*)sb16_pnp_dma16}
-};
-
-void conf_item_index_lookup(struct conf_list_item *item,int val) {
- if (item->etype == ET_SCHAR) {
- item->setting = 0;
- while (item->setting < item->listlen && ((signed char*)(item->list))[item->setting] != val)
- item->setting++;
- }
- else if (item->etype == ET_SINTX) {
- item->setting = 0;
- while (item->setting < item->listlen && ((int16_t*)(item->list))[item->setting] != val)
- item->setting++;
- }
-
- if (item->setting == item->listlen)
- item->setting = 0;
-}
-
-int conf_sound_card_list(const char *title,struct conf_list_item *list,const int list_items,int width) {
- struct conf_list_item *li;
- unsigned char redraw = 1;
- unsigned char sel = 0,i;
- struct vga_msg_box box;
- int c;
-
- vga_msg_box_create(&box,title,2,width);
- do {
- if (redraw) {
- vga_moveto(box.x + 2,box.y + 2);
-
- for (i=0;i < list_items;i++) {
- li = list + i;
- vga_write_color(0x1E);
- vga_write(ER_NAMES[li->name]);
- vga_writec(':');
- vga_write_color(sel == i ? 0x70 : 0x1E);
- if (li->etype == ET_SCHAR) {
- signed char v = ((signed char*)(li->list))[li->setting];
- if (v >= 0) sprintf(temp_str,"%-2u",v);
- else sprintf(temp_str,"NA");
- vga_write(temp_str);
- }
- else if (li->etype == ET_SINTX) {
- int16_t v = ((int16_t*)(li->list))[li->setting];
- if (v >= 0) sprintf(temp_str,"%03x",v);
- else sprintf(temp_str,"NA ");
- vga_write(temp_str);
- }
- vga_write_color(0x1E);
- vga_writec(' ');
- }
-
- redraw=0;
- }
-
- ui_anim(0);
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27 || c == 13) break;
- if (c == 0x4B00) {
- if (sel == 0) sel = list_items-1;
- else sel--;
- redraw=1;
- }
- else if (c == 0x4D00) {
- if (sel == (list_items-1)) sel = 0;
- else sel++;
- redraw=1;
- }
- else if (c == 0x4800) { /* up arrow */
- do {
- li = list + sel;
- if ((++li->setting) >= li->listlen) li->setting = 0;
-
- if (li->etype == ET_SCHAR) {
- signed char v = ((signed char*)(li->list))[li->setting];
- if (li->name == ER_DMA || li->name == ER_DMA16) {
- if (v >= 0 && v != sb_card->dma8 && v != sb_card->dma16 && sndsb_by_dma(v) != NULL)
- continue;
- }
- else if (li->name == ER_IRQ) {
- if (v >= 0 && v != sb_card->irq && sndsb_by_irq(v) != NULL)
- continue;
- }
- }
- else if (li->etype == ET_SINTX) {
- int16_t v = ((int16_t*)(li->list))[li->setting];
- if (li->name == ER_BASE) {
- if (v > 0 && v != sb_card->baseio && sndsb_by_base(v) != NULL)
- continue;
- }
- }
-
- break;
- } while (1);
- redraw = 1;
- }
- else if (c == 0x5000) { /* down arrow */
- do {
- li = list + sel;
- if (li->setting == 0) li->setting = li->listlen - 1;
- else li->setting--;
-
- if (li->etype == ET_SCHAR) {
- signed char v = ((signed char*)(li->list))[li->setting];
- if (li->name == ER_DMA || li->name == ER_DMA16) {
- if (v >= 0 && v != sb_card->dma8 && v != sb_card->dma16 && sndsb_by_dma(v) != NULL)
- continue;
- }
- else if (li->name == ER_IRQ) {
- if (v >= 0 && v != sb_card->irq && sndsb_by_irq(v) != NULL)
- continue;
- }
- }
- else if (li->etype == ET_SINTX) {
- int16_t v = ((int16_t*)(li->list))[li->setting];
- if (li->name == ER_BASE) {
- if (v > 0 && v != sb_card->baseio && sndsb_by_base(v) != NULL)
- continue;
- }
- }
-
- break;
- } while (1);
- redraw = 1;
- }
- }
- } while (1);
-
- vga_msg_box_destroy(&box);
- return (c == 13);
-}
-
-void conf_sound_card() {
- /* VDMSOUND emulates the mixer byte that reports config, but it gets confused when you change it */
- if (sb_card->vdmsound) {
- }
- /* Creative SB16 drivers for Windows: Despite the ability to do so, it's probably not a good idea
- * to change the configuration out from under it */
- else if (sb_card->windows_creative_sb16_drivers) {
- }
- else if (sb_card->ess_extensions && sb_card->ess_chipset == SNDSB_ESS_688) {
- /* ESS control registers also allow changing IRQ/DMA, at least on non-PnP versions.
- * It's also possible to change the base I/O, even if the PnP protocol is not available,
- * but that's a bit too iffy at the moment to play with.
- *
- * TODO: This configuration method is said not to work if the ESS 688 is a ISA PnP
- * device. So far the only ESS 688 have is in a laptop where the chip is "embedded"
- * into the motherboard and is "Plug & Play" only in that the PnP BIOS reports it
- * in device node enumeration, yet I am apparently able to change IRQ/DMA resources
- * this way. UPDATE: Well, it turns out the chip lets me change the IRQ, but the
- * DMA channel seems to be fixed (unchangeable). */
- conf_item_index_lookup(&ess_688[0]/*IRQ*/,sb_card->irq);
- conf_item_index_lookup(&ess_688[1]/*DMA*/,sb_card->dma8);
- if (conf_sound_card_list("ESS 688",ess_688,sizeof(ess_688)/sizeof(ess_688[0]),56)) {
- signed char IRQ = ess_688_irq[ess_688[0].setting];/*IRQ*/
- signed char DMA8 = ess_688_dma[ess_688[1].setting];/*DMA*/
- unsigned char do_stop_start = wav_playing;
- unsigned char irq_i=0,dma_i=0;
- int tmp;
-
- if (do_stop_start) stop_play();
-
- if (sb_card->irq != -1) {
- _dos_setvect(irq2int(sb_card->irq),old_irq);
- if (old_irq_masked) p8259_mask(sb_card->irq);
- }
-
- if (DMA8 > 3) DMA8 = -1;
-
- while (dma_i < 3 && ess_688_map_to_dma[dma_i] != DMA8) dma_i++;
- while (irq_i < 7 && ess_688_map_to_irq[irq_i] != IRQ) irq_i++;
-
- /* byte expansion:
- *
- * 00 = 0000
- * 01 = 0101
- * 10 = 1010
- * 11 = 1111
- */
- dma_i = (dma_i & 3) | ((dma_i & 3) << 2);
- irq_i = (irq_i & 3) | ((irq_i & 3) << 2);
-
- /* write the ESS registers to make the change */
- /* NTS: on later chipsets (PnP) these are readonly */
- tmp = sndsb_ess_read_controller(sb_card,0xB1); /* interrupt control */
- if (tmp >= 0) {
- tmp = (tmp & 0xF0) + irq_i;
- sndsb_ess_write_controller(sb_card,0xB1,(unsigned char)tmp);
- }
-
- tmp = sndsb_ess_read_controller(sb_card,0xB2); /* DMA control */
- if (tmp >= 0) {
- tmp = (tmp & 0xF0) + dma_i;
- sndsb_ess_write_controller(sb_card,0xB2,(unsigned char)tmp);
- }
- sndsb_reset_dsp(sb_card);
-
- /* now... some registers might actually be readonly.
- * we'll find out when we readback and find which ones have changed. */
- tmp = sndsb_ess_read_controller(sb_card,0xB1); /* interrupt control */
- if (tmp >= 0) {
- if ((tmp&3) == ((tmp>>2)&3))
- IRQ = ess_688_map_to_irq[tmp & 3];
- }
- tmp = sndsb_ess_read_controller(sb_card,0xB2); /* DMA control */
- if (tmp >= 0) {
- if ((tmp&3) == ((tmp>>2)&3))
- DMA8 = ess_688_map_to_dma[tmp & 3];
- }
-
- /* then the library needs to be updated */
- /* TODO: there should be a sndsb_ call to do this! */
- sb_card->dma8 = DMA8;
- sb_card->dma16 = DMA8;
- sb_card->irq = IRQ;
-
- if (sb_card->irq != -1) {
- old_irq_masked = p8259_is_masked(sb_card->irq);
- old_irq = _dos_getvect(irq2int(sb_card->irq));
- _dos_setvect(irq2int(sb_card->irq),sb_irq);
- p8259_unmask(sb_card->irq);
- }
-
- if (do_stop_start) begin_play();
- }
- return;
- }
- /* -------- ISA Plug & Play --------- */
- else if (sb_card->pnp_id != 0) {
- if (ISAPNP_ID_FMATCH(sb_card->pnp_id,'C','T','L')) {
- conf_item_index_lookup(&sb16_pnp[0]/*BASE*/,sb_card->baseio);
- conf_item_index_lookup(&sb16_pnp[1]/*IRQ*/,sb_card->irq);
- conf_item_index_lookup(&sb16_pnp[2]/*DMA*/,sb_card->dma8);
- conf_item_index_lookup(&sb16_pnp[3]/*DMA16*/,sb_card->dma16);
- if (conf_sound_card_list("Creative Sound Blaster 16 PnP configuration",sb16_pnp,sizeof(sb16_pnp)/sizeof(sb16_pnp[0]),56)) {
- int16_t BASE = sb16_pnp_base[sb16_pnp[0].setting];/*BASE*/
- signed char IRQ = sb16_pnp_irq[sb16_pnp[1].setting];/*IRQ*/
- signed char DMA8 = sb16_pnp_dma[sb16_pnp[2].setting];/*DMA*/
- signed char DMA16 = sb16_pnp_dma16[sb16_pnp[3].setting];/*DMA16*/
- unsigned char do_stop_start = wav_playing;
-
- if (do_stop_start) stop_play();
- isa_pnp_init_key();
- isa_pnp_wake_csn(sb_card->pnp_csn);
-
- if (sb_card->irq != -1) {
- _dos_setvect(irq2int(sb_card->irq),old_irq);
- if (old_irq_masked) p8259_mask(sb_card->irq);
- }
-
- if (DMA8 > 3) DMA8 = -1;
-
- /* disable the device IO (0) */
- isa_pnp_write_address(0x07); /* log device select */
- isa_pnp_write_data(0x00); /* main device */
-
- isa_pnp_write_data_register(0x30,0x00); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
-
- isa_pnp_write_io_resource(0,BASE >= 0 ? BASE : 0);
- isa_pnp_write_dma(0,DMA8 >= 0 ? DMA8 : 4); /* setting the DMA field to "4" is how you unassign the resource */
- isa_pnp_write_dma(1,DMA16 >= 0 ? DMA16 : 4);
- isa_pnp_write_irq(0,IRQ > 0 ? IRQ : 0); /* setting the IRQ field to "0" is how you unassign the resource */
- isa_pnp_write_irq_mode(0,2); /* edge level high */
-
- /* enable the device IO */
- isa_pnp_write_data_register(0x30,0x01); /* activate: bit 0 */
- isa_pnp_write_data_register(0x31,0x00); /* IO range check: bit 0 */
-
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
-
- /* then the library needs to be updated */
- /* TODO: there should be a sndsb_ call to do this! */
- sb_card->baseio = BASE;
- sb_card->dma8 = DMA8;
- sb_card->dma16 = DMA16;
- sb_card->irq = IRQ;
-
- if (sb_card->irq != -1) {
- old_irq_masked = p8259_is_masked(sb_card->irq);
- old_irq = _dos_getvect(irq2int(sb_card->irq));
- _dos_setvect(irq2int(sb_card->irq),sb_irq);
- p8259_unmask(sb_card->irq);
- }
-
- if (do_stop_start) begin_play();
- }
- return;
- }
- }
- /* -------- Non Plug & Play --------- */
- else if (sb_card->dsp_vmaj == 4) {
- /* SB16 non-pnp can reassign resources when
- writing mixer bytes 0x80, 0x81 */
- conf_item_index_lookup(&sb16_non_pnp[0]/*IRQ*/,sb_card->irq);
- conf_item_index_lookup(&sb16_non_pnp[1]/*DMA*/,sb_card->dma8);
- conf_item_index_lookup(&sb16_non_pnp[2]/*DMA16*/,sb_card->dma16);
- if (conf_sound_card_list("Creative Sound Blaster 16 configuration",sb16_non_pnp,sizeof(sb16_non_pnp)/sizeof(sb16_non_pnp[0]),56)) {
- signed char IRQ = sb16_non_pnp_irq[sb16_non_pnp[0].setting];/*IRQ*/
- signed char DMA8 = sb16_non_pnp_dma[sb16_non_pnp[1].setting];/*DMA*/
- signed char DMA16 = sb16_non_pnp_dma16[sb16_non_pnp[2].setting];/*DMA16*/
- unsigned char do_stop_start = wav_playing,c;
- if (do_stop_start) stop_play();
-
- if (sb_card->irq != -1) {
- _dos_setvect(irq2int(sb_card->irq),old_irq);
- if (old_irq_masked) p8259_mask(sb_card->irq);
- }
-
- if (DMA8 < 0) DMA16 = -1;
- if (DMA8 > 3) DMA8 = -1;
-
- /* as seen on real Creative SB16 hardware:
- the 16-bit DMA channel must be either 5, 6, 7,
- or must match the 8-bit DMA channel. */
- if (DMA16 < 4 && DMA16 >= 0)
- DMA16 = DMA8;
-
- /* apply changes */
- c = 0;
- if (IRQ == 2) c |= 0x01;
- else if (IRQ == 5) c |= 0x02;
- else if (IRQ == 7) c |= 0x04;
- else if (IRQ == 10) c |= 0x08;
- else IRQ = -1;
- sndsb_write_mixer(sb_card,0x80,c);
-
- c = 0;
- if (DMA8 == 0) c |= 0x01;
- else if (DMA8 == 1) c |= 0x02;
- else if (DMA8 == 3) c |= 0x08;
- else DMA8 = -1;
-
- /* NTS: From the Creative programming guide:
- * "DSP version 4.xx also supports the transfer of 16-bit sound data through
- * 8-bit DMA channel. To make this possible, set all 16-bit DMA channel bits
- * to 0 leaving only 8-bit DMA channel set"
- *
- * Also as far as I can tell there's really no way to assign
- * an 8-bit DMA without either assigning to 5,6,7 or matching
- * the 8-bit DMA channel */
- if (DMA16 == 5) c |= 0x20;
- else if (DMA16 == 6) c |= 0x40;
- else if (DMA16 == 7) c |= 0x80;
- else DMA16 = DMA8;
- sndsb_write_mixer(sb_card,0x81,c);
-
- /* then the library needs to be updated */
- /* TODO: there should be a sndsb_ call to do this! */
- sb_card->dma8 = DMA8;
- sb_card->dma16 = DMA16;
- sb_card->irq = IRQ;
-
- if (sb_card->irq != -1) {
- old_irq_masked = p8259_is_masked(sb_card->irq);
- old_irq = _dos_getvect(irq2int(sb_card->irq));
- _dos_setvect(irq2int(sb_card->irq),sb_irq);
- p8259_unmask(sb_card->irq);
- }
-
- if (do_stop_start) begin_play();
- }
- return;
- }
- else if (sb_card->is_gallant_sc6600) {
- /* the Gallant SC-6600 has it's own weird "plug & play"
- configuration method, although the base I/O is not
- software configurable */
- conf_item_index_lookup(&sc6600[0]/*IRQ*/,sb_card->irq);
- conf_item_index_lookup(&sc6600[1]/*DMA*/,sb_card->dma8);
- if (conf_sound_card_list("SC-4000 configuration",sc6600,sizeof(sc6600)/sizeof(sc6600[0]),56)) {
- signed char IRQ = sc6600_irq[sc6600[0].setting];/*IRQ*/
- signed char DMA8 = sc6600_dma[sc6600[1].setting];/*DMA*/
- unsigned char do_stop_start = wav_playing;
- unsigned char irq_i=0,dma_i=0,cfg=0;
-
- if (do_stop_start) stop_play();
-
- if (sb_card->irq != -1) {
- _dos_setvect(irq2int(sb_card->irq),old_irq);
- if (old_irq_masked) p8259_mask(sb_card->irq);
- }
-
- if (DMA8 > 3) DMA8 = -1;
-
- while (dma_i < 3 && gallant_sc6600_map_to_dma[dma_i] != DMA8) dma_i++;
- while (irq_i < 7 && gallant_sc6600_map_to_irq[irq_i] != IRQ) irq_i++;
-
- cfg &= ~(3 << 0);
- cfg |= dma_i << 0;
- cfg &= ~(7 << 3);
- cfg |= irq_i << 3;
-
- sndsb_reset_dsp(sb_card);
-
- /* write config byte */
- sndsb_write_dsp(sb_card,0x50);
- sndsb_write_dsp(sb_card,cfg);
- sndsb_write_dsp(sb_card,0xF2);
-
- sndsb_write_dsp(sb_card,0x50);
- sndsb_write_dsp(sb_card,cfg);
- sndsb_write_dsp(sb_card,0xE6);
-
- sndsb_reset_dsp(sb_card);
-
- sndsb_write_dsp(sb_card,0x50);
- sndsb_write_dsp(sb_card,cfg);
- sndsb_write_dsp(sb_card,0xF2);
-
- sndsb_write_dsp(sb_card,0x50);
- sndsb_write_dsp(sb_card,cfg);
- sndsb_write_dsp(sb_card,0xE6);
-
- sndsb_reset_dsp(sb_card);
-
- /* then the library needs to be updated */
- /* TODO: there should be a sndsb_ call to do this! */
- sb_card->dma8 = DMA8;
- sb_card->dma16 = DMA8;
- sb_card->irq = IRQ;
-
- if (sb_card->irq != -1) {
- old_irq_masked = p8259_is_masked(sb_card->irq);
- old_irq = _dos_getvect(irq2int(sb_card->irq));
- _dos_setvect(irq2int(sb_card->irq),sb_irq);
- p8259_unmask(sb_card->irq);
- }
-
- if (do_stop_start) begin_play();
- }
- return;
- }
-
- {
- int c;
- struct vga_msg_box box;
- vga_msg_box_create(&box,"Your sound card is not software configurable,\nor does not have any method I know of to do so.",0,0);
- do {
- ui_anim(0);
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
- }
- else {
- c = -1;
- }
- } while (!(c == 13 || c == 10));
- vga_msg_box_destroy(&box);
- }
-}
-
-void choose_sound_card() {
- int c,rows=3+1+SNDSB_MAX_CARDS,cols=70,sel=0,i;
- unsigned char wp = wav_playing;
- struct sndsb_ctx *card;
- struct vga_msg_box box;
-
- if (sb_card->is_gallant_sc6600 || sb_card->mega_em || sb_card->sbos)
- rows++;
-
- for (i=0;i < SNDSB_MAX_CARDS;i++) {
- card = &sndsb_card[i];
- if (card == sb_card) sel = i;
- }
-
- vga_msg_box_create(&box,"",rows,cols); /* 3 rows 70 cols */
- draw_device_info(sb_card,box.x+2,box.y+1+rows-3,cols,3);
- for (i=0;i < SNDSB_MAX_CARDS;i++)
- draw_sound_card_choice(box.x+2,box.y+1+i,cols,&sndsb_card[i],i == sel);
-
- card = NULL;
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27) {
- card = NULL;
- break;
- }
- else if (c == 13) {
- card = &sndsb_card[sel];
- if (card->baseio != 0) break;
- card = NULL;
- }
- else if (c == 0x4800) {
- draw_sound_card_choice(box.x+2,box.y+1+sel,cols,&sndsb_card[sel],0);
- if (sel == 0) sel = SNDSB_MAX_CARDS - 1;
- else sel--;
- draw_sound_card_choice(box.x+2,box.y+1+sel,cols,&sndsb_card[sel],1);
- draw_device_info(&sndsb_card[sel],box.x+2,box.y+1+rows-3,cols,3);
- }
- else if (c == 0x5000) {
- draw_sound_card_choice(box.x+2,box.y+1+sel,cols,&sndsb_card[sel],0);
- if (++sel == SNDSB_MAX_CARDS) sel = 0;
- draw_sound_card_choice(box.x+2,box.y+1+sel,cols,&sndsb_card[sel],1);
- draw_device_info(&sndsb_card[sel],box.x+2,box.y+1+rows-3,cols,3);
- }
- }
- }
-
- if (card != NULL) {
- stop_play();
- if (sb_card->irq != -1) {
- _dos_setvect(irq2int(sb_card->irq),old_irq);
- if (old_irq_masked) p8259_mask(sb_card->irq);
- }
-
- sb_card = card;
- sndsb_assign_dma_buffer(sb_card,sb_dma);
- if (sb_card->irq != -1) {
- old_irq_masked = p8259_is_masked(sb_card->irq);
- old_irq = _dos_getvect(irq2int(sb_card->irq));
- _dos_setvect(irq2int(sb_card->irq),sb_irq);
- p8259_unmask(sb_card->irq);
- }
-
- if (wp) begin_play();
- }
-
- vga_msg_box_destroy(&box);
-}
-#endif
-
-#ifdef INCLUDE_FX
-void fx_reset() {
- fx_volume = 256;
- fx_echo_delay = 0;
- fx_echo_free();
- if (wav_playing) {
- stop_play();
- begin_play();
- }
-}
-
-void fx_vol_echo() {
- struct vga_msg_box box;
- unsigned char redraw=1;
- int c;
-
- vga_msg_box_create(&box,
- "Echo effect\n"
- "Use +/- to adjust, R to reset to off",3,0);
- while (1) {
- if (redraw) {
- vga_moveto(box.x+2,box.y+4);
- vga_write_color(0x1E);
- if (fx_echo_delay == 0)
- vga_write("(off) ");
- else {
- sprintf(temp_str,"%u ",fx_echo_delay);
- vga_write(temp_str);
- }
- redraw=0;
- }
-
- ui_anim(0);
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27 || c == 13)
- break;
- else if (c == 'r') {
- fx_echo_delay = 0;
- redraw = 1;
- }
- else if (c == '-') {
- if (fx_echo_delay > 0) {
- fx_echo_delay--;
- redraw = 1;
- }
- }
- else if (c == '_') {
- if (fx_echo_delay > 64) {
- fx_echo_delay -= 64;
- redraw = 1;
- }
- else if (fx_echo_delay > 0) {
- fx_echo_delay = 0;
- redraw = 1;
- }
- }
- else if (c == '=') {
- fx_echo_delay++;
- redraw = 1;
- }
- else if (c == '+') {
- fx_echo_delay += 128;
- redraw = 1;
- }
- }
- }
- vga_msg_box_destroy(&box);
-}
-
-void fx_vol_dialog() {
- struct vga_msg_box box;
- unsigned char redraw=1;
- int c;
-
- vga_msg_box_create(&box,
- "Volume effect\n"
- "Use +/- to adjust, R to reset to 100%",3,0);
- while (1) {
- if (redraw) {
- unsigned long i = ((unsigned long)fx_volume * 1000UL) / 256UL;
- vga_moveto(box.x+2,box.y+4);
- vga_write_color(0x1E);
- sprintf(temp_str,"%u.%03u %s ",
- (unsigned int)(i / 1000UL),
- (unsigned int)(i % 1000UL),
- (fx_volume == 256 ? "(disable)" : " "));
- vga_write(temp_str);
- redraw=0;
- }
-
- ui_anim(0);
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27 || c == 13)
- break;
- else if (c == 'r') {
- fx_volume = 256;
- redraw = 1;
- }
- else if (c == '-') {
- if (fx_volume > 0) {
- fx_volume--;
- redraw = 1;
- }
- }
- else if (c == '_') {
- if (fx_volume > 32) {
- fx_volume -= 32;
- redraw = 1;
- }
- else if (fx_volume > 0) {
- fx_volume = 0;
- redraw = 1;
- }
- }
- else if (c == '=') {
- fx_volume++;
- redraw = 1;
- }
- else if (c == '+') {
- fx_volume += 64;
- redraw = 1;
- }
- }
- }
- vga_msg_box_destroy(&box);
-}
-#endif
-
-int main(int argc,char **argv) {
- unsigned char sb_irq_pcount = 0;
- int i,loop,redraw,bkgndredraw,cc;
- const struct vga_menu_item *mitem = NULL;
- unsigned char assume_dma = 0;
- uint32_t buffer_limit = 0;
- int disable_probe = 0;
- int disable_pnp = 0;
- int disable_env = 0;
- int force_ddac = 0;
- VGA_ALPHA_PTR vga;
- int autoplay = 0;
- int sc_idx = -1;
-
- printf("Sound Blaster test program\n");
- for (i=1;i < argc;) {
- char *a = argv[i++];
-
- if (*a == '-' || *a == '/') {
- unsigned char m = *a++;
- while (*a == m) a++;
-
- if (!strcmp(a,"h") || !strcmp(a,"help")) {
- help();
- return 1;
- }
- else if (!strcmp(a,"ex-ess")) {
- sndsb_probe_options.experimental_ess = 1;
- }
- else if (!strcmp(a,"noess")) {
- sndsb_probe_options.disable_ess_extensions = 1;
- }
- else if (!strcmp(a,"adma")) {
- assume_dma = 1;
- }
- else if (!strcmp(a,"sbalias:dsp")) {
- sndsb_probe_options.use_dsp_alias = 1;
- }
- else if (!strcmp(a,"noidle")) {
- dont_sb_idle = 1;
- }
- else if (!strcmp(a,"nochain")) {
- dont_chain_irq = 1;
- }
- else if (!strcmp(a,"16k")) {
- buffer_limit = 16UL * 1024UL;
- }
- else if (!strcmp(a,"8k")) {
- buffer_limit = 8UL * 1024UL;
- }
- else if (!strcmp(a,"4k")) {
- buffer_limit = 4UL * 1024UL;
- }
- else if (!strcmp(a,"-nmi")) {
-#if TARGET_MSDOS == 32
- sndsb_nmi_32_hook = 0;
-#endif
- }
- else if (!strcmp(a,"+nmi")) {
-#if TARGET_MSDOS == 32
- sndsb_nmi_32_hook = 1;
-#endif
- }
- else if (!strcmp(a,"nopnp")) {
- disable_pnp = 1;
- }
- else if (!strncmp(a,"wav=",4)) {
- a += 4;
- strcpy(wav_file,a);
- }
- else if (!strcmp(a,"play")) {
- autoplay = 1;
- }
- else if (!strncmp(a,"sc=",3)) {
- a += 3;
- sc_idx = strtol(a,NULL,0);
- }
- else if (!strcmp(a,"noprobe")) {
- disable_probe = 1;
- }
- else if (!strcmp(a,"noenv")) {
- disable_env = 1;
- }
- else if (!strcmp(a,"ddac")) {
- force_ddac = 1;
- }
- else if (!strcmp(a,"nomirqp")) {
- sndsb_probe_options.disable_manual_irq_probing = 1;
- }
- else if (!strcmp(a,"noairqp")) {
- sndsb_probe_options.disable_alt_irq_probing = 1;
- }
- else if (!strcmp(a,"nosb16cfg")) {
- sndsb_probe_options.disable_sb16_read_config_byte = 1;
- }
- else if (!strcmp(a,"nodmap")) {
- sndsb_probe_options.disable_manual_dma_probing = 1;
- }
- else if (!strcmp(a,"nohdmap")) {
- sndsb_probe_options.disable_manual_high_dma_probing = 1;
- }
- else if (!strcmp(a,"nowinvxd")) {
- sndsb_probe_options.disable_windows_vxd_checks = 1;
- }
- else {
- help();
- return 1;
- }
- }
- }
-
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
-
- /* TODO: Make sure this code still runs reliably without DMA (Direct DAC etc) if DMA not available! */
- if (!probe_8237())
- printf("WARNING: Cannot init 8237 DMA\n");
-
- if (assume_dma)
- d8237_flags |= D8237_DMA_PRIMARY | D8237_DMA_SECONDARY;
-
- printf("DMA available: 0-3=%s 4-7=%s\n",
- d8237_flags&D8237_DMA_PRIMARY?"yes":"no",
- d8237_flags&D8237_DMA_SECONDARY?"yes":"no");
-
- if (!probe_8259()) {
- printf("Cannot init 8259 PIC\n");
- return 1;
- }
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!init_sndsb()) {
- printf("Cannot init library\n");
- return 1;
- }
-#if TARGET_MSDOS == 32
- if (sndsb_nmi_32_hook > 0) /* it means the NMI hook is taken */
- printf("Sound Blaster NMI hook/reflection active\n");
-
- if (gravis_mega_em_detect(&megaem_info)) {
- /* let the user know we're a 32-bit program and MEGA-EM's emulation
- * won't work with 32-bit DOS programs */
- printf("WARNING: Gravis MEGA-EM detected. Sound Blaster emulation doesn't work\n");
- printf(" with 32-bit protected mode programs (like myself). If you want\n");
- printf(" to test it's Sound Blaster emulation use the 16-bit real mode\n");
- printf(" builds instead.\n");
- }
- if (gravis_sbos_detect() >= 0) {
- printf("WARNING: Gravis SBOS emulation is not 100%% compatible with 32-bit builds.\n");
- printf(" It may work for awhile, but eventually the simulated IRQ will go\n");
- printf(" missing and playback will stall. Please consider using the 16-bit\n");
- printf(" real-mode builds instead. When a workaround is possible, it will\n");
- printf(" be implemented and this warning will be removed.\n");
- }
-#elif TARGET_MSDOS == 16
-# if defined(__LARGE__)
- if (gravis_sbos_detect() >= 0) {
- printf("WARNING: 16-bit large model builds of the SNDSB program have a known, but not\n");
- printf(" yet understood incompatability with Gravis SBOS emulation. Use the\n");
- printf(" dos86s, dos86m, or dos86c builds.\n");
- }
-# endif
-#endif
-#ifdef ISAPNP
- if (!init_isa_pnp_bios()) {
- printf("Cannot init ISA PnP\n");
- return 1;
- }
- if (!disable_pnp) {
- if (find_isa_pnp_bios()) {
- int ret;
- char tmp[192];
- unsigned int j,nodesize=0;
- const char *whatis = NULL;
- unsigned char csn,node=0,numnodes=0xFF,data[192];
-
- memset(data,0,sizeof(data));
- if (isa_pnp_bios_get_pnp_isa_cfg(data) == 0) {
- struct isapnp_pnp_isa_cfg *nfo = (struct isapnp_pnp_isa_cfg*)data;
- isapnp_probe_next_csn = nfo->total_csn;
- isapnp_read_data = nfo->isa_pnp_port;
- }
- else {
- printf(" ISA PnP BIOS failed to return configuration info\n");
- }
-
- /* enumerate device nodes reported by the BIOS */
- if (isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize) == 0 && numnodes != 0xFF && nodesize <= sizeof(devnode_raw)) {
- for (node=0;node != 0xFF;) {
- struct isa_pnp_device_node far *devn;
- unsigned char this_node;
-
- /* apparently, start with 0. call updates node to
- * next node number, or 0xFF to signify end */
- this_node = node;
- if (isa_pnp_bios_get_sysdev_node(&node,devnode_raw,ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW) != 0) break;
-
- devn = (struct isa_pnp_device_node far*)devnode_raw;
- if (isa_pnp_is_sound_blaster_compatible_id(devn->product_id,&whatis)) {
- isa_pnp_product_id_to_str(tmp,devn->product_id);
- if ((ret = sndsb_try_isa_pnp_bios(devn->product_id,this_node,devn,sizeof(devnode_raw))) <= 0)
- printf("ISA PnP BIOS: error %d for %s '%s'\n",ret,tmp,whatis);
- else
- printf("ISA PnP BIOS: found %s '%s'\n",tmp,whatis);
- }
- }
- }
-
- /* enumerate the ISA bus directly */
- if (isapnp_read_data != 0) {
- printf("Scanning ISA PnP devices...\n");
- for (csn=1;csn < 255;csn++) {
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
-
- isa_pnp_write_address(0x06); /* CSN */
- if (isa_pnp_read_data() == csn) {
- /* apparently doing this lets us read back the serial and vendor ID in addition to resource data */
- /* if we don't, then we only read back the resource data */
- isa_pnp_init_key();
- isa_pnp_wake_csn(csn);
-
- for (j=0;j < 9;j++) data[j] = isa_pnp_read_config();
-
- if (isa_pnp_is_sound_blaster_compatible_id(*((uint32_t*)data),&whatis)) {
- isa_pnp_product_id_to_str(tmp,*((uint32_t*)data));
- if ((ret = sndsb_try_isa_pnp(*((uint32_t*)data),csn)) <= 0)
- printf("ISA PnP: error %d for %s '%s'\n",ret,tmp,whatis);
- else
- printf("ISA PnP: found %s '%s'\n",tmp,whatis);
- }
- }
-
- /* return back to "wait for key" state */
- isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */
- }
- }
- }
- }
-#endif
- /* Non-plug & play scan */
- if (!disable_env && sndsb_try_blaster_var() != NULL) {
- printf("Created card ent. for BLASTER variable. IO=%X MPU=%X DMA=%d DMA16=%d IRQ=%d\n",
- sndsb_card_blaster->baseio,
- sndsb_card_blaster->mpuio,
- sndsb_card_blaster->dma8,
- sndsb_card_blaster->dma16,
- sndsb_card_blaster->irq);
- if (!sndsb_init_card(sndsb_card_blaster)) {
- printf("Nope, didn't work\n");
- sndsb_free_card(sndsb_card_blaster);
- }
- }
- if (!disable_probe) {
- if (sndsb_try_base(0x220))
- printf("Also found one at 0x220\n");
- if (sndsb_try_base(0x240))
- printf("Also found one at 0x240\n");
- }
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- /* There is a known issue with NTVDM.EXE Sound Blaster emulation under Windows XP. Not only
- * do we get stuttery audio, but at some random point (1-5 minutes of continuous playback)
- * the DOS VM crashes up for some unknown reason (VM is hung). */
- if (windows_mode == WINDOWS_NT) {
- struct sndsb_ctx *cx = sndsb_index_to_ctx(0);
- if (cx != NULL && cx->baseio != 0) {
- if (cx->windows_emulation && cx->windows_xp_ntvdm) {
- printf("WARNING: Windows XP/Vista/7 NTVDM.EXE emulation detected.\n");
- printf(" There is a known issue with NTVDM.EXE emulation that causes\n");
- printf(" playback to stutter, and if left running long enough, causes\n");
- printf(" this program to lock up and freeze.\n");
- printf(" If you must use this program under Windows XP, please consider\n");
- printf(" installing VDMSOUND and running this program within the VDMSOUND\n");
- printf(" environment.\n");
- }
- }
- }
-#endif
-
- if (sc_idx < 0) {
- int count=0;
- for (i=0;i < SNDSB_MAX_CARDS;i++) {
- struct sndsb_ctx *cx = sndsb_index_to_ctx(i);
- if (sndsb_card[i].baseio == 0 && sndsb_card[i].mpuio == 0) continue;
- printf(" [%u] base=%X mpu=%X dma=%d dma16=%d irq=%d DSP=%u 1.XXAI=%u\n",
- i+1,cx->baseio,cx->mpuio,cx->dma8,cx->dma16,cx->irq,cx->dsp_ok,cx->dsp_autoinit_dma);
- printf(" MIXER=%u[%s] DSPv=%u.%u SC6600=%u OPL=%X GAME=%X AWE=%X\n",
- cx->mixer_ok,sndsb_mixer_chip_str(cx->mixer_chip),
- (unsigned int)cx->dsp_vmaj,(unsigned int)cx->dsp_vmin,
- cx->is_gallant_sc6600,cx->oplio,cx->gameio,cx->aweio);
- printf(" ESS=%u[%s] use=%u wss=%X OPL3SAx=%X\n",
- cx->ess_chipset,sndsb_ess_chipset_str(cx->ess_chipset),
- cx->ess_extensions,cx->wssio,cx->opl3sax_controlio);
-#ifdef ISAPNP
- if (cx->pnp_name != NULL) {
- isa_pnp_product_id_to_str(temp_str,cx->pnp_id);
- printf(" ISA PnP[%u]: %s %s\n",cx->pnp_csn,temp_str,cx->pnp_name);
- }
-#endif
- printf(" '%s'\n",cx->dsp_copyright);
- count++;
- }
- if (count == 0) {
- printf("No cards found.\n");
- return 1;
- }
- printf("-----------\n");
- printf("Select the card you wish to test: "); fflush(stdout);
- i = getch();
- printf("\n");
- if (i == 27) return 0;
- if (i == 13 || i == 10) i = '1';
- sc_idx = i - '0';
- }
-
- if (sc_idx < 1 || sc_idx > SNDSB_MAX_CARDS) {
- printf("Sound card index out of range\n");
- return 1;
- }
-
- sb_card = &sndsb_card[sc_idx-1];
- if (sb_card->baseio == 0) {
- printf("No such card\n");
- return 1;
- }
-
- printf("Allocating sound buffer..."); fflush(stdout);
- {
- uint32_t choice = sndsb_recommended_dma_buffer_size(sb_card,buffer_limit);
-
- do {
- sb_dma = dma_8237_alloc_buffer(choice);
- if (sb_dma == NULL) choice -= 4096UL;
- } while (sb_dma == NULL && choice > 4096UL);
-
- if (sb_dma == NULL) {
- printf(" failed\n");
- return 0;
- }
- }
-
- i = int10_getmode();
- if (i != 3) int10_setmode(3);
-
- /* hook IRQ 0 */
- irq_0_count = 0;
- irq_0_adv = 1;
- irq_0_max = 1;
- old_irq_0 = _dos_getvect(irq2int(0));
- _dos_setvect(irq2int(0),irq_0);
- p8259_unmask(0);
-
- if (sb_card->irq != -1) {
- old_irq_masked = p8259_is_masked(sb_card->irq);
- old_irq = _dos_getvect(irq2int(sb_card->irq));
- _dos_setvect(irq2int(sb_card->irq),sb_irq);
- p8259_unmask(sb_card->irq);
- }
-
- vga_write_color(0x07);
- vga_clear();
-
- loop=1;
- redraw=1;
- wav_record=0;
- bkgndredraw=1;
- vga_menu_bar.bar = main_menu_bar;
- vga_menu_bar.sel = -1;
- vga_menu_bar.row = 3;
- vga_menu_idle = my_vga_menu_idle;
- if (force_ddac) sb_card->dsp_play_method = SNDSB_DSPOUTMETHOD_DIRECT;
- reduced_irq_interval=(sb_card->dsp_play_method == SNDSB_DSPOUTMETHOD_1xx);
- update_cfg();
-
- if (!sndsb_assign_dma_buffer(sb_card,sb_dma)) {
- printf("Cannot assign DMA buffer\n");
- return 1;
- }
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- /* please let me know if the user attempts to close my DOS Box */
- if (dos_close_awareness_available()) {
- int d;
-
- printf("Windows is running, attempting to enable Windows close-awareness\n");
-
- /* counter-intuitive in typical Microsoft fashion.
- * When they say "enable/disable" the close command what they apparently mean
- * is that "enabling" it triggers immediate closing when the user clicks the close
- * button, and "disabling" means it queues the event and hands it to the DOS
- * program as a request to shutdown. If their documentation would simply
- * explain that, I would not have wasted 30 minutes wondering why Windows 9x
- * would immediately complain about not being able to close this program.
- *
- * Sadly, Windows XP, despite being the "merging of Windows NT and 98 codebases"
- * doesn't provide us with close-awareness. */
- if ((d=dos_close_awareness_enable(0)) != 0)
- printf("Warning, cannot enable Windows 'close-awareness' ret=0x%X\n",d);
- else
- printf("Close-awareness enabled\n");
- }
-#endif
-
- if (wav_file[0] != 0) open_wav();
- if (autoplay) begin_play();
- while (loop) {
- if ((mitem = vga_menu_bar_keymon()) != NULL) {
- /* act on it */
- if (mitem == &main_menu_file_quit) {
- if (confirm_quit()) {
- loop = 0;
- break;
- }
- }
- else if (mitem == &main_menu_file_set) {
- prompt_play_wav(0);
- bkgndredraw = 1;
- wav_record = 0;
- redraw = 1;
- }
- else if (mitem == &main_menu_playback_play) {
- if (wav_record) {
- stop_play();
- wav_record = 0;
- }
- if (!wav_playing) {
- begin_play();
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_playback_record) {
- if (!wav_record) {
- stop_play();
- wav_record = 1;
- }
- if (!wav_playing) {
- begin_play();
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_playback_stop) {
- if (wav_playing) {
- stop_play();
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_device_dsp_reset) {
- struct vga_msg_box box;
- vga_msg_box_create(&box,"Resetting DSP...",0,0);
- stop_play();
- sndsb_reset_dsp(sb_card);
- t8254_wait(t8254_us2ticks(1000000));
- vga_msg_box_destroy(&box);
- }
- else if (mitem == &main_menu_device_mixer_reset) {
- struct vga_msg_box box;
- vga_msg_box_create(&box,"Resetting mixer...",0,0);
- sndsb_reset_mixer(sb_card);
- t8254_wait(t8254_us2ticks(1000000));
- vga_msg_box_destroy(&box);
- }
- else if (mitem == &main_menu_help_about) {
- struct vga_msg_box box;
- vga_msg_box_create(&box,"Sound Blaster test program v1.1 for DOS\n\n(C) 2008-2014 Jonathan Campbell\nALL RIGHTS RESERVED\n"
-#if TARGET_MSDOS == 32
- "32-bit protected mode version"
-#elif defined(__LARGE__)
- "16-bit real mode (large model) version"
-#elif defined(__MEDIUM__)
- "16-bit real mode (medium model) version"
-#elif defined(__COMPACT__)
- "16-bit real mode (compact model) version"
-#else
- "16-bit real mode (small model) version"
-#endif
- ,0,0);
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) break;
- }
- }
- vga_msg_box_destroy(&box);
- }
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- else if (mitem == &main_menu_help_dsp_modes) {
- int quit = 0;
- struct vga_msg_box box;
-
- vga_msg_box_create(&box,
- "Explanation of DSP modes:\n"
- "\n"
- "4.xx Sound Blaster 16 or compatible DSP operation. 16-bit audio.\n"
- "\n"
- "3.xx Sound Blaster Pro or compatible. Most clones emulate this card.\n"
- " Creative SB16 cards do not replicate Sound Blaster Pro stereo.\n"
- "\n"
- "2.01 Sound Blaster 2.01 or compatible with auto-init DMA and\n"
- " high-speed DAC playback modes up to 44100Hz.\n"
- "\n"
- "2.00 Sound Blaster 2.0 or compatible with auto-init DMA.\n"
- "\n"
- "1.xx Original Sound Blaster or compatible DSP operation.\n"
- "\n"
- "Direct DSP command 0x10 (Direct DAC output) and system timer.\n"
- " If DMA is not available, this is your only option. Emulators,\n"
- " clones, some motherboard & SB16 combos have problems with it.\n"
- "\n"
- "Detailed explanations are available in README.TXT"
- ,0,0);
- while (!quit) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) {
- quit = (i == 27);
- break;
- }
- }
- }
- vga_msg_box_destroy(&box);
-
- vga_msg_box_create(&box,
- "Additional playback modes:\n"
- "\n"
- "Flip sign Flip sign bit before sending to audio, and instruct SB16 DSP\n"
- " to play nonstandard format. Clones may produce loud static.\n"
- "\n"
- "ADPCM Convert audio to Sound Blaster ADPCM format and instruct DSP\n"
- " to play it. Clones generally do not support this.\n"
- "\n"
- "Auto-init DSP 2.01 and higher support auto-init ADPCM playback. Clones\n"
- "ADPCM definitely do not support this.\n"
- "\n"
- "ADPCM reset On actual Creative SB hardware the DSP resets the ADPCM step\n"
- "per interval size per block. DOSBox, emulators, do not reset ADPCM state.\n"
- "\n"
- "Goldplay A semi-popular music tracker library, SB support is hacky.\n"
- " This program can use the same technique for testing purposes\n"
- "\n"
- "Detailed explanations are available in README.TXT"
- ,0,0);
- while (!quit) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) {
- quit = (i == 27);
- break;
- }
- }
- }
- vga_msg_box_destroy(&box);
-
- vga_msg_box_create(&box,
- "Additional things you can play with:\n"
- "\n"
- "IRQ interval ..... DSP block size to play/record with.\n"
- "DMA autoinit ..... Use/don't use auto-init on the DMA controller side.\n"
- "DSP playback ..... Whether to use auto-init or single-cycle DSP commands.\n"
- "Force hispeed .... If set, always use hispeed DSP playback (SB 2.0 and Pro).\n"
- "\n"
- "DSP 4.xx autoinit FIFO . (SB16) use the FIFO for auto-init DSP 4.xx.\n"
- "DSP 4.xx single FIFO ... (SB16) use the FIFO for single cycle DSP 4.xx.\n"
- "DSP nag mode ........... Test 'nagging' the DSP, Crystal Dream style.\n"
- " Has no effect unless DSP in single-cycle mode.\n"
- "Poll ack when no IRQ ... If not assigned an IRQ, use polling of the status\n"
- " port to prevent halting on SB16.\n"
- "DSP alias port ......... Use alias port 22Dh instead of 22Ch.\n"
- "Backwards .............. Play file backwards by using DMA decrement mode.\n"
- "\n"
- "Detailed explanations are available in README.TXT"
- ,0,0);
- while (!quit) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) {
- quit = (i == 27);
- break;
- }
- }
- }
- vga_msg_box_destroy(&box);
- }
-#endif
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- else if (mitem == &main_menu_playback_dsp4_fifo_autoinit) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->dsp_4xx_fifo_autoinit = !sb_card->dsp_4xx_fifo_autoinit;
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_device_dsp_alias) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- change_alias_menu();
- if (wp) begin_play();
- bkgndredraw = 1;
- redraw = 1;
- }
- else if (mitem == &main_menu_playback_dsp_poll_ack_no_irq) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->poll_ack_when_no_irq = !sb_card->poll_ack_when_no_irq;
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_dsp_nag_mode) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- if (sb_card->dsp_nag_mode && sb_card->dsp_nag_hispeed) {
- sb_card->dsp_nag_mode = sb_card->dsp_nag_hispeed = 0;
- }
- else if (sb_card->dsp_nag_mode) {
- sb_card->dsp_nag_mode = sb_card->dsp_nag_hispeed = 1;
- }
- else {
- sb_card->dsp_nag_hispeed = 0;
- sb_card->dsp_nag_mode = 1;
- }
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_dsp4_fifo_single) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->dsp_4xx_fifo_single_cycle = !sb_card->dsp_4xx_fifo_single_cycle;
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_force_hispeed) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->force_hispeed = !sb_card->force_hispeed;
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_flip_sign) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->audio_data_flipped_sign = !sb_card->audio_data_flipped_sign;
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
-#endif
- else if (mitem == &main_menu_playback_goldplay) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->goldplay_mode = !sb_card->goldplay_mode;
-#if TARGET_MSDOS == 32
- if (!irq_0_had_warned && sb_card->goldplay_mode) {
- /* NOTE TO SELF: It can overwhelm the UI in DOSBox too, but DOSBox seems able to
- recover if you manage to hit CTRL+F12 to speed up the CPU cycles in the virtual machine.
- On real hardware, even with the recovery method the machine remains hung :( */
- if (confirm_yes_no_dialog(dos32_irq_0_warning))
- irq_0_had_warned = 1;
- else
- sb_card->goldplay_mode = 0;
- }
-#endif
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_goldplay_mode) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- if (++goldplay_samplerate_choice > GOLDRATE_MAX)
- goldplay_samplerate_choice = GOLDRATE_MATCH;
- update_cfg();
- ui_anim(1);
- if (wp) begin_play();
- }
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- else if (mitem == &main_menu_windows_fullscreen) {
- /* NTS: Does not seem to work under Windows XP */
- if (windows_mode == WINDOWS_ENHANCED || windows_mode == WINDOWS_STANDARD) {
- __asm {
- mov ax,0x168B
- xor bx,bx
- int 0x2F
- }
- }
- else {
- struct vga_msg_box box;
-
- vga_msg_box_create(&box,
- windows_mode == WINDOWS_NONE ?
- "Windows is not running" :
- "Windows NT not supported"
- ,0,0);
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) break;
- }
- }
- vga_msg_box_destroy(&box);
- }
- }
- else if (mitem == &main_menu_playback_noreset_adpcm) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- adpcm_do_reset_interval = !adpcm_do_reset_interval;
- update_cfg();
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_timer_clamp) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sample_rate_timer_clamp = !sample_rate_timer_clamp;
- update_cfg();
- if (wp) begin_play();
- }
-#endif
- else if (mitem == &main_menu_playback_dsp_autoinit_dma) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->dsp_autoinit_dma = !sb_card->dsp_autoinit_dma;
- update_cfg();
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_dsp_autoinit_command) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->dsp_autoinit_command = !sb_card->dsp_autoinit_command;
- update_cfg();
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_reduced_irq) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- if (++reduced_irq_interval >= 3) reduced_irq_interval = -1;
- update_cfg();
- if (wp) begin_play();
- }
- else if (mitem == &main_menu_playback_params) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- change_param_menu();
- if (wp) begin_play();
- bkgndredraw = 1;
- redraw = 1;
- }
- else if (mitem == &main_menu_playback_autoinit_adpcm) {
- unsigned char wp = wav_playing;
- if (do_adpcm_ai_warning) {
- if (adpcm_warning_prompt()) {
- do_adpcm_ai_warning = 0;
- if (wp) stop_play();
- sb_card->enable_adpcm_autoinit ^= 1;
- if (wp) begin_play();
- }
- }
- else {
- if (wp) stop_play();
- sb_card->enable_adpcm_autoinit ^= 1;
- if (wp) begin_play();
- }
- }
- else if (mitem == &main_menu_device_trigger_irq) {
- unsigned char wp = wav_playing;
- unsigned int patience=1000;
- unsigned char pirqc;
- if (wp) stop_play();
- pirqc = sb_irq_count;
- sndsb_write_dsp(sb_card,0xF2);
-/* FIX: Wait for the IRQ to actually fire. Starting playback after sending
- the command also creates an IRQ storm that can crash the machine. */
- do {
- if (--patience == 0) break;
- t8254_wait(t8254_us2ticks(1000));
- } while (sb_irq_count == pirqc);
- if (wp) begin_play();
- }
-#ifdef SB_MIXER
- else if (mitem == &main_menu_device_mixer_controls) {
- play_with_mixer();
- bkgndredraw = 1;
- redraw = 1;
- }
- else if (mitem == &main_menu_device_ess_controls) {
- play_with_ess();
- bkgndredraw = 1;
- redraw = 1;
- }
-#endif
-#ifdef CARD_INFO_AND_CHOOSER
- else if (mitem == &main_menu_device_info) {
- show_device_info();
- }
- else if (mitem == &main_menu_device_choose_sound_card) {
- choose_sound_card();
- }
-#endif
-#ifdef LIVE_CFG
- else if (mitem == &main_menu_device_configure_sound_card) {
- conf_sound_card();
- }
-#endif
-#ifdef INCLUDE_FX
- else if (mitem == &main_menu_effects_reset) {
- fx_reset();
- }
- else if (mitem == &main_menu_effects_vol) {
- fx_vol_dialog();
- }
- else if (mitem == &main_menu_effects_echo) {
- fx_vol_echo();
- }
-#endif
- }
-
- if (sb_irq_count != sb_irq_pcount) {
- sb_irq_pcount = sb_irq_count;
- redraw = 1;
- }
-
- if (redraw || bkgndredraw) {
- if (!wav_playing) update_cfg();
- if (bkgndredraw) {
- for (vga=vga_alpha_ram+(80*2),cc=0;cc < (80*23);cc++) *vga++ = 0x1E00 | 177;
- vga_menu_bar_draw();
- draw_irq_indicator();
- }
- ui_anim(bkgndredraw);
- _cli();
- vga_moveto(0,2);
- vga_write_color(0x1F);
- for (vga=vga_alpha_ram+(80*2),cc=0;cc < 80;cc++) *vga++ = 0x1F20;
- vga_write("File: ");
- vga_write(wav_file);
- vga_write_sync();
- bkgndredraw = 0;
- redraw = 0;
- _sti();
- }
-
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
-
- if (i == 27) {
- if (confirm_quit()) {
- loop = 0;
- break;
- }
- }
- else if (i == '?') {
- if (sb_card->reason_not_supported) {
- struct vga_msg_box box;
-
- vga_msg_box_create(&box,sb_card->reason_not_supported,0,0);
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) break;
- }
- }
- vga_msg_box_destroy(&box);
- }
- }
- else if (i == ' ') {
- if (!wav_record) {
- if (wav_playing) stop_play();
- else begin_play();
- }
- }
- else if (i == 0x4B00) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- wav_position -= wav_sample_rate * 5;
- if ((signed long)wav_position < 0) wav_position = 0;
- if (wp) begin_play();
- bkgndredraw = 1;
- redraw = 1;
- }
- else if (i == 0x4D00) {
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- wav_position += wav_sample_rate * 5;
- if (wp) begin_play();
- bkgndredraw = 1;
- redraw = 1;
- }
- else if (i == 0x4300) { /* F9 */
- unsigned char wp = wav_playing;
- if (wp) stop_play();
- sb_card->backwards ^= 1;
- if (wp) begin_play();
- bkgndredraw = 1;
- redraw = 1;
- }
- else if (i == 0x4200) { /* F8 */
- getch(); /* delibrate pause */
- }
- }
-
-#if !(TARGET_MSDOS == 16 && (defined(__SMALL__) || defined(__COMPACT__))) /* this is too much to cram into a small model EXE */
- /* Windows "close-awareness".
- * If the user attempts to close the DOSBox window, Windows will let us know */
- if (dos_close_awareness_available()) {
- int r = dos_close_awareness_query();
-
- if (r == DOS_CLOSE_AWARENESS_NOT_ACK) {
- /* then ack it, and act as if File -> Quit were selected */
- dos_close_awareness_ack();
-
- if (confirm_quit())
- break;
- else
- dos_close_awareness_cancel();
- }
- else if (r == DOS_CLOSE_AWARENESS_ACKED) {
- /* then we need to exit */
- break;
- }
- }
-#endif
-
- ui_anim(0);
- }
-
- _sti();
- vga_write_sync();
- printf("Stopping playback...\n");
- stop_play();
- printf("Closing WAV...\n");
- close_wav();
- printf("Freeing buffer...\n");
- dma_8237_free_buffer(sb_dma); sb_dma = NULL;
-
- if (sb_card->irq >= 0 && old_irq_masked)
- p8259_mask(sb_card->irq);
-
- printf("Releasing IRQ...\n");
- if (sb_card->irq != -1)
- _dos_setvect(irq2int(sb_card->irq),old_irq);
-
- sndsb_free_card(sb_card);
- free_sndsb(); /* will also de-ref/unhook the NMI reflection */
- _dos_setvect(irq2int(0),old_irq_0);
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_ULTRASND_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = ultrasnd.c
-OBJS = $(SUBDIR)$(HPS)ultrasnd.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-TSRS_EXE = $(SUBDIR)$(HPS)tsrs.exe
-
-$(HW_ULTRASND_LIB): $(OBJS)
- wlib -q -b -c $(HW_ULTRASND_LIB) -+$(SUBDIR)$(HPS)ultrasnd.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_ULTRASND_LIB) .symbolic
-
-exe: $(TEST_EXE) $(TSRS_EXE) .symbolic
-
-$(TEST_EXE): $(HW_ULTRASND_LIB) $(HW_ULTRASND_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(HW_FLATREAL_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8237_LIB) $(HW_8237_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_ULTRASND_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8237_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(TSRS_EXE): $(HW_ULTRASND_LIB) $(HW_ULTRASND_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(HW_FLATREAL_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_8237_LIB) $(HW_8237_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tsrs.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)tsrs.obj $(HW_ULTRASND_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_8237_LIB_WLINK_LIBRARIES) name $(TSRS_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_ULTRASND_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <ctype.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/ultrasnd/ultrasnd.h>
-#include <hw/dos/tgusmega.h>
-#include <hw/dos/tgussbos.h>
-#include <hw/dos/doswin.h>
-
-int main(int argc,char **argv) {
- struct ultrasnd_ctx *u;
- unsigned long ofs,ptr;
- unsigned char FAR *dmaptr;
- int i,j,fd,rd;
- int no_dma=0;
- int die=0;
-
- printf("Gravis Ultrasound test program\n");
- probe_dos();
- detect_windows();
- if (!probe_vga()) {
- printf("Cannot init VGA\n");
- return 1;
- }
- if (!probe_8237()) {
- printf("Cannot init 8237 DMA\n");
- return 1;
- }
- if (!probe_8259()) {
- printf("Cannot init 8259 PIC\n");
- return 1;
- }
- if (!probe_8254()) {
- printf("Cannot init 8254 timer\n");
- return 1;
- }
- if (!init_ultrasnd()) {
- printf("Cannot init library\n");
- return 1;
- }
-
- for (i=1;i < argc;i++) {
- char *s = argv[i];
-
- if (!strcmp(s,"-d"))
- ultrasnd_debug(1);
- else if (!strcmp(s,"-nodma"))
- no_dma = 1;
- }
-
- if (ultrasnd_try_ultrasnd_env() != NULL) {
- printf("ULTRASND environment variable: PORT=0x%03x IRQ=%d,%d DMA=%d,%d\n",
- ultrasnd_env->port,
- ultrasnd_env->irq1,
- ultrasnd_env->irq2,
- ultrasnd_env->dma1,
- ultrasnd_env->dma2);
- if (ultrasnd_probe(ultrasnd_env,0)) {
- printf("Never mind, doesn't work\n");
- ultrasnd_free_card(ultrasnd_env);
- }
- }
-
- if (windows_mode == WINDOWS_NONE) {
- /* FIXME: Windows XP DOS Box: This probing function causes the (virtual) keyboard to stop responding. Why? */
- if (ultrasnd_try_base(0x220))
- printf("Also found one at 0x220\n");
- if (ultrasnd_try_base(0x240))
- printf("Also found one at 0x240\n");
- }
-
- for (i=0;i < MAX_ULTRASND;i++) {
- u = &ultrasnd_card[i];
- if (ultrasnd_card_taken(u)) {
- printf("[%u] RAM=%dKB PORT=0x%03x IRQ=%d,%d DMA=%d,%d 256KB-boundary=%u voices=%u/%uHz\n",
- i+1,
- (int)(u->total_ram >> 10UL),
- u->port,
- u->irq1,
- u->irq2,
- u->dma1,
- u->dma2,
- u->boundary256k,
- u->active_voices,
- u->output_rate);
- }
- }
- printf("Which card to use? "); fflush(stdout);
- i = -1; scanf("%d",&i); i--;
- if (i < 0 || i >= MAX_ULTRASND || !ultrasnd_card_taken(&ultrasnd_card[i])) return 1;
- u = &ultrasnd_card[i];
-
- if (no_dma) {
- printf("Disabling DMA at your request\n");
- u->use_dma = 0;
- }
-
- /* ------------------------------------------------------------------------------------------------------- */
- if (!die) {
- printf("8-bit 11KHz test\n");
-
- /* load something into RAM */
- fd = open("8_11khz.wav",O_RDONLY|O_BINARY);
- if (fd < 0) fd = open("..\\..\\8_11khz.wav",O_RDONLY|O_BINARY);
- if (fd < 0) fd = open("..\\..\\..\\8_11khz.wav",O_RDONLY|O_BINARY);
- if (fd < 0) {
- fprintf(stderr,"Cannot open .WAV\n");
- return 1;
- }
- lseek(fd,44,SEEK_SET);
- ofs=0;
- printf("Loading into DRAM "); fflush(stdout);
- if ((dmaptr = ultrasnd_dram_buffer_alloc(u,4096)) != NULL) {
- printf("phys=0x%08lX ",(unsigned long)(u->dram_xfer_a->phys));
- while ((rd = _dos_xread(fd,dmaptr,4096)) > 0) {
- ultrasnd_send_dram_buffer(u,ofs,rd,ULTRASND_DMA_FLIP_MSB);
- printf("."); fflush(stdout);
- ofs += rd;
- }
- printf("\n");
- /* and then repeat the last sample to avoid click */
- ultrasnd_poke(u,ofs,ultrasnd_peek(u,0));
- ultrasnd_dram_buffer_free(u);
- }
- else {
- printf("ERROR: Cannot alloc DMA transfer DRAM upload\n");
- }
- close(fd);
-
- /* get the audio going */
- ultrasnd_stop_voice(u,0);
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR);
- ultrasnd_set_voice_fc(u,0,ultrasnd_sample_rate_to_fc(u,11025));
- ultrasnd_set_voice_ramp_rate(u,0,0,0);
- ultrasnd_set_voice_ramp_start(u,0,0xF0); /* NTS: You have to set the ramp start/end because it will override your current volume */
- ultrasnd_set_voice_ramp_end(u,0,0xF0);
- ultrasnd_set_voice_volume(u,0,0xFFF0); /* full vol */
- ultrasnd_set_voice_pan(u,0,7); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- ultrasnd_set_voice_ramp_control(u,0,0);
- ultrasnd_set_voice_current(u,0,1);
- ultrasnd_set_voice_start(u,0,1); /* NTS: If 0, the card won't stop and will run into 0xFFFFF and beyond */
- ultrasnd_set_voice_end(u,0,ofs-1);
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR);
- ultrasnd_start_voice(u,0);
-
- /* wait */
- do {
- ptr = ultrasnd_read_voice_current(u,0);
- fprintf(stderr,"\x0D" "ESC to quit, ENTER to move on. 0x%08lx ",ptr); fflush(stderr);
-
- if (kbhit()) {
- i = getch();
- if (i == 27) {
- die = 1;
- break;
- }
- else if (i == 13) {
- break;
- }
- else if (i == 8) {
- ultrasnd_set_voice_mode(u,0,ultrasnd_read_voice_mode(u,0) ^ ULTRASND_VOICE_MODE_BACKWARDS);
- }
- else if (i == 32) {
- ultrasnd_set_voice_current(u,0,0);
- ultrasnd_set_voice_current(u,0,0);
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR);
- }
- else if (i == 'r' || i == 'R') {
- ultrasnd_set_voice_pan(u,0,0); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- }
- else if (i == 'l' || i == 'L') {
- ultrasnd_set_voice_pan(u,0,0xF); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- }
- else if (i == 'c' || i == 'C') {
- ultrasnd_set_voice_pan(u,0,0x7); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- }
- }
- } while(1);
- fprintf(stderr,"\n");
-
- /* shut up the GUS */
- for (i=0;i < u->active_voices;i++) {
- ultrasnd_stop_voice(u,i);
- for (j=0;j < 14;j++)
- ultrasnd_select_write16(u,j,0);
- }
- }
-
- /* ------------------------------------------------------------------------------------------------------- */
- if (!die) {
- printf("16-bit 44.1KHz test\n");
-
- /* load something into RAM */
- fd = open("16_44khz.wav",O_RDONLY|O_BINARY);
- if (fd < 0) fd = open("..\\..\\16_44khz.wav",O_RDONLY|O_BINARY);
- if (fd < 0) fd = open("..\\..\\..\\16_44khz.wav",O_RDONLY|O_BINARY);
- if (fd < 0) {
- fprintf(stderr,"Cannot open .WAV\n");
- return 1;
- }
- lseek(fd,44,SEEK_SET);
- ofs=0;
- printf("Loading into DRAM "); fflush(stdout);
- if ((dmaptr = ultrasnd_dram_buffer_alloc(u,4096)) != NULL) {
- printf("phys=0x%08lX ",(unsigned long)(u->dram_xfer_a->phys));
- while ((rd = _dos_xread(fd,dmaptr,4096)) > 0) {
- ultrasnd_send_dram_buffer(u,ofs,rd,ULTRASND_DMA_DATA_SIZE_16BIT);
- printf("."); fflush(stdout);
- ofs += rd;
- }
- printf("\n");
- /* and then repeat the last sample to avoid click */
- ultrasnd_poke(u,ofs,ultrasnd_peek(u,0));
- ultrasnd_poke(u,ofs+1,ultrasnd_peek(u,1));
- ultrasnd_dram_buffer_free(u);
- }
- else {
- printf("ERROR: Cannot alloc DMA transfer DRAM upload\n");
- }
- /* and then repeat the last sample to avoid click */
- close(fd);
-
- /* get the audio going */
- ultrasnd_stop_voice(u,0);
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
- ultrasnd_set_voice_fc(u,0,ultrasnd_sample_rate_to_fc(u,44100));
- ultrasnd_set_voice_ramp_rate(u,0,0,0);
- ultrasnd_set_voice_ramp_start(u,0,0xF0); /* NTS: You have to set the ramp start/end because it will override your current volume */
- ultrasnd_set_voice_ramp_end(u,0,0xF0);
- ultrasnd_set_voice_volume(u,0,0xFFF0); /* full vol */
- ultrasnd_set_voice_pan(u,0,7); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- ultrasnd_set_voice_ramp_control(u,0,0);
- ultrasnd_set_voice_start(u,0,2); /* NTS: If 0 or 1, the card won't stop and will run into 0xFFFFF and beyond */
- ultrasnd_set_voice_end(u,0,ofs-1);
- ultrasnd_set_voice_current(u,0,2); /* Start well within the range */
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
- ultrasnd_start_voice(u,0);
-
- /* wait */
- do {
- ptr = ultrasnd_read_voice_current(u,0);
- fprintf(stderr,"\x0D" "ESC to quit, ENTER to move on. 0x%08lx ",ptr); fflush(stderr);
-
- if (kbhit()) {
- i = getch();
- if (i == 27) {
- die = 1;
- break;
- }
- else if (i == 13) {
- break;
- }
- else if (i == 8) {
- ultrasnd_set_voice_mode(u,0,ultrasnd_read_voice_mode(u,0) ^ ULTRASND_VOICE_MODE_BACKWARDS);
- }
- else if (i == 32) {
- ultrasnd_set_voice_current(u,0,2);
- ultrasnd_set_voice_current(u,0,2);
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
- }
- else if (i == 'r' || i == 'R') {
- ultrasnd_set_voice_pan(u,0,0); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- }
- else if (i == 'l' || i == 'L') {
- ultrasnd_set_voice_pan(u,0,0xF); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- }
- else if (i == 'c' || i == 'C') {
- ultrasnd_set_voice_pan(u,0,0x7); /* center (FIXME: Despite the code being present, DOSBox's GUS emulation fails to emulate the pan register and everything is rendered at center) */
- }
- }
- } while(1);
- fprintf(stderr,"\n");
-
- /* shut up the GUS */
- for (i=0;i < u->active_voices;i++) {
- ultrasnd_stop_voice(u,i);
- for (j=0;j < 14;j++)
- ultrasnd_select_write16(u,j,0);
- }
- }
-
- /* ------------------------------------------------------------------------------------------------------- */
- if (!die) {
- printf("16-bit 44.1KHz stereo test (stereo 'aliasing')\n");
- /* ^ by that I mean using the Gravis recommended trick
- of uploading interleaved data and setting the fractional
- step to 2 so that the chip simply skips every other
- sample. naturally this only works in very specific
- cases, such as the 14-voice mode at 44.1KHz. */
-
- /* load something into RAM */
- fd = open("16_44khs.wav",O_RDONLY|O_BINARY);
- if (fd < 0) fd = open("..\\..\\16_44khs.wav",O_RDONLY|O_BINARY);
- if (fd < 0) fd = open("..\\..\\..\\16_44khs.wav",O_RDONLY|O_BINARY);
- if (fd < 0) {
- fprintf(stderr,"Cannot open .WAV\n");
- return 1;
- }
- lseek(fd,44,SEEK_SET);
- ofs=0;
- printf("Loading into DRAM "); fflush(stdout);
- if ((dmaptr = ultrasnd_dram_buffer_alloc(u,4096)) != NULL) {
- printf("phys=0x%08lX ",(unsigned long)(u->dram_xfer_a->phys));
- while (ofs < (120UL*1024UL) && (rd = _dos_xread(fd,dmaptr,4096)) > 0) {
- ultrasnd_send_dram_buffer(u,ofs,rd,ULTRASND_DMA_DATA_SIZE_16BIT);
- printf("."); fflush(stdout);
- ofs += rd;
- }
- printf("\n");
- /* and then repeat the last sample to avoid click */
- ultrasnd_poke(u,ofs,ultrasnd_peek(u,0));
- ultrasnd_poke(u,ofs+1,ultrasnd_peek(u,1));
- ultrasnd_dram_buffer_free(u);
- }
- else {
- printf("ERROR: Cannot alloc DMA transfer DRAM upload\n");
- }
- /* and then repeat the last sample to avoid click */
- close(fd);
-
- /* get the audio going */
- ultrasnd_stop_voice(u,0);
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
- ultrasnd_set_voice_fc(u,0,ultrasnd_sample_rate_to_fc(u,44100)*2); /* important: Must be precisely 2x 44.1KHz */
- ultrasnd_set_voice_ramp_rate(u,0,0,0);
- ultrasnd_set_voice_ramp_start(u,0,0xF0); /* NTS: You have to set the ramp start/end because it will override your current volume */
- ultrasnd_set_voice_ramp_end(u,0,0xF0);
- ultrasnd_set_voice_volume(u,0,0xFFF0); /* full vol */
- ultrasnd_set_voice_pan(u,0,0); /* full left */
- ultrasnd_set_voice_ramp_control(u,0,0);
- ultrasnd_set_voice_start(u,0,2+2); /* NTS: If 0 or 1, the card won't stop and will run into 0xFFFFF and beyond */
- ultrasnd_set_voice_end(u,0,ofs-1);
- ultrasnd_set_voice_current(u,0,2+2); /* Start well within the range */
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
-
- ultrasnd_stop_voice(u,1);
- ultrasnd_set_voice_mode(u,1,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
- ultrasnd_set_voice_fc(u,1,ultrasnd_sample_rate_to_fc(u,44100)*2); /* important: Must be precisely 2x 44.1KHz */
- ultrasnd_set_voice_ramp_rate(u,1,0,0);
- ultrasnd_set_voice_ramp_start(u,1,0xF0); /* NTS: You have to set the ramp start/end because it will override your current volume */
- ultrasnd_set_voice_ramp_end(u,1,0xF0);
- ultrasnd_set_voice_volume(u,1,0xFFF0); /* full vol */
- ultrasnd_set_voice_pan(u,1,15); /* full right */
- ultrasnd_set_voice_ramp_control(u,1,0);
- ultrasnd_set_voice_start(u,1,2+2+2); /* NTS: If 0 or 1, the card won't stop and will run into 0xFFFFF and beyond */
- ultrasnd_set_voice_end(u,1,ofs-1);
- ultrasnd_set_voice_current(u,1,2+2+2); /* Start well within the range */
- ultrasnd_set_voice_mode(u,1,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
-
- ultrasnd_start_voice_imm(u,0);
- ultrasnd_start_voice_imm(u,1);
-
- /* wait */
- do {
- unsigned long ptr2;
- ptr = ultrasnd_read_voice_current(u,0);
- ptr2 = ultrasnd_read_voice_current(u,1);
- fprintf(stderr,"\x0D" "ESC to quit, ENTER to move on. 0x%08lx,0x%08lx ",ptr,ptr2); fflush(stderr);
-
- if (kbhit()) {
- i = getch();
- if (i == 27) {
- die = 1;
- break;
- }
- else if (i == 13) {
- break;
- }
- else if (i == 8) {
- ultrasnd_stop_voice(u,0);
- ultrasnd_stop_voice(u,1);
-
- ultrasnd_set_voice_mode(u,0,ultrasnd_read_voice_mode(u,0) ^ ULTRASND_VOICE_MODE_BACKWARDS);
- ultrasnd_set_voice_mode(u,1,ultrasnd_read_voice_mode(u,0));
-
- ultrasnd_start_voice(u,0);
- ultrasnd_start_voice(u,1);
- }
- else if (i == 32) {
- ultrasnd_stop_voice(u,0);
- ultrasnd_stop_voice(u,1);
-
- ultrasnd_set_voice_current(u,0,2);
- ultrasnd_set_voice_current(u,0,2);
- ultrasnd_set_voice_mode(u,0,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
-
- ultrasnd_set_voice_current(u,1,2+2);
- ultrasnd_set_voice_current(u,1,2+2);
- ultrasnd_set_voice_mode(u,1,ULTRASND_VOICE_MODE_LOOP | ULTRASND_VOICE_MODE_BIDIR | ULTRASND_VOICE_MODE_16BIT);
-
- ultrasnd_start_voice(u,0);
- ultrasnd_start_voice(u,1);
- }
- }
- } while(1);
- fprintf(stderr,"\n");
-
- /* shut up the GUS */
- for (i=0;i < u->active_voices;i++) {
- ultrasnd_stop_voice(u,i);
- for (j=0;j < 14;j++)
- ultrasnd_select_write16(u,j,0);
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-#include <sys/types.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <stdio.h>\r
-\r
-#include <hw/cpu/cpu.h>\r
-#include <hw/dos/dos.h>\r
-#include <hw/dos/tgusmega.h>\r
-#include <hw/dos/tgussbos.h>\r
-#include <hw/dos/tgusumid.h>\r
-\r
-/* this program demonstrates how to detect Gravis Ultrasound TSR programs */\r
-int main() {\r
- {\r
- struct mega_em_info nfo;\r
- if (gravis_mega_em_detect(&nfo)) {\r
- printf("MEGA-EM v%u.%02u is resident on INT %02xh. (%04xh)\n",\r
- nfo.version>>8,\r
- nfo.version&0xFF,\r
- nfo.intnum,\r
- nfo.response);\r
- }\r
- }\r
-\r
- {\r
- int v = gravis_sbos_detect();\r
- if (v >= 0) printf("SBOS installed on INT %02xh\n",v);\r
- }\r
- \r
- {\r
- int v = gravis_ultramid_detect();\r
- if (v >= 0) printf("ULTRAMID installed on INT %02xh\n",v);\r
- }\r
- \r
- return 0;\r
-}\r
-\r
+++ /dev/null
-/* NOTES:
-
- 2011/10/28: Ah-ha! This code was having difficulty using 16-bit
- DMA channels because I somehow missed in Gravis documentation
- that the DMA start address is subject to 16-bit address translation,
- just like anything else related to 16-bit audio on the Gravis
- chipsets. The GF1 test/init routine is now able to use full
- GF1 capabilities and DMA properly when the card uses DMA channels
- 5, 6, and 7
-
- Gravis Ultrasound Max:
-
- - I ran into an annoying H/W glitch while writing this code
- that is related to starting/stopping DMA transfers.
- Apparently, if you first unmask the AT DMA channel, then
- program the GUS DRAM addr and program in the settings
- RIGHT OFF THE BAT, you will mostly get good transfers
- but some transfers will have audible static (as if for
- some odd reason the GUS is getting the DMA data but
- NOT writing every 100th byte to it's RAM or something).
-
- The workaround apparently is to cautiously start the DMA:
- - Write 0x00 to DMA control to stop, THEN read to ack
- - Program AT DMA controller, but do not unmask channel yet
- - Write configuration to GUS DMA control, but do not yet
- set the enable bit (bit 0)
- - Write DRAM address to GUS DMA control
- - Then, write DMA control again with "enable DMA" bit set
- - Then, instruct the AT DMA controller to unmask the channel.
-
- Following this sequence of steps resolves the staticy crackly
- audio observed with a GUS Max on an ancient Pentium/100MHz
- system of mine.
-
- -- Jonathan C.
-
-
- Bidirectional looping misconception:
-
- - Each voice has a "current" position, a start, and an end.
- When the current position hits the end, the voice stops.
- Unless the voice is said to loop, then it goes back to start.
- A voice can also be marked as "bi-directional" which means
- that instead the voice's "backwards" bit is set and the
- current position heads back towards the start from the end.
-
- DOSBox 0.74 GUS emulation:
- - When the current position passes start, go forward again.
- Thus, setting start == 0 and end == len-1 makes the sample
- loop properly.
- GUS MAX:
- - When the current position was start, and less than the
- previous position, go forward again. Note this makes it
- impossible to ping-pong loop a sample starting at 0
- (or 1 if 16-bit) because when start == 0 the GF1 goes right
- past the point and into 0xFFF.. without changing
- direction. To make it work, set start to 2 samples in.
-
-
- Proper voice programming sequence:
-
- The SDK doesn't say anything about this, but it seems that the
- best way to get the voice programmed the way you want without
- weird side effects, is to stop the voice, program the parameters,
- and then set the mode as the LAST STEP. If you set the mode, then
- set the positions and such, you risk the voice immediately going
- off backwards, or other side effects.
-
- Unfortuantely because of the way this code is written, you will
- need to set the mode twice. Once prior to programming, and then
- as the final step.
-
-
- Pre-initialized state and "stuck" IRQ: [BUG: FIXME]
-
- Apparently, if a previous program was using the GUS and left the
- timers active, or failed to clean up IRQ flags, our test routine
- will fail to trigger the IRQ with timers and fail the GUS. This
- can happen if you first run certain demoscene programs like "Dope"
- or "2nd Reality" then attempt to use this program.
-
- Someday when you have time, hunt down every possible way to
- a) forcibly stop the timers b) forcibly clear all pending IRQs
- and then have the code do just that before the timer test.
-
- Commenting out the timer test is not an option, since it would
- then be trivial for some other device to pass the RAM test.
-
- Note the Interwave SDK and Gravis documents mention a register
- with a bit you set to clear all pending IRQs at bootup. Maybe
- that would be of use?
-
- In the meantime, the solution is to either
- a) Run ULTRINIT from the ULTRASND directory
- b) Run this program with no IRQ and DMA, play some audio,
- then quit, and run again.
-
-
- DMA transfer programming:
-
- The GUS SDK shows that you can set a bit to get a DMA terminal
- count interrupt, meaning an IRQ when the DMA finishes. The
- actual GUS will set bit 6 (but not fire an IRQ) when the DMA
- transfer is complete. DOSBox will NOT set bit 6 when DMA TC
- complete, unless you asked for the IRQ. This is why this code
- checks both and terminates either then bit 6 is set, or the
- DMA controller indicates terminal count.
-
-
- DMA problem on real hardware with DMA channels 5, 6, and 7. [BUG: FIXME]
-
- If your ultrasound is configured for high DMA channels, this
- code fails the DMA test and does not succeed in transferring
- the test message to GUS DRAM. Yet, high DMA channels work fine
- in DOSBox.
-
- Card identification [TODO: FIXME]
-
- The Gravis SDK mentions several registers that can be used to
- identify the card (if it is a GUS 3.7 or MAX or later). The
- GUS MAX has the ability to remove the legacy GUS Classic
- sample rate limits, which might be of use to you here.
-
- Also refer to the Linux driver source code on how to go about this process:
-
- http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/sound/isa/gus/gus_dma.c
-
-
- SBOS initialization check [TODO: FIXME add to Sound Blaster library]
-
- Add code where if the DSP version comes back as 0xAA,0xAA, then
- do a quick check to see if the card is actually a GUS, and if so,
- fiddle with the "Sound Blaster emulation" registers to turn them
- off and reset the return value to 0x00 so that future SB testing
- does not see the GUS as SB.
-
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <ctype.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <malloc.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/8237/8237.h> /* 8237 DMA */
-#include <hw/8254/8254.h> /* 8254 timer */
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/ultrasnd/ultrasnd.h>
-
-static int debug_on = 0;
-static int ultrasnd_test_irq_fired = 0;
-static int ultrasnd_test_irq_n = 0;
-
-/* actual sample rate table (based on total voices) */
-const uint16_t ultrasnd_rate_per_voices[33] = {
- 44100, 44100, 44100, 44100, 44100, 44100, 44100, 44100, /* 0-7 */
- 44100, 44100, 44100, 44100, 44100, 44100, 44100, 41160, /* 8-15 */
- 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843, /* 16-23 */
- 25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, /* 24-31 */
- 19293 }; /* 32 */
-
-struct ultrasnd_ctx ultrasnd_card[MAX_ULTRASND];
-struct ultrasnd_ctx *ultrasnd_env = NULL;
-int ultrasnd_inited = 0;
-
-void ultrasnd_debug(int on) {
- debug_on = on;
-}
-
-uint32_t ultrasnd_dram_16bit_xlate(uint32_t a) {
- /* Ewwww... */
- return (a & 0x000C0000) | ((a & 0x3FFFF) >> 1UL);
-}
-
-uint32_t ultrasnd_dram_16bit_xlate_from(uint32_t a) {
- /* Ewwww... */
- return (a & 0xFFFC0000) | ((a & 0x1FFFF) << 1UL);
-}
-
-static void gus_delay(struct ultrasnd_ctx *u) {
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
- inp(u->port+0x102);
-}
-
-void ultrasnd_select_voice(struct ultrasnd_ctx *u,uint8_t reg) {
- outp(u->port+0x102,reg);
- outp(u->port+0x102,reg); /* NTS: the "gravis ultrasound encyclopedia" recommends doing this... why? */
- outp(u->port+0x102,reg);
-}
-
-void ultrasnd_select_write(struct ultrasnd_ctx *u,uint8_t reg,uint8_t data) {
- outp(u->port+0x103,reg);
- outp(u->port+0x105,data);
- gus_delay(u);
- outp(u->port+0x105,data);
-}
-
-uint16_t ultrasnd_select_read16(struct ultrasnd_ctx *u,uint8_t reg) {
- outp(u->port+0x103,reg);
- return inpw(u->port+0x104);
-}
-
-void ultrasnd_select_write16(struct ultrasnd_ctx *u,uint8_t reg,uint16_t data) {
- outp(u->port+0x103,reg);
- outpw(u->port+0x104,data);
- gus_delay(u);
- outpw(u->port+0x104,data);
-}
-
-uint8_t ultrasnd_select_read(struct ultrasnd_ctx *u,uint8_t reg) {
- outp(u->port+0x103,reg);
- gus_delay(u);
- return inp(u->port+0x105);
-}
-
-uint8_t ultrasnd_selected_read(struct ultrasnd_ctx *u) {
- return inp(u->port+0x105);
-}
-
-unsigned char ultrasnd_peek(struct ultrasnd_ctx *u,uint32_t ofs) {
- if (u == NULL) return 0xFF;
- if (ofs & 0xFF000000UL) return 0xFF; /* The GUS only has 24-bit addressing */
-
- ultrasnd_select_write16(u,0x43,(uint16_t)ofs); /* 0x43: DRAM address low 16 bits */
- ultrasnd_select_write(u,0x44,(uint8_t)(ofs >> 16UL)); /* 0x44: DRAM address upper 8 bits */
- return inp(u->port+0x107);
-}
-
-void ultrasnd_poke(struct ultrasnd_ctx *u,uint32_t ofs,uint8_t b) {
- if (u == NULL) return;
- if (ofs & 0xFF000000UL) return; /* The GUS only has 24-bit addressing */
-
- ultrasnd_select_write16(u,0x43,(uint16_t)ofs); /* 0x43: DRAM address low 16 bits */
- ultrasnd_select_write(u,0x44,(uint8_t)(ofs >> 16UL)); /* 0x44: DRAM address upper 8 bits */
- outp(u->port+0x107,b);
-}
-
-int ultrasnd_valid_dma(struct ultrasnd_ctx *u,int8_t i) {
- switch (i) {
- case 1: return 1;
- case 3: return 2;
- case 5: return 3;
- case 6: return 4;
- case 7: return 5;
- };
- return 0;
-}
-
-int ultrasnd_valid_irq(struct ultrasnd_ctx *u,int8_t i) {
- switch (i) {
- case 2: return 1;
- case 3: return 3;
- case 5: return 2;
- case 7: return 4;
- case 11: return 5;
- case 12: return 6;
- case 15: return 7;
- };
- return 0;
-}
-
-static void interrupt far ultrasnd_test_irq() {
- ultrasnd_test_irq_fired++;
-
- /* ack PIC */
- if (ultrasnd_test_irq_n >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
-}
-
-void ultrasnd_set_active_voices(struct ultrasnd_ctx *u,unsigned char voices) {
- if (voices < 14) u->active_voices = 14;
- else if (voices > 32) u->active_voices = 32;
- else u->active_voices = voices;
- u->output_rate = ultrasnd_rate_per_voices[u->active_voices];
- ultrasnd_select_write(u,0x0E,0xC0 | (u->active_voices - 1));
-}
-
-/* NOTE: If possible, you are supposed to provide both IRQs and both DMA channels provided by ULTRASND,
- * or given by a probing function. However this function also supports basic probing without any
- * knowledge of what IRQ is involved. To do that, pass in the context with port number nonzero
- * and IRQ and DMA channels set to -1 (unknown).
- *
- * if program_cfg is nonzero, this routine will write the IRQ and DMA configuration registers. */
-int ultrasnd_probe(struct ultrasnd_ctx *u,int program_cfg) {
- void (interrupt far *old_irq)() = NULL;
- unsigned char c1,c2,c2i,c;
- unsigned int i,patience;
-
- /* The "Gravis Ultrasound Programmers Encyclopedia" describes a probe function that only
- * checks whether the onboard RAM can be peek'd and poke'd. Lame. Our test here goes
- * further to ensure that it looks and acts like a Gravis Ultrasound */
- if (u == NULL) return 1;
- if (u->port < 0) return 1;
- if ((u->port&0xF) != 0) return 1;
-
- /* this card can only work with certain IRQs */
- if (u->irq1 >= 0 && ultrasnd_valid_irq(u,u->irq1) == 0) {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ %u is not a valid GUS IRQ.\n",u->port);
- return 1;
- }
- if (u->irq2 >= 0 && ultrasnd_valid_irq(u,u->irq2) == 0) {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ %u is not a valid GUS IRQ.\n",u->port,u->irq2);
- return 1;
- }
-
- /* reset the GF1 */
- ultrasnd_select_write(u,0x4C,0x00); /* 0x4C: reset register -> master reset (bit 0=0) disable DAC (bit 1=0) master IRQ disable (bit 2=0) */
- t8254_wait(t8254_us2ticks(20000)); /* wait 20ms for good measure, most docs imply 14 CPU cycles via IN statements but I don't think that's enough */
- c1 = ultrasnd_selected_read(u); /* FIXME: Reading the reg back immediately works correctly, but writing the selector register and reading back returns incorrect data? Is that DOSBox being weird or does the GUS actually do that? */
-
- /* FIXME: DOSBox's emulation implies that the timers fire the IRQ anyway even if we don't set bit 2. Is that what the actual GUS does or is DOSBox full of it on that matter? */
- c2i = 0x03 | (u->irq1 >= 0 ? 0x4 : 0x0); /* don't set bit 2 unless we intend to actually service the IRQ interrupt */
- ultrasnd_select_write(u,0x4C,c2i); /* 0x4C: reset register -> end reset (bit 0=1) enable DAC (bit 1=1) master IRQ enable (bit 2) */
- t8254_wait(t8254_us2ticks(20000)); /* wait 20ms for good measure, most docs imply 14 CPU cycles via IN statements but I don't think that's enough */
- c2 = ultrasnd_selected_read(u); /* FIXME: Reading the reg back immediately works correctly, but writing the selector register and reading back returns incorrect data? Is that DOSBox being weird or does the GUS actually do that? */
-
- if (c1 == 0xFF && c2 == 0xFF) {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: Read back 0xFF during reset, so it's probably not there\n",u->port);
- return 1;
- }
-
- /* FIXME: The ultrasound SDK documentation never says anything about being able to read the registers.
- * The programmer's encyclopedia though implies you can. So then, can we hit the reset register
- * and read it back to know it's there? [DOSBox emulation: yes, we can!] */
- /* Did we really write Ultrasound register 0x4C or is it something else? */
- if ((c1&7) != 0 || (c2&7) != c2i) {
- /* HACK: DOSBox 0.74 emulates a GUS that happily leaves your bits set after reset.
- The Real Thing however resets your bits as part of the reset. So what you
- will likely read back is only one of the bits set, and you will need to
- turn on the DAC by reading and writing again. */
- if (c1 == 0 && c2 == 1) {
- ultrasnd_select_write(u,0x4C,c2i); /* 0x4C: reset register -> end reset (bit 0=1) enable DAC (bit 1=1) master IRQ enable (bit 2) */
- t8254_wait(t8254_us2ticks(20000)); /* wait 20ms for good measure, most docs imply 14 CPU cycles via IN statements but I don't think that's enough */
- c2 = ultrasnd_selected_read(u); /* FIXME: Reading the reg back immediately works correctly, but writing the selector register and reading back returns incorrect data? Is that DOSBox being weird or does the GUS actually do that? */
- if ((c2&7) != c2i) {
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: Reset register OK but DAC enable bit is stuck off, which means that your GUS is probably not going to output the audio we are playing. If UltraInit has been showing error messages you may want to check that the line/speaker output amplifier is OK. c1=0x%02x c2=%02x\n",u->port,c1,c2);
- }
- }
- else {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: Reset register is supposed to be read/write. This is probably not a GUS. c1=0x%02x c2=%02x\n",u->port,c1,c2);
- return 1;
- }
- }
-
- /* the tests below can cause interrupts. so hook the IRQ */
- if (u->irq1 >= 0) {
- ultrasnd_test_irq_fired = 0;
- ultrasnd_test_irq_n = u->irq1;
- old_irq = _dos_getvect(irq2int(u->irq1));
- _dos_setvect(irq2int(u->irq1),ultrasnd_test_irq);
- /* perhaps a probing test prior to this call fired off the IRQ, but we failed to hook it because we didn't know. */
- _cli();
- p8259_OCW2(u->irq1,P8259_OCW2_SPECIFIC_EOI | (u->irq1&7));
- if (u->irq1 >= 8) p8259_OCW2(2,P8259_OCW2_SPECIFIC_EOI | 2); /* IRQ 8-15 -> IRQ 2 chaining */
- _sti();
- p8259_unmask(u->irq1);
- t8254_wait(t8254_us2ticks(1000)); /* 1ms */
- /* in case we did unmask an IRQ, it probably fired about now and bumped up our IRQ counter */
- _cli();
- if (ultrasnd_test_irq_fired != 0 && debug_on)
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ %d was apparently stuck prior to this probe function, and I just got it un-stuck\n",u->port,u->irq1);
- ultrasnd_test_irq_fired = 0;
- _sti();
- }
-
- if (u->irq1 >= 0 && program_cfg) {
- /* now use the Mixer register to enable line out, and to select the IRQ control register.
- * we can't actually read back the current configuration, because the registers are of
- * course write only. but we can program them to match what we know about IRQ and DMA
- * settings */
- outp(u->port+0x000,0x40 | 0x08); /* bit 1: 0=enable line out, bit 0: 0=enable line in, bit 3: 1=enable latches bit 6: 1=next I/O goes to IRQ latches */
- c1 = ultrasnd_valid_irq(u,u->irq1);
- if (u->irq2 == u->irq1) c1 |= 0x40; /* same IRQ */
- else c1 |= ultrasnd_valid_irq(u,u->irq2) << 3;
- outp(u->port+0x00B,c1);
-
- outp(u->port+0x000,0x00 | 0x08); /* bit 1: 0=enable line out, bit 0: 0=enable line in, bit 3: 1=enable latches bit 6: 0=next I/O goes to DMA latches */
- c1 = ultrasnd_valid_dma(u,u->dma1);
- if (u->dma2 == u->dma1) c1 |= 0x40; /* same IRQ */
- else c1 |= ultrasnd_valid_dma(u,u->dma2) << 3;
- outp(u->port+0x00B,c1);
- }
- else {
- /* just enable line out, do not program the IRQ and DMA settings */
- outp(u->port+0x000,0x00 | 0x08); /* bit 1: 0=enable line out, bit 0: 0=enable line in, bit 3: 1=enable latches bit 6: 1=next I/O goes to DMA latches */
- }
-
- /* clear pending or active DMA, in case the reset didn't do anything with it */
- ultrasnd_select_write(u,0x41,0x00); /* disable any DMA */
- ultrasnd_select_read(u,0x41); /* read to clear DMA terminal count---even though we didn't ask for TC IRQ */
-
- /* stop all voices, in case the last program left them running
- and firing off IRQs (like most MS-DOS GUS demos, apparently) */
- for (i=0;i < 32;i++) {
- ultrasnd_select_voice(u,i);
- ultrasnd_select_write(u,0x06,0);
- ultrasnd_select_write(u,0x07,0);
- ultrasnd_select_write(u,0x08,0);
- ultrasnd_select_write16(u,0x09,0);
- ultrasnd_select_write(u,0x00,3);
- ultrasnd_select_write(u,0x0D,0);
- ultrasnd_select_read(u,0x8D);
- }
-
- /* clear all IRQ events */
- patience = 5000;
- ultrasnd_select_voice(u,0);
- do {
- if (--patience == 0) {
- if (debug_on) fprintf(stderr,"GUS: Ran out of patience attempting to clear interrupt events\n");
- break;
- }
-
- _cli();
- if ((c1 = (ultrasnd_select_read(u,0x8F) & 0xC0)) != 0xC0) {
- ultrasnd_select_voice(u,c1&0x1F);
- ultrasnd_select_read(u,0x8D);
- ultrasnd_select_write(u,0x00,3);
- _sti();
- }
- } while (c1 != 0xC0);
- c1 = inp(u->port+0x006);
- _sti();
-
- /* any IRQs that did happen, ignore them */
- ultrasnd_test_irq_fired = 0;
-
- /* Gravis SDK also shows there are two timer registers. When loaded by the application they count up to 0xFF then generate an IRQ.
- * So if we load them and no counting happens, it's not a GUS. */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0xE0); /* clear timer IRQ, mask off timer 1 & 2 */
- ultrasnd_select_write(u,0x45,0x00); /* disable timer 1 & 2 IRQ */
- ultrasnd_select_write(u,0x46,0x80); /* load timer 1 */
- ultrasnd_select_write(u,0x47,0x80); /* load timer 2 */
- ultrasnd_select_write(u,0x45,0x0C); /* enable timer 1 & 2 IRQ */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0x03); /* unmask timer IRQs, clear reset, start timers */
-
- if ((inp(u->port+0x006)&0xC) != 0)
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ status register still shows pending IRQ for timers despite clearing and resetting them\n",u->port);
- if (u->irq1 >= 0 && ultrasnd_test_irq_fired != 0)
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ fired at or before the timer was enabled. Did something else happen?\n",u->port,ultrasnd_test_irq_fired);
-
- /* wait 500ms, more than enough time for the timers to count up to 0xFF and signal IRQ */
- /* NTS: The SDK doc doesn't say, but apparently the timer will hit 0xFF, fire the IRQ, then reset to 0 and count up again (or else DOSBox is mis-emulating the GUS) */
- for (i=0,c1=0;i < 500 && (c1&0xC) != 0xC;i++) {
- t8254_wait(t8254_us2ticks(1000)); /* 1ms */
- c1 = inp(u->port+0x006); /* IRQ status */
- }
- ultrasnd_select_write(u,0x45,0x00); /* disable timer 1 & 2 IRQ */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0xE0); /* clear timer IRQ, mask off timer 1 & 2 */
- if ((c1&0xC) != 0xC) {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: Timer readback fail 0x%02x\n",c1);
- goto timerfail;
- }
- if (u->irq1 >= 0 && ultrasnd_test_irq_fired == 0) {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: Timer never signalled IRQ\n");
- goto irqfail;
- }
-
- /* wait for the timer to stop */
- patience = 100;
- do {
- t8254_wait(t8254_us2ticks(1000)); /* 1ms */
- c = inp(u->port+0x008);
- if (--patience == 0) {
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: Timeout waiting for timers to stop\n",u->port);
- break;
- }
- } while ((c&0x60) == 0x00);
-
- /* check the RAM. is there at least a 4KB region we can peek and poke? */
- /* FIXME: According to Wikipedia there are versions of the card that don't have RAM at all (just ROM). How do we work with those? */
- for (i=0;i < 0x1000U;i++) ultrasnd_poke(u,i,(uint8_t)(i^0x55));
- for (i=0;i < 0x1000U;i++) if (ultrasnd_peek(u,i) != ((uint8_t)i^0x55)) goto ramfail;
-
- /* unless we know otherwise, samples cannot straddle a 256KB boundary */
- u->boundary256k = 1;
-
- /* initial versions came stock with 256KB with support for additional RAM in 256KB increments */
- u->total_ram = 256UL << 10UL; /* 256KB */
- for (i=1;i < ((8UL << 20UL) >> 18UL);i++) { /* test up to 8MB (8MB / 256KB banks) */
- uint32_t ofs = (uint32_t)i << (uint32_t)18UL;
-
- /* put sentry value at base to detect address wrapping */
- ultrasnd_poke(u,0,0x55);
- ultrasnd_poke(u,1,0xAA);
-
- /* now write a test value to the base of the 256KB bank */
- ultrasnd_poke(u,ofs,0x33);
- ultrasnd_poke(u,ofs+1,0x99);
-
- /* if the value at base changed, then address wrapping occurred
- * and the test immediately after would falsely detect RAM there */
- if (ultrasnd_peek(u,0) != 0x55 || ultrasnd_peek(u,1) != 0xAA)
- break;
-
- /* if the value at the bank is not what we wrote, then RAM isn't there */
- if (ultrasnd_peek(u,ofs) != 0x33 || ultrasnd_peek(u,ofs+1) != 0x99)
- break;
-
- /* final test: write to the bytes at the end of the bank and see if they made it */
- ultrasnd_poke(u,ofs+0x3FFFE,0x11);
- ultrasnd_poke(u,ofs+0x3FFFF,0x55);
- if (ultrasnd_peek(u,ofs+0x3FFFE) != 0x11 || ultrasnd_peek(u,ofs+0x3FFFF) != 0x55)
- break;
-
- /* it's RAM. count it. move on */
- u->total_ram = ofs + 0x40000UL;
- }
-
- /* Next: the DMA test */
- if (u->dma1 >= 0) {
- static const char *testing = "Test message 1234 ABCD AaaababbabaCcocococo. If you can read this the DMA transfer worked.";
- unsigned char FAR *buffer,FAR *str;
- const unsigned int testlen = 512;
-
- if ((str=buffer=ultrasnd_dram_buffer_alloc(u,testlen)) != NULL) {
- char c;
- int i,len;
- unsigned int patience,rem;
- uint32_t phys = u->dram_xfer_a->phys;
- uint32_t lin = (uint32_t)u->dram_xfer_a->lin;
-
-#if TARGET_MSDOS == 32
- memset(buffer,128,testlen);
-#else
- _fmemset(buffer,128,testlen);
-#endif
-
- _cli();
-
- /* Stop GUS DMA */
- ultrasnd_select_write(u,0x41,0x00); /* disable any DMA */
- ultrasnd_select_read(u,0x41); /* read to clear DMA terminal count---even though we didn't ask for TC IRQ */
-
- /* clear GUS DRAM so that we're not comparing stale data */
- for (i=0;i < 0x2000;i++) ultrasnd_poke(u,i,0x00);
-
- /* Fill the buffer with a chosen phrase */
- len = strlen(testing)+1;
- for (i=0;i < len;i++) str[i] = testing[i];
-
- /* Now initiate a DMA transfer (host) */
- outp(d8237_ioport(u->dma1,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(u->dma1) | D8237_MASK_SET); /* mask */
- outp(d8237_ioport(u->dma1,D8237_REG_W_WRITE_MODE),
- D8237_MODER_CHANNEL(u->dma1) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) | /* "READ" from system memory */
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_DEMAND));
- d8237_write_base(u->dma1,u->dram_xfer_a->phys); /* RAM location with not much around */
- d8237_write_count(u->dma1,testlen);
-
- /* Now initiate a DMA transfer (GUS DRAM) */
- ultrasnd_select_write(u,0x41,(u->dma1 >= 4 ? 4 : 0)); /* data size in bit 2, writing to DRAM, enable DMA */
- if (u->dma1 >= 4) /* Ugh, even DMA is subject to Gravis 16-bit translation */
- ultrasnd_select_write16(u,0x42,ultrasnd_dram_16bit_xlate(0x1000)>>4);
- else
- ultrasnd_select_write16(u,0x42,0x1000>>4);
- ultrasnd_select_write(u,0x41,(u->dma1 >= 4 ? 4 : 0) | 0x1); /* data size in bit 2, writing to DRAM, enable DMA */
-
- /* GO! */
- outp(d8237_ioport(u->dma1,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(u->dma1)); /* unmask */
-
- /* wait for the GUS to indicate DMA terminal count */
- /* Note that DOSBox's emulation of a GUS does not indicate DMA TC, since we didn't ask for it, but the actual GF1 chipset
- * will return with bit 6 set whether we asked for TC IRQ or not. */
- patience = 1000;
- do {
- rem = d8237_read_count(u->dma1);
- if (rem == 0 || rem >= 0xFFFE)
- break;
-
- t8254_wait(t8254_us2ticks(1000));
- } while (--patience != 0);
- if (rem >= 0xFFFE) rem = 0; /* the DMA counter might return 0xFFFF when terminal count reached */
-
- /* mask DMA channel again */
- outp(d8237_ioport(u->dma1,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(u->dma1) | D8237_MASK_SET); /* mask */
-
- /* stop DMA */
- ultrasnd_select_write(u,0x41,0x00);
- ultrasnd_select_read(u,0x41); /* read to clear DMA terminal count---even though we didn't ask for TC IRQ */
-
- _sti();
- ultrasnd_dram_buffer_free(u);
-
- if ((unsigned int)rem >= testlen) goto dmafail;
- else if (rem != 0) {
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: DMA transfer is incomplete (%u/%u), probably stalled out during transfer. You should choose another DMA channel.\n",u->port,rem,testlen);
- goto dmafail;
- }
-
- /* OK then, did our message make it into DRAM? */
- for (i=0;i < len;i++) {
- c = ultrasnd_peek(u,i+0x1000);
- if (c != testing[i]) {
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: DMA transfer corrupted test data (phys=%8lx lin=%8lx)\n",u->port,(unsigned long)phys,(unsigned long)lin);
- fprintf(stderr," I wrote: '%s'\n",testing);
- fprintf(stderr," Got back: '");
- for (i=0;i < len;i++) fprintf(stderr,"%c",ultrasnd_peek(u,i+0x1000));
- fprintf(stderr,"'\n");
- goto dmafail;
- }
- }
- }
- else {
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: Unable to allocate buffer for DMA testing\n",u->port);
- }
- }
-
- /* read IRQ status register. failure to clear IRQ conditions is something to be concerned about */
- c1 = inp(u->port+0x006);
- if (c1 != 0x00) fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ status register nonzero after init. The probe function missed something.\n",u->port);
-
- if (u->irq1 >= 0) {
- _dos_setvect(irq2int(u->irq1),old_irq);
- p8259_mask(u->irq1);
- }
-
- if (u->dma1 >= 0)
- u->use_dma = 1;
- else
- u->use_dma = 0;
-
- for (i=0;i < 32;i++) u->voicemode[i] = 0;
- ultrasnd_set_active_voices(u,14);
- return 0;
-dmafail:
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: DMA test failed, nothing was transferred\n",u->port);
- goto commoncleanup;
-irqfail:
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ test failed, timers did not signal IRQ handler\n",u->port);
- goto commoncleanup;
-ramfail:
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: RAM test failed\n",u->port);
- goto commoncleanup;
-timerfail:
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: Timer test failed (IRQstatus=0x%02X)\n",u->port,inp(u->port+0x006));
- goto commoncleanup;
-commoncleanup:
- if (u->irq1 >= 0) {
- unsigned char irr,i;
-
- _dos_setvect(irq2int(u->irq1),old_irq);
- p8259_mask(u->irq1);
-
- /* problem: the GUS's IRQ acts like a level-triggered interrupt. if we don't
- * take pains to clear it, it remains "stuck" and nobody else can signal that IRQ */
-
- ultrasnd_select_write(u,0x4C,0x00); /* 0x4C: reset register -> master reset (bit 0=0) disable DAC (bit 1=0) master IRQ disable (bit 2=0) */
- t8254_wait(t8254_us2ticks(20000)); /* wait 20ms for good measure, most docs imply 14 CPU cycles via IN statements but I don't think that's enough */
- ultrasnd_select_write(u,0x4C,0x01); /* 0x4C: reset register -> end reset (bit 0=1) enable DAC (bit 1=1) master IRQ enable (bit 2) */
- t8254_wait(t8254_us2ticks(20000)); /* wait 20ms for good measure, most docs imply 14 CPU cycles via IN statements but I don't think that's enough */
-
- /* clear pending or active DMA, in case the reset didn't do anything with it */
- ultrasnd_select_write(u,0x41,0x00); /* disable any DMA */
- ultrasnd_select_read(u,0x41); /* read to clear DMA terminal count---even though we didn't ask for TC IRQ */
-
- /* Gravis SDK also shows there are two timer registers. When loaded by the application they count up to 0xFF then generate an IRQ.
- * So if we load them and no counting happens, it's not a GUS. */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0xE0); /* clear timer IRQ, mask off timer 1 & 2 */
- ultrasnd_select_write(u,0x45,0x00); /* disable timer 1 & 2 IRQ */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0xE0); /* clear timer IRQ, mask off timer 1 & 2 */
-
- /* stop all voices, in case the last program left them running
- and firing off IRQs (like most MS-DOS GUS demos, apparently) */
- for (i=0;i < 32;i++) {
- ultrasnd_select_voice(u,i);
- ultrasnd_select_write(u,0x06,0);
- ultrasnd_select_write(u,0x07,0);
- ultrasnd_select_write(u,0x08,0);
- ultrasnd_select_write16(u,0x09,0);
- ultrasnd_select_write(u,0x00,3);
- ultrasnd_select_write(u,0x0D,0);
- ultrasnd_select_read(u,0x8D);
- }
-
- /* clear all IRQ events */
- patience = 5000;
- ultrasnd_select_voice(u,0);
- do {
- if (--patience == 0) {
- if (debug_on) fprintf(stderr,"GUS: Ran out of patience attempting to clear interrupt events\n");
- break;
- }
-
- _cli();
- if ((c1 = (ultrasnd_select_read(u,0x8F) & 0xC0)) != 0xC0) {
- ultrasnd_select_voice(u,c1&0x1F);
- ultrasnd_select_read(u,0x8D);
- ultrasnd_select_write(u,0x00,3);
- _sti();
- }
- } while (c1 != 0xC0);
-
- /* suck up all possible IRQ events */
- for (i=0;i < 255;i++) c1 = inp(u->port+0x006); /* IRQ status */
-
- _sti();
-
- /* the IRQ might actually be waiting to be ACKed.
- * if we don't take care of this, conflicts can happen, like the PLAYMP3
- * program probing for Ultrasnd then SoundBlaster, and the un-acked IRQ
- * prevents the Sound Blaster (on the same IRQ) from getting it's IRQ signal.
- * This is more likely than you think considering DOSBox's default configuration */
- irr = (unsigned short)p8259_read_IRR(u->irq1);
- if (irr & (1 << (u->irq1 & 7))) {
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: Stray IRQ signal\n",u->port);
- p8259_OCW2(u->irq1,P8259_OCW2_SPECIFIC_EOI|(u->irq1&7));
- }
-
- irr = (unsigned short)p8259_read_IRR(u->irq1);
- if (irr & (1 << (u->irq1 & 7))) {
- fprintf(stderr,"Gravis Ultrasound[0x%03x]: Stray IRQ signal...again!\n",u->port);
- p8259_OCW2(u->irq1,P8259_OCW2_SPECIFIC_EOI|(u->irq1&7));
- }
- }
- return 1;
-}
-
-int ultrasnd_irq_taken(int irq) {
- int i;
-
- for (i=0;i < MAX_ULTRASND;i++) {
- struct ultrasnd_ctx *u = &ultrasnd_card[i];
- if (u->irq1 == irq || u->irq2 == irq)
- return 1;
- }
-
- return 0;
-}
-
-int ultrasnd_dma_taken(int dma) {
- int i;
-
- for (i=0;i < MAX_ULTRASND;i++) {
- struct ultrasnd_ctx *u = &ultrasnd_card[i];
- if (u->dma1 == dma || u->dma2 == dma)
- return 1;
- }
-
- return 0;
-}
-
-int ultrasnd_port_taken(int port) {
- int i;
-
- for (i=0;i < MAX_ULTRASND;i++) {
- struct ultrasnd_ctx *u = &ultrasnd_card[i];
- if (u->port == port)
- return 1;
- }
-
- return 0;
-}
-
-void ultrasnd_init_ctx(struct ultrasnd_ctx *u) {
- u->port = -1;
- u->use_dma = 0;
- u->dma1 = u->dma2 = -1;
- u->irq1 = u->irq2 = -1;
- u->dram_xfer_a = NULL;
-}
-
-void ultrasnd_free_card(struct ultrasnd_ctx *u) {
- ultrasnd_dram_buffer_free(u);
- ultrasnd_init_ctx(u);
- if (u == ultrasnd_env) ultrasnd_env = NULL;
-}
-
-int ultrasnd_card_taken(struct ultrasnd_ctx *u) {
- return (u->port >= 0);
-}
-
-int init_ultrasnd() {
- int i;
-
- if (!ultrasnd_inited) {
- ultrasnd_inited = 1;
- for (i=0;i < MAX_ULTRASND;i++)
- ultrasnd_init_ctx(&ultrasnd_card[i]);
- }
-
- return 1;
-}
-
-struct ultrasnd_ctx *ultrasnd_alloc_card() {
- int i;
-
- for (i=0;i < MAX_ULTRASND;i++) {
- if (!ultrasnd_card_taken(&ultrasnd_card[i]))
- return &ultrasnd_card[i];
- }
-
- return NULL;
-}
-
-static void interrupt far dummy_irq_hi() {
- p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(2,P8259_OCW2_NON_SPECIFIC_EOI);
-}
-
-static void interrupt far dummy_irq() {
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
-}
-
-/* updates a bitmask on what IRQs have fired on their own (and therefore are not fired by the GUS).
- * also returns a bitmask of "stuck" interrupts, which is important given my comments below on
- * DOSBox and the GUS's persistent IRQ signal once timers have been triggered */
-static unsigned short ultrasnd_irq_watch(unsigned short *eirq) {
- void far *oldvec[16] = {NULL}; /* Apparently some systems including DOSBox have masked IRQs pointing to NULL interrupt vectors. So to properly test we have to put a dummy there. Ewwwww... */
- unsigned short irr,stuck = 0,irq,intv;
- unsigned int patience = 0;
- unsigned char ml,mh;
-#if TARGET_MSDOS == 32
- uint32_t *intvec = (uint32_t*)0x00000000;
-#else
- uint32_t far *intvec = (uint32_t far *)MK_FP(0x0000,0x000);
-#endif
-
- for (irq=0;irq < 16;irq++) {
- intv = irq2int(irq);
- /* read the interrupt table directly. assume the DOS extender (if 32-bit) would translate getvect() and cause problems */
- if (intvec[intv] == 0x00000000UL) {
- oldvec[irq] = _dos_getvect(intv);
- if (irq >= 8) _dos_setvect(intv,dummy_irq_hi);
- else _dos_setvect(intv,dummy_irq);
- }
- else {
- oldvec[irq] = NULL;
- }
- }
-
- /* BUG: DOSBox's emulation (and possibly the real thing) fire the IRQ
- * for the timer even if we don't set Master IRQ enable. This
- * results in the IRQ being stuck active but masked off. So what
- * we have to do is unmask the IRQ long enough for it to fire,
- * then re-mask it for the activity test. Doing this also means that
- * if the IRQ was active for something else, then that something
- * else will have it's interrupt serviced properly. Else, if it
- * was the GUS, then this lets the PIC get the IRQ signal out of
- * it's way to allow the GUS to fire again. */
-
- _cli();
- ml = p8259_read_mask(0); /* IRQ0-7 */
- mh = p8259_read_mask(8); /* IRQ8-15 */
- p8259_write_mask(0,0x00); /* unmask all interrupts, give the IRQ a chance to fire. keep a record of any IRQs that remain stuck */
- p8259_write_mask(8,0x00);
- _sti();
- stuck = 0xFFFF;
- for (patience=0;patience < 250;patience++) {
- t8254_wait(t8254_us2ticks(1000));
- _cli();
- irr = (unsigned short)p8259_read_IRR(0);
- irr |= (unsigned short)p8259_read_IRR(8) << 8U;
- _sti();
- stuck &= irr;
- }
- /* issue a specific EOI for any interrupt that remains stuck and unserviced */
- for (irq=2;irq <= 15;irq++) {
- if (irq == 2 || irq == 9) {
- /* do not disturb the IRQ 8-15 -> IRQ 2 chain or IRQ 9 weirdness. GUS cards don't use IRQ 9 anyway. */
- }
- else if (stuck & (1U << irq)) {
- _cli();
- p8259_OCW2(irq,P8259_OCW2_SPECIFIC_EOI | (irq&7));
- if (irq >= 8) p8259_OCW2(2,P8259_OCW2_SPECIFIC_EOI | 2); /* IRQ 8-15 -> IRQ 2 chaining */
- _sti(); /* then give the EOI'd IRQ a chance to clear */
- }
- }
- if (eirq != NULL) {
- _cli();
- /* now carry out the test and note interrupts as they happen */
- p8259_write_mask(0,0xFF); /* mask off all interrupts */
- p8259_write_mask(8,0xFF);
- patience = 250;
- do {
- t8254_wait(t8254_us2ticks(1000));
-
- irr = (unsigned short)p8259_read_IRR(0);
- irr |= (unsigned short)p8259_read_IRR(8) << 8U;
- for (irq=0;irq < 16;irq++) {
- if (stuck & (1U << irq)) {
- }
- else if (irr & (1U << irq)) {
- *eirq |= 1U << irq;
- }
- }
- } while (--patience != 0);
- }
-// fprintf(stdout,"Pre-test IRQ elimination: 0x%04X irr=0x%04x stuck=0x%04x\n",*eirq,irr,stuck);
-
- /* restore interrupt mask */
- p8259_write_mask(0,ml);
- p8259_write_mask(8,mh);
- _sti();
-
- for (irq=0;irq < 16;irq++) {
- if (oldvec[irq] != NULL) {
- intv = irq2int(irq);
- intvec[intv] = 0x00000000UL;
- }
- }
-
- return stuck;
-}
-
-int ultrasnd_test_irq_timer(struct ultrasnd_ctx *u,int irq) {
- unsigned char c1;
- unsigned int i;
-
- i = (unsigned short)p8259_read_IRR(0);
- i |= (unsigned short)p8259_read_IRR(8) << 8U;
- if (i & (1 << irq)) {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ timer test cannot work, IRQ %u already fired\n",u->port,irq);
- return 0;
- }
-
- _cli();
- p8259_mask(irq);
-
- /* Gravis SDK also shows there are two timer registers. When loaded by the application they count up to 0xFF then generate an IRQ.
- * So if we load them and no counting happens, it's not a GUS. */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0xE0); /* clear timer IRQ, mask off timer 1 & 2 */
- ultrasnd_select_write(u,0x45,0x00); /* disable timer 1 & 2 IRQ */
- ultrasnd_select_write(u,0x46,0xFE); /* load timer 1 */
- ultrasnd_select_write(u,0x47,0xFE); /* load timer 2 */
- ultrasnd_select_write(u,0x45,0x0C); /* enable timer 1 & 2 IRQ */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0x03); /* unmask timer IRQs, clear reset, start timers */
-
- /* wait 50ms, more than enough time for the timers to count up to 0xFF and signal IRQ */
- for (i=0;i < 500 && (c1&0xC) != 0xC;i++) {
- t8254_wait(t8254_us2ticks(1000)); /* 1ms */
- c1 = inp(u->port+0x006); /* IRQ status */
- }
- ultrasnd_select_write(u,0x45,0x00); /* disable timer 1 & 2 IRQ */
- outp(u->port+0x008,0x04); /* select "timer stuff" */
- outp(u->port+0x009,0xE0); /* clear timer IRQ, mask off timer 1 & 2 */
- if ((c1&0xC) != 0xC) {
- if (debug_on) fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ timer test failed, timers did not complete (0x%02x)\n",u->port,c1);
- return 0;
- }
-
- i = (unsigned short)p8259_read_IRR(0);
- i |= (unsigned short)p8259_read_IRR(8) << 8U;
- if (!(i & (1 << irq))) {
-// fprintf(stderr,"Gravis Ultrasound[0x%03x]: IRQ timer test failed, IRQ %d did not fire\n",u->port,irq);
- return 0;
- }
-
- return 1;
-}
-
-struct ultrasnd_ctx *ultrasnd_try_base(uint16_t base) {
- unsigned char irq_tries[] = {2,3,5,7,11,12,15},tri;
- unsigned short eliminated_irq = 0U,stuck,iv,i,cc;
- struct ultrasnd_ctx *u;
-
- if (ultrasnd_port_taken(base))
- return NULL;
- if ((u = ultrasnd_alloc_card()) == NULL)
- return NULL;
-
- ultrasnd_init_ctx(u);
- u->port = base;
-
- if (u->irq1 < 0) {
- /* prior to probing, take note of IRQs that fire without help from the GUS.
- * ignore return value (stuck IRQs) */
- ultrasnd_irq_watch(&eliminated_irq);
- }
-
- if (ultrasnd_probe(u,0)) {
- ultrasnd_free_card(u);
- return NULL;
- }
-
- if (u->irq1 < 0) {
- /* FIXME: DOSBox 0.74: This code hangs somewhere in here if auto-detecting a GUS configured on IRQ 11, or 15.
- * Update: The vector patching code in the watch function fixes it for the most part---but if you run
- * the real-mode version and then the protected mode version, the IRQ hang will occur again. */
- for (cc=0;u->irq1 < 0 && cc < 2;cc++) {
- /* probe again, updating the eliminated mask but also noting which IRQs are stuck.
- * if DOSBox's emulation is correct, the GUS will persist in it's IRQ signalling
- * because of our timer testing and the stuck IRQ might be the one we're looking for. */
- stuck = ultrasnd_irq_watch(NULL);
- if (stuck == 0)
- break;
- else if ((stuck & (stuck - 1)) == 0) { /* if only 1 bit set */
- i=0;
- for (iv=0;iv < 16;iv++) {
- if (stuck & (1 << iv)) {
- i = iv;
- break;
- }
- }
-
- if ((eliminated_irq & (1 << iv)) == 0) {
- if (ultrasnd_valid_irq(u,i) != 0 && ultrasnd_test_irq_timer(u,i))
- u->irq1 = i;
- else
- eliminated_irq |= 1 << iv;
-
- stuck = ultrasnd_irq_watch(NULL);
- }
- }
- else {
- break; /* we'll have to try another way */
- }
- }
-
- for (tri=0;u->irq1 < 0 && tri < sizeof(irq_tries);tri++) {
- if (eliminated_irq & (1 << irq_tries[tri]))
- continue;
-
- if (ultrasnd_valid_irq(u,irq_tries[tri]) != 0 && ultrasnd_test_irq_timer(u,irq_tries[tri]))
- u->irq1 = irq_tries[tri];
- else
- eliminated_irq |= 1 << irq_tries[tri];
-
- ultrasnd_irq_watch(NULL);
- }
- ultrasnd_irq_watch(NULL);
- }
-
- if (u->dma1 < 0) {
- /* TODO: DMA channel probing code */
- }
-
- return u;
-}
-
-/* try initializing a card based on the ULTRASND env variable */
-struct ultrasnd_ctx *ultrasnd_try_ultrasnd_env() {
- struct ultrasnd_ctx *u;
- int val[6],par=0;
- char *p;
-
- if ((p = getenv("ULTRASND")) == NULL)
- return NULL;
- if ((u = ultrasnd_alloc_card()) == NULL)
- return NULL;
-
- ultrasnd_init_ctx(u);
- for (par=0;par < 6;par++) val[par] = -1;
- /* ULTRASND=<port>,<play DMA>,<rec DMA>,<GUS IRQ>,<SB MIDI IRQ> */
- par = 0;
- while (*p) {
- if (*p == ' ') {
- p++;
- continue;
- }
-
- if (isdigit(*p)) {
- if (par == 0) { /* port num, hex */
- val[par] = (int)strtol(p,NULL,16); /* hexadecimal */
- }
- else {
- val[par] = (int)strtol(p,NULL,0); /* decimal */
- }
- }
- else {
- val[par] = -1;
- }
-
- while (*p && *p != ',') p++;
- if (*p == ',') p++;
- if (++par >= 6) break;
- }
-
- if (ultrasnd_port_taken(val[0]))
- return NULL;
-
- if (val[0] >= 0x200)
- u->port = val[0];
- else
- return NULL;
-
- if (val[1] >= 0)
- u->dma1 = val[1];
- if (val[2] >= 0)
- u->dma2 = val[2];
- if (val[3] >= 0)
- u->irq1 = val[3];
- if (val[4] >= 0)
- u->irq2 = val[4];
-
- return (ultrasnd_env=u);
-}
-
-uint16_t ultrasnd_sample_rate_to_fc(struct ultrasnd_ctx *u,unsigned int r) {
- uint32_t m;
-
- /* "frequency counter" is 6.8 fixed point */
- m = ((1UL << 9UL) * (unsigned long)r) / (unsigned long)u->output_rate;
- return (uint16_t)m << 1U;
-}
-
-unsigned char ultrasnd_read_voice_mode(struct ultrasnd_ctx *u,unsigned char voice) {
- ultrasnd_select_voice(u,voice);
- return ultrasnd_select_read(u,0x80);
-}
-
-void ultrasnd_set_voice_mode(struct ultrasnd_ctx *u,unsigned char voice,uint8_t mode) {
- ultrasnd_select_voice(u,voice); mode &= ~3;
- mode |= ultrasnd_select_read(u,0x00) & 3;
-
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write(u,0x00,mode);
-
- t8254_wait(t8254_us2ticks(100)); /* 100us */
-
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write(u,0x00,mode);
- u->voicemode[voice] = mode;
-}
-
-void ultrasnd_set_voice_fc(struct ultrasnd_ctx *u,unsigned char voice,uint16_t fc) {
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write16(u,0x01,fc);
-}
-
-void ultrasnd_set_voice_start(struct ultrasnd_ctx *u,unsigned char voice,uint32_t ofs) {
- if (u->voicemode[voice] & ULTRASND_VOICE_MODE_16BIT) ofs = ultrasnd_dram_16bit_xlate(ofs);
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write16(u,0x02,ofs >> 7UL);
- ultrasnd_select_write16(u,0x03,ofs << 9UL);
-}
-
-void ultrasnd_set_voice_end(struct ultrasnd_ctx *u,unsigned char voice,uint32_t ofs) {
- if (u->voicemode[voice] & ULTRASND_VOICE_MODE_16BIT) ofs = ultrasnd_dram_16bit_xlate(ofs);
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write16(u,0x04,ofs >> 7UL);
- ultrasnd_select_write16(u,0x05,ofs << 9UL);
-}
-
-void ultrasnd_stop_voice(struct ultrasnd_ctx *u,int i) {
- unsigned char c;
- int j;
-
- ultrasnd_select_voice(u,i);
- for (j=0;j < 16;j++) {
- c = ultrasnd_select_read(u,0x80); /* voice select (read) */
- ultrasnd_select_write(u,0x00,c | 3); /* voice select (write), set STOP VOICE */
- t8254_wait(t8254_us2ticks(100)); /* 100us */
- c = ultrasnd_select_read(u,0x80); /* voice select (read) */
- ultrasnd_select_write(u,0x00,c | 3); /* voice select (write), set STOP VOICE */
- t8254_wait(t8254_us2ticks(100)); /* 100us */
- c = ultrasnd_select_read(u,0x80); /* voice select (read) */
- if (c&1) break; /* if the voice stopped, then we succeeded */
- }
-
-// if (!(c&1)) fprintf(stderr,"Cannot stop voice %02x\n",c);
- u->voicemode[i] = c;
-}
-
-void ultrasnd_start_voice(struct ultrasnd_ctx *u,int i) {
- unsigned char c;
- int j;
-
- ultrasnd_select_voice(u,i);
- for (j=0;j < 16;j++) {
- c = ultrasnd_select_read(u,0x80); /* voice select (read) */
- ultrasnd_select_write(u,0x00,c & (~3)); /* voice select (write), clear STOP VOICE */
- t8254_wait(t8254_us2ticks(100)); /* 100us */
- c = ultrasnd_select_read(u,0x80); /* voice select (read) */
- ultrasnd_select_write(u,0x00,c & (~3)); /* voice select (write), clear STOP VOICE */
- t8254_wait(t8254_us2ticks(100)); /* 100us */
- c = ultrasnd_select_read(u,0x80); /* voice select (read) */
- if (!(c&1)) break; /* if the voice started, then we succeeded */
- }
-
-// if (c&1) fprintf(stderr,"Cannot start voice %02x\n",c);
- u->voicemode[i] = c;
-}
-
-void ultrasnd_start_voice_imm(struct ultrasnd_ctx *u,int i) {
- unsigned char c;
-
- ultrasnd_select_voice(u,i);
- c = ultrasnd_select_read(u,0x80); /* voice select (read) */
- ultrasnd_select_write(u,0x00,c & (~3)); /* voice select (write), clear STOP VOICE */
- u->voicemode[i] = c;
-}
-
-void ultrasnd_set_voice_ramp_rate(struct ultrasnd_ctx *u,unsigned char voice,unsigned char adj,unsigned char rate) {
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write(u,0x06,(adj & 0x3F) | (rate << 6));
-}
-
-void ultrasnd_set_voice_ramp_start(struct ultrasnd_ctx *u,unsigned char voice,unsigned char start) {
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write(u,0x07,start);
-}
-
-void ultrasnd_set_voice_ramp_end(struct ultrasnd_ctx *u,unsigned char voice,unsigned char end) {
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write(u,0x08,end);
-}
-
-void ultrasnd_set_voice_volume(struct ultrasnd_ctx *u,unsigned char voice,uint16_t vol) {
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write16(u,0x09,vol);
-}
-
-uint32_t ultrasnd_read_voice_current(struct ultrasnd_ctx *u,unsigned char voice) {
- uint32_t ofs;
- uint16_t a,b;
-
- /* nobody says or implies that the GUS keeps the halves buffered while
- we read, so assume the worst case scenario and re-read if we see
- the upper half change. */
- ultrasnd_select_voice(u,voice);
- do {
- a = ultrasnd_select_read16(u,0x8A);
- ofs = ultrasnd_select_read16(u,0x8B) >> 9UL;
- b = ultrasnd_select_read16(u,0x8A);
- } while (a != b);
- ofs |= (uint32_t)a << 7UL;
- ofs &= 0xFFFFF;
-
- /* NOTE TO SELF: As seen on GUS MAX ISA card: Bits 22-20 are set for some reason.
- And our attempts to play forwards ends up in reverse? */
- if (u->voicemode[voice] & ULTRASND_VOICE_MODE_16BIT) ofs = ultrasnd_dram_16bit_xlate_from(ofs);
- return ofs;
-}
-
-void ultrasnd_set_voice_current(struct ultrasnd_ctx *u,unsigned char voice,uint32_t loc) {
- loc &= 0xFFFFF;
- if (u->voicemode[voice] & ULTRASND_VOICE_MODE_16BIT) loc = ultrasnd_dram_16bit_xlate(loc);
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write16(u,0x0A,loc >> 7UL);
- ultrasnd_select_write16(u,0x0B,loc << 9UL);
-}
-
-void ultrasnd_set_voice_pan(struct ultrasnd_ctx *u,unsigned char voice,uint8_t pan) {
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write(u,0x0C,pan);
-}
-
-void ultrasnd_set_voice_ramp_control(struct ultrasnd_ctx *u,unsigned char voice,uint8_t ctl) {
- ultrasnd_select_voice(u,voice);
- ultrasnd_select_write(u,0x0D,ctl);
-}
-
-unsigned char FAR *ultrasnd_dram_buffer_alloc(struct ultrasnd_ctx *u,unsigned long len) {
- if (len >= 0xFF00UL) {
- ultrasnd_dram_buffer_free(u);
- return NULL;
- }
-
- if (u->dram_xfer_a != NULL) {
- if (len <= u->dram_xfer_a->length) return u->dram_xfer_a->lin;
- ultrasnd_dram_buffer_free(u);
- }
-
- if ((u->dram_xfer_a = dma_8237_alloc_buffer(len)) == NULL)
- return NULL;
-
- return u->dram_xfer_a->lin;
-}
-
-int ultrasnd_send_dram_buffer(struct ultrasnd_ctx *u,uint32_t ofs,unsigned long len,uint8_t flags) {
- unsigned char FAR *src;
- uint8_t dma = u->use_dma;
- unsigned int patience;
- uint32_t phys,i;
- uint16_t rem;
-
- if (u == NULL || u->dram_xfer_a == NULL || len > u->dram_xfer_a->length || len > 0xFF00UL)
- return 0;
-
- src = u->dram_xfer_a->lin;
- phys = u->dram_xfer_a->phys;
-
- /* cannot do half-word transfers when 16-bit is involved */
- if (dma && ((len & 1) && ((u->dma1 >= 4) || (flags & ULTRASND_DMA_DATA_SIZE_16BIT))))
- dma = 0;
- /* the target DRAM address must be 16-bit aligned (32-bit aligned for 16-bit audio) */
- if (dma && (ofs & 0xF) != 0)
- dma = 0;
- if (dma && u->dma1 >= 4 && (ofs & 0x1F) != 0)
- dma = 0;
-
- if (dma) {
- _cli();
-
- /* disable GUS DMA */
- ultrasnd_select_write(u,0x41,0x00);
- ultrasnd_select_read(u,0x41); /* read to clear DMA terminal count---even though we didn't ask for TC IRQ */
-
- /* Now initiate a DMA transfer (host) */
- outp(d8237_ioport(u->dma1,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(u->dma1) | D8237_MASK_SET); /* mask */
- outp(d8237_ioport(u->dma1,D8237_REG_W_WRITE_MODE),
- D8237_MODER_CHANNEL(u->dma1) |
- D8237_MODER_TRANSFER(D8237_MODER_XFER_READ) | /* "READ" from system memory */
- D8237_MODER_MODESEL(D8237_MODER_MODESEL_DEMAND));
- d8237_write_base(u->dma1,phys); /* RAM location with not much around */
- d8237_write_count(u->dma1,len);
-
- /* Now initiate a DMA transfer (GUS DRAM) */
- ultrasnd_select_write(u,0x41,(u->dma1 >= 4 ? 4 : 0) | (flags & 0xC0)); /* data size in bit 2, writing to DRAM, enable DMA, and bits 6-7 provided by caller */
- if (u->dma1 >= 4) /* Ugh, even DMA is subject to Gravis 16-bit translation */
- ultrasnd_select_write16(u,0x42,(uint16_t)(ultrasnd_dram_16bit_xlate(ofs)>>4UL));
- else
- ultrasnd_select_write16(u,0x42,(uint16_t)(ofs>>4UL));
- ultrasnd_select_write(u,0x41,(u->dma1 >= 4 ? 4 : 0) | 0x1 | (flags & 0xC0)); /* data size in bit 2, writing to DRAM, enable DMA, and bits 6-7 provided by caller */
-
- /* GO! */
- outp(d8237_ioport(u->dma1,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(u->dma1)); /* unmask */
-
- _sti();
-
- /* watch it run */
- /* Note that DOSBox's emulation of a GUS does not indicate DMA TC, since we didn't ask for it, but the actual GF1 chipset
- * will return with bit 6 set whether we asked for TC IRQ or not. */
- patience = 10000; /* 100ns * 10000 = 1 sec */
- do {
- rem = d8237_read_count(u->dma1);
- if (rem == 0 || rem >= 0xFFFE)
- break;
-
- t8254_wait(t8254_us2ticks(100));
- } while (--patience != 0);
- if (rem >= 0xFFFE) rem = 0;
-
- if (patience == 0)
- fprintf(stderr,"GUS DMA transfer timeout (rem=%lu)\n",rem);
- if (rem != 0)
- fprintf(stderr,"GUS DMA transfer TC while DMA controller has %u remaining\n",rem);
-
- /* mask DMA channel again */
- outp(d8237_ioport(u->dma1,D8237_REG_W_SINGLE_MASK),D8237_MASK_CHANNEL(u->dma1) | D8237_MASK_SET); /* mask */
-
- /* stop DMA */
- ultrasnd_select_write(u,0x41,0x00);
- ultrasnd_select_read(u,0x41); /* read to clear DMA terminal count---even though we didn't ask for TC IRQ */
- }
- else {
- if (flags & ULTRASND_DMA_FLIP_MSB) {
- if (flags & ULTRASND_DMA_DATA_SIZE_16BIT) {
- for (i=0;i < len;i += 2) {
- ultrasnd_poke(u,ofs+i,src[i]);
- ultrasnd_poke(u,ofs+i+1,src[i+1] ^ 0x80);
- }
- }
- else {
- for (i=0;i < len;i++) ultrasnd_poke(u,ofs+i,src[i] ^ 0x80);
- }
- }
- else {
- for (i=0;i < len;i++) ultrasnd_poke(u,ofs+i,src[i]);
- }
- }
-
- return 1;
-}
-
-void ultrasnd_dram_buffer_free(struct ultrasnd_ctx *u) {
- if (u->dram_xfer_a != NULL) {
- dma_8237_free_buffer(u->dram_xfer_a);
- u->dram_xfer_a = NULL;
- }
-}
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* 2 seems a reasonable max, since 1 is most common */
-#define MAX_ULTRASND 2
-
-/* maximum sample rate (at 14 or less voices) */
-#define ULTRASND_RATE 44100
-
-#define ULTRASND_VOICE_MODE_IS_STOPPED 0x01
-#define ULTRASND_VOICE_MODE_STOP 0x02
-#define ULTRASND_VOICE_MODE_16BIT 0x04
-#define ULTRASND_VOICE_MODE_LOOP 0x08
-#define ULTRASND_VOICE_MODE_BIDIR 0x10
-#define ULTRASND_VOICE_MODE_IRQ 0x20
-#define ULTRASND_VOICE_MODE_BACKWARDS 0x40
-#define ULTRASND_VOICE_MODE_IRQ_PENDING 0x80
-
-/* data being sent is 16-bit PCM */
-#define ULTRASND_DMA_DATA_SIZE_16BIT 0x40
-/* during transfer invert bit 7 (or bit 15) to convert unsigned->signed */
-#define ULTRASND_DMA_FLIP_MSB 0x80
-
-struct ultrasnd_ctx {
- int16_t port; /* NOTE: Gravis ultrasound takes port+0x0 to port+0xF, and port+0x100 to port+0x10F */
- int8_t dma1,dma2; /* NOTE: These can be the same */
- int8_t irq1,irq2; /* NOTE: These can be the same */
- uint32_t total_ram; /* total RAM onboard. in most cases, a multiple of 256KB */
- uint8_t active_voices;
- uint16_t output_rate;
- uint8_t boundary256k:1; /* whether all DMA transfers, playback, etc. must occur within 256KB block boundaries */
- uint8_t use_dma:1; /* whether to use DMA to upload/download data from DRAM */
- uint8_t reserved:7;
- uint8_t voicemode[32]; /* voice modes. because when you enable 16-bit PCM weird shit happens to the DRAM addresses */
- struct dma_8237_allocation *dram_xfer_a;
-};
-
-extern const uint16_t ultrasnd_rate_per_voices[33];
-extern struct ultrasnd_ctx ultrasnd_card[MAX_ULTRASND];
-extern struct ultrasnd_ctx *ultrasnd_env;
-extern int ultrasnd_inited;
-
-void ultrasnd_debug(int on);
-void ultrasnd_select_voice(struct ultrasnd_ctx *u,uint8_t reg);
-void ultrasnd_select_write(struct ultrasnd_ctx *u,uint8_t reg,uint8_t data);
-void ultrasnd_select_write16(struct ultrasnd_ctx *u,uint8_t reg,uint16_t data);
-uint16_t ultrasnd_select_read16(struct ultrasnd_ctx *u,uint8_t reg);
-uint8_t ultrasnd_select_read(struct ultrasnd_ctx *u,uint8_t reg);
-uint8_t ultrasnd_selected_read(struct ultrasnd_ctx *u);
-unsigned char ultrasnd_peek(struct ultrasnd_ctx *u,uint32_t ofs);
-void ultrasnd_poke(struct ultrasnd_ctx *u,uint32_t ofs,uint8_t b);
-int ultrasnd_valid_dma(struct ultrasnd_ctx *u,int8_t i);
-int ultrasnd_valid_irq(struct ultrasnd_ctx *u,int8_t i);
-void ultrasnd_set_active_voices(struct ultrasnd_ctx *u,unsigned char voices);
-int ultrasnd_probe(struct ultrasnd_ctx *u,int program_cfg);
-int ultrasnd_irq_taken(int irq);
-int ultrasnd_dma_taken(int dma);
-int ultrasnd_port_taken(int port);
-void ultrasnd_init_ctx(struct ultrasnd_ctx *u);
-void ultrasnd_free_card(struct ultrasnd_ctx *u);
-int ultrasnd_card_taken(struct ultrasnd_ctx *u);
-int init_ultrasnd();
-struct ultrasnd_ctx *ultrasnd_alloc_card();
-int ultrasnd_test_irq_timer(struct ultrasnd_ctx *u,int irq);
-struct ultrasnd_ctx *ultrasnd_try_base(uint16_t base);
-struct ultrasnd_ctx *ultrasnd_try_ultrasnd_env();
-uint16_t ultrasnd_sample_rate_to_fc(struct ultrasnd_ctx *u,unsigned int r);
-unsigned char ultrasnd_read_voice_mode(struct ultrasnd_ctx *u,unsigned char voice);
-void ultrasnd_set_voice_mode(struct ultrasnd_ctx *u,unsigned char voice,uint8_t mode);
-void ultrasnd_set_voice_fc(struct ultrasnd_ctx *u,unsigned char voice,uint16_t fc);
-void ultrasnd_set_voice_start(struct ultrasnd_ctx *u,unsigned char voice,uint32_t ofs);
-void ultrasnd_set_voice_end(struct ultrasnd_ctx *u,unsigned char voice,uint32_t ofs);
-void ultrasnd_stop_voice(struct ultrasnd_ctx *u,int i);
-void ultrasnd_start_voice(struct ultrasnd_ctx *u,int i);
-void ultrasnd_start_voice_imm(struct ultrasnd_ctx *u,int i);
-void ultrasnd_set_voice_ramp_rate(struct ultrasnd_ctx *u,unsigned char voice,unsigned char adj,unsigned char rate);
-void ultrasnd_set_voice_ramp_start(struct ultrasnd_ctx *u,unsigned char voice,unsigned char start);
-void ultrasnd_set_voice_ramp_end(struct ultrasnd_ctx *u,unsigned char voice,unsigned char end);
-void ultrasnd_set_voice_volume(struct ultrasnd_ctx *u,unsigned char voice,uint16_t vol);
-uint32_t ultrasnd_read_voice_current(struct ultrasnd_ctx *u,unsigned char voice);
-void ultrasnd_set_voice_current(struct ultrasnd_ctx *u,unsigned char voice,uint32_t loc);
-void ultrasnd_set_voice_pan(struct ultrasnd_ctx *u,unsigned char voice,uint8_t pan);
-void ultrasnd_set_voice_ramp_control(struct ultrasnd_ctx *u,unsigned char voice,uint8_t ctl);
-unsigned char FAR *ultrasnd_dram_buffer_alloc(struct ultrasnd_ctx *u,unsigned long len);
-int ultrasnd_send_dram_buffer(struct ultrasnd_ctx *u,uint32_t ofs,unsigned long len,uint8_t flags);
-void ultrasnd_dram_buffer_free(struct ultrasnd_ctx *u);
+++ /dev/null
-@echo off\r
-\r
-set WHAT=make\r
-if "%1" == "clean" set WHAT=clean\r
-\r
-echo Building: ohci\r
-cd ohci\r
-call make.bat %WHAT%\r
-cd ..\r
-\r
-echo All done\r
+++ /dev/null
-@echo off\r
-if exist *.map del *.map\r
-if exist *.obj del *.obj\r
-if exist *.sym del *.sym\r
-if exist *.exe del *.exe\r
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\..\mak\dos86c.mak HPS=\ all REL=..\..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\..\mak\dos86l.mak HPS=\ all REL=..\..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\..\mak\dos86m.mak HPS=\ all REL=..\..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\..\mak\dos86s.mak HPS=\ all REL=..\..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\..\mak\dos386f.mak HPS=\ all REL=..\..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_USB_OHCI_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..$(HPS)..
-AFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..$(HPS)..
-NASMFLAGS_THIS =
-
-# NTS: CPU functions here are to be moved at some point to the cpu library!
-C_SOURCE = ohci.c
-OBJS = $(SUBDIR)$(HPS)ohci.obj
-HW_USB_OHCI_LIB = $(SUBDIR)$(HPS)ohci.lib
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-$(HW_USB_OHCI_LIB): $(OBJS)
- wlib -q -b -c $(HW_USB_OHCI_LIB) -+$(SUBDIR)$(HPS)ohci.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-.ASM.OBJ:
- nasm -o $@ -f obj $(NASMFLAGS) $[@
-
-all: lib exe
-
-lib: $(HW_USB_OHCI_LIB) .symbolic
-
-exe: $(TEST_EXE) .symbolic
-
-$(TEST_EXE): $(HW_USB_OHCI_LIB) $(HW_USB_OHCI_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_PCI_LIB) $(HW_PCI_LIB_DEPENDENCIES) $(HW_PCIE_LIB) $(HW_PCIE_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(HW_8259_LIB) $(HW_8259_LIB_DEPENDENCIES) $(HW_VGAGUI_LIB) $(HW_VGAGUI_LIB_DEPENDENCIES) $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES)
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_USB_OHCI_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_PCI_LIB_WLINK_LIBRARIES) $(HW_PCIE_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) $(HW_8259_LIB_WLINK_LIBRARIES) $(HW_VGAGUI_LIB_WLINK_LIBRARIES) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_USB_OHCI_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* Experimental code to control an OHCI compliant USB Host Controller.
- (C) 2012 Jonathan Campbell
-
-
- Test results:
- - VirtualBox: works fine, however the USB emulation is cheap w.r.t. the
- Frame Counter: it advances when we read it rather than by
- the passage of time.
-
- - Pentium 4 system with VIA graphics: Works fine
-
- - Pentium III 600Mhz IBM NetVista: Works fine claiming ownership from BIOS,
- but the BIOS seems to have difficulty with taking control back when we want
- it to do so.
- */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <dos.h>
-
-#include <hw/flatreal/flatreal.h>
-#include <hw/usb/ohci/ohci.h>
-#include <hw/llmem/llmem.h>
-#include <hw/8254/8254.h>
-#include <hw/8259/8259.h> /* 8259 PIC interrupts */
-#include <hw/pcie/pcie.h>
-#include <hw/pci/pci.h>
-#include <hw/cpu/cpu.h>
-#include <hw/vga/vga.h>
-#include <hw/vga/vgagui.h>
-#include <hw/vga/vgatty.h>
-#include <hw/dos/doswin.h>
-
-static char str_tmp[256];
-
-static void help() {
- printf("test [options]\n");
- printf("USB OHCI Host Controller test program\n");
- printf("*NOTICE: Please check which standard your USB controller follows.\n");
- printf(" Currently there is UHCI, OHCI, EHCI, and XHCI. This program implements OHCI.\n");
- printf(" /dev <n> specify which USB controller to use. defaults to first find.\n");
- printf(" pci:<bus>:<dev>:<func> to specify PCI device\n");
- printf(" pcie:<bus>:<dev>:<func> to specify PCIe device\n");
- printf(" /list list USB controllers detected\n");
- printf(" /? this help\n");
-}
-
-union usb_ohci_ci_hccontrol {
- struct {
- uint32_t ControlBulkServiceRatio:2; /* bit 0-1 */
- uint32_t PeriodicListEnable:1; /* bit 2 */
- uint32_t IsochronousEnable:1; /* bit 3 */
- uint32_t ControlListEnable:1; /* bit 4 */
- uint32_t BulkListEnable:1; /* bit 5 */
- uint32_t HostControllerFunctionalState:2;/* bit 6-7 */
- uint32_t InterruptRouting:1; /* bit 8 */
- uint32_t RemoteWakeupConnected:1; /* bit 9 */
- uint32_t RemoteWakeupEnable:1; /* bit 10 */
- uint32_t _reserved_:21; /* bit 11-31 */
- } f;
- uint32_t raw;
-};
-
-union usb_ohci_ci_rhd {
- struct {
- uint32_t NumberDownstreamPorts:8; /* bit 0-7 */
- uint32_t PowerSwitchingMode:1; /* bit 8 */
- uint32_t NoPowerSwitching:1; /* bit 9 */
- uint32_t DeviceType:1; /* bit 10 */
- uint32_t OverCurrentProtectionMode:1; /* bit 11 */
- uint32_t NoOverCurrentProtection:1; /* bit 12 */
- uint32_t _reserved:11; /* bit 13-23 */
- uint32_t PowerOnToGoodTime:8; /* bit 24-31 */
-
- uint32_t DeviceRemovable:16; /* bit 0-15 bitmask for each port (0=removable 1=not removeable) */
- uint32_t PortPowerControlMask:16; /* bit 16-31 bitmask for each port */
-
- uint32_t LocalPowerStatus:1; /* bit 0 */
- uint32_t OverCurrentIndicator:1; /* bit 1 */
- uint32_t _reserved2:13; /* bit 2-14 */
- uint32_t DeviceRemoteWakeupEnable:1; /* bit 15 */
- uint32_t LocalPowerStatusChange:1; /* bit 16 */
- uint32_t OverCurrentIndicatorChange:1; /* bit 17 */
- uint32_t _reserved3:13; /* bit 18-30 */
- uint32_t ClearRemoteWakeupEnable:1; /* bit 31 */
- } f;
- struct {
- uint32_t a,b,c;
- } raw;
-};
-
-struct usb_ohci_ci_ctx {
- /* hardware resources */
- uint64_t mmio_base;
- int8_t IRQ;
- /* anything we learn about the controller */
- uint8_t bcd_revision;
- uint8_t legacy_support:1; /* OHCI controller contains "Legacy support" I/O */
- uint8_t legacy_emulation_active:1; /* (last checked) OHCI controller is emulating ports 60h and 64h */
- uint8_t legacy_irq_enable:1; /* OHCI controller generates IRQ1/IRQ12 interrupts */
- uint8_t legacy_external_irq_enable:1; /* OHCI controller generates emulation interrupt when keyboard controller signals IRQ */
- uint8_t legacy_a20_state:1; /* The state of the A20 gate */
- uint8_t bios_is_using_it:1; /* whether or not (last checked) the BIOS is using the USB controller */
- uint8_t bios_was_using_it:1; /* whether or not on first init the BIOS was using it (and therefore we must return control when done) */
- uint8_t bios_was_using_legacy_support:1;
- uint8_t bios_was_using_legacy_external_irq:1;
- uint8_t _reserved_1:1;
-
- union usb_ohci_ci_hccontrol control;
-
- uint16_t FrameInterval;
- uint16_t FullSpeedLargestDataPacket;
- uint16_t FrameRemaining;
- uint32_t FrameNumber;
- uint16_t FrameNumberHi;
- uint16_t PeriodicStart;
- volatile uint32_t irq_events;
- volatile uint32_t port_events[16]; /* NTS: port_events[0] is HcRhStatus */
-
- union usb_ohci_ci_rhd RootHubDescriptor;
-};
-
-struct usb_ohci_ci_ctx *usb_ohci_ci_create() {
- struct usb_ohci_ci_ctx *r = (struct usb_ohci_ci_ctx *)malloc(sizeof(struct usb_ohci_ci_ctx));
- if (r != NULL) {
- memset(r,0,sizeof(*r));
- r->IRQ = -1;
- }
- return r;
-}
-
-struct usb_ohci_ci_ctx *usb_ohci_ci_destroy(struct usb_ohci_ci_ctx *c) {
- if (c != NULL) {
- c->mmio_base = 0;
- c->IRQ = -1;
- free(c);
- }
- return NULL;
-}
-
-uint32_t usb_ohci_ci_read_reg(struct usb_ohci_ci_ctx *c,uint32_t reg) {
- if (reg >= 0xFFD) return 0;
-
- if (c != NULL) {
-#if TARGET_MSDOS == 32
- if (dos_ltp_info.paging) return 0;
- return *((volatile uint32_t*)((uint32_t)c->mmio_base + reg));
-#else
- if (!flatrealmode_allowed()) return 0;
- if (!flatrealmode_ok()) {
- if (!flatrealmode_setup(FLATREALMODE_4GB))
- return 0;
- }
-
- return flatrealmode_readd((uint32_t)c->mmio_base + reg);
-#endif
- }
-
- return 0;
-}
-
-void usb_ohci_ci_write_reg(struct usb_ohci_ci_ctx *c,uint32_t reg,uint32_t val) {
- if (reg >= 0xFFD) return;
-
- if (c != NULL) {
-#if TARGET_MSDOS == 32
- if (dos_ltp_info.paging) return;
- *((volatile uint32_t*)((uint32_t)c->mmio_base + reg)) = val;
-#else
- if (!flatrealmode_allowed()) return;
- if (!flatrealmode_ok()) {
- if (!flatrealmode_setup(FLATREALMODE_4GB))
- return;
- }
-
- flatrealmode_writed((uint32_t)c->mmio_base + reg,val);
-#endif
- }
-}
-
-/* NTS: USB standard: port 0 is the root hub, ports 1-15 are the actual "ports",
- and the OS is supposed to do this funky virtualization thing. Right, ok then... */
-uint32_t usb_ohci_ci_read_port_status(struct usb_ohci_ci_ctx *ohci,uint8_t port) {
- if (ohci == NULL || port > ohci->RootHubDescriptor.f.NumberDownstreamPorts)
- return ~0UL;
-
- return usb_ohci_ci_read_reg(ohci,0x50+(port*4));
-}
-
-void usb_ohci_ci_write_port_status(struct usb_ohci_ci_ctx *ohci,uint8_t port,uint32_t d) {
- if (ohci == NULL || port > ohci->RootHubDescriptor.f.NumberDownstreamPorts)
- return;
-
- usb_ohci_ci_write_reg(ohci,0x50+(port*4),d);
-}
-
-int usb_ohci_ci_software_online(struct usb_ohci_ci_ctx *c) {
- unsigned int port;
- uint32_t tmp;
-
- if (c == NULL) return -1;
-
- /* do NOT reset the controller if the BIOS is using it!!! */
- if (c->bios_is_using_it) {
- fprintf(stderr,"OHCI BUG: Don't resume the controller while the BIOS is using it, you moron.\n");
- return -1;
- }
-
- /* don't write resume if the controller is already in resume or operational mode */
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
- if (c->control.f.HostControllerFunctionalState == 2/*USBOperational*/) return 0;
-
- /* write it */
- c->control.f.HostControllerFunctionalState = 2/*USBOperational*/;
- usb_ohci_ci_write_reg(c,0x04/*HcControl*/,c->control.raw);
-
- /* wait */
- t8254_wait(t8254_us2ticks(3000/*3ms*/));
-
- /* if it kept the state, then we're good */
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
-
- /* root hub */
- tmp = usb_ohci_ci_read_port_status(c,0/*root hub*/) & 0x00020000UL; /* mask off all but "status change" bits */
- usb_ohci_ci_write_port_status(c,0,tmp); /* write back to clear status */
- c->port_events[0] |= tmp; /* note them in our context so the main program can react */
-
- /* and ports */
- for (port=1;port < c->RootHubDescriptor.f.NumberDownstreamPorts;port++) {
- tmp = usb_ohci_ci_read_port_status(c,port) & 0x001F0000UL; /* mask off all but "status change" bits */
- usb_ohci_ci_write_port_status(c,port,tmp); /* write back to clear status in HC */
- c->port_events[port] |= tmp; /* note them in our context so the main program can react */
- }
-
- return (c->control.f.HostControllerFunctionalState == 2/*USBOperational*/)?0:-1;
-}
-
-/* enter resume state, and wait 10ms */
-int usb_ohci_ci_software_resume(struct usb_ohci_ci_ctx *c) {
- if (c == NULL) return -1;
-
- /* do NOT reset the controller if the BIOS is using it!!! */
- if (c->bios_is_using_it) {
- fprintf(stderr,"OHCI BUG: Don't resume the controller while the BIOS is using it, you moron.\n");
- return -1;
- }
-
- /* don't write resume if the controller is already in resume or operational mode */
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
- if (c->control.f.HostControllerFunctionalState == 1/*USBResume*/) return 0;
- else if (c->control.f.HostControllerFunctionalState == 2/*USBOperational*/) return 0;
-
- /* write it */
- c->control.f.HostControllerFunctionalState = 1/*USBResume*/;
- usb_ohci_ci_write_reg(c,0x04/*HcControl*/,c->control.raw);
-
- /* wait */
- t8254_wait(t8254_us2ticks(10000/*10ms*/));
-
- /* if it kept the state, then we're good */
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
-
- return (c->control.f.HostControllerFunctionalState == 1/*USBResume*/)?0:-1;
-}
-
-/* explicitly put the OHCI controller into USBReset state */
-int usb_ohci_ci_set_usb_reset_state(struct usb_ohci_ci_ctx *c) {
- int ret = 0;
-
- if (c == NULL) return -1;
-
- /* do NOT reset the controller if the BIOS is using it!!! */
- if (c->bios_is_using_it) {
- fprintf(stderr,"OHCI BUG: Don't reset the controller while the BIOS is using it, you moron.\n");
- return -1;
- }
-
- /* write it */
- c->control.f.HostControllerFunctionalState = 0/*USBReset*/;
- usb_ohci_ci_write_reg(c,0x04/*HcControl*/,c->control.raw);
-
- if (ret == 0) {
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
- if (c->control.f.HostControllerFunctionalState != 0/*USBReset*/) {
- fprintf(stderr,"OHCI: controller did not accept USBReset state\n");
- ret = -1;
- }
- }
-
- return ret;
-}
-
-int usb_ohci_ci_update_root_hub_status(struct usb_ohci_ci_ctx *c) {
- if (c == NULL) return -1;
-
- /* Load port info */
- c->RootHubDescriptor.raw.a = usb_ohci_ci_read_reg(c,0x48/*HcRhDescriptorA*/);
- c->RootHubDescriptor.raw.b = usb_ohci_ci_read_reg(c,0x4C/*HcRhDescriptorB*/);
- c->RootHubDescriptor.raw.c = usb_ohci_ci_read_reg(c,0x50/*HcRhStatus*/);
-
- /* sanitize results */
- if (c->RootHubDescriptor.f.NumberDownstreamPorts > 15)
- c->RootHubDescriptor.f.NumberDownstreamPorts = 15;
-
- return 0;
-}
-
-int usb_ohci_ci_update_frame_status(struct usb_ohci_ci_ctx *c) {
- unsigned int cpu_flags;
- uint32_t tmp;
-
- if (c == NULL) return -1;
-
- cpu_flags = get_cpu_flags(); _cli();
-
- tmp = usb_ohci_ci_read_reg(c,0x38/*HcFmRemaining*/);
- c->FrameRemaining = tmp & 0x3FFF;
-
- tmp = usb_ohci_ci_read_reg(c,0x3C/*HcFmNumber*/);
- c->FrameNumber = (tmp & 0xFFFF) | (((uint32_t)c->FrameNumberHi) << 16UL);
-
- set_cpu_flags(cpu_flags);
- return 0;
-}
-
-/* cause OHCI reset. note that by USB standard, the USB controller will
- leave reset with function state == USBSuspend and it's the caller's
- job to do OHCI compliant resume -> operational state changes */
-int usb_ohci_ci_software_reset(struct usb_ohci_ci_ctx *c) {
- unsigned int patience;
- uint32_t tmp;
- int ret = 0;
- size_t i;
-
- if (c == NULL) return -1;
-
- /* do NOT reset the controller if the BIOS is using it!!! */
- if (c->bios_is_using_it) {
- fprintf(stderr,"OHCI BUG: Don't reset the controller while the BIOS is using it, you moron.\n");
- return -1;
- }
-
- /* hit the reset bit */
- usb_ohci_ci_write_reg(c,0x08/*HcCommandStatus*/,1UL);
-
- /* wait */
- t8254_wait(t8254_us2ticks(1000/*1ms*/));
-
- /* wait for the reset bit to clear */
- patience = 500;
- do {
- tmp = usb_ohci_ci_read_reg(c,0x08/*HcCommandStatus*/);
- if (!(tmp&1UL)) {
- /* the bit cleared, it's finished resetting */
- break;
- }
-
- if (--patience == 0) {
- fprintf(stderr,"OHCI: Ran out of patience waiting for reset to complete\n");
- ret = -1;
- break;
- }
-
- t8254_wait(t8254_us2ticks(10000/*10ms*/));
- } while (1);
-
- if (ret == 0) {
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
- if (!(c->control.f.HostControllerFunctionalState == 3/*USBSuspend*/ || c->control.f.HostControllerFunctionalState == 3/*USBSuspend*/)) {
- fprintf(stderr,"OHCI: Despite software reset, controller is not in suspend or reset state\n");
- ret = -1;
- }
- }
-
- /* complete the reset by disabling interrupts and functions */
- c->control.f.BulkListEnable=0;
- c->control.f.IsochronousEnable=0;
- c->control.f.ControlListEnable=0;
- c->control.f.PeriodicListEnable=0;
- c->control.f.RemoteWakeupEnable=0;
- c->control.f.RemoteWakeupConnected=0; /* FIXME: OHCI code in Linux kernel does this---do we have to do it? */
- for (i=0;i < 16;i++) c->port_events[i] = 0;
- c->irq_events = 0;
- usb_ohci_ci_write_reg(c,0x04/*HcControl*/,c->control.raw);
- usb_ohci_ci_write_reg(c,0x14/*HcInterruptDisable*/,0xC000007FUL); /* disable all event interrupts, including Ownership Change and Master */
-
- tmp = usb_ohci_ci_read_reg(c,0x34/*HcFmInterval*/);
- c->FrameInterval = tmp & 0x3FFF;
- c->FullSpeedLargestDataPacket = (tmp >> 16) & 0x7FFF;
-
- tmp = usb_ohci_ci_read_reg(c,0x40/*HcPeriodicStart*/);
- c->PeriodicStart = tmp & 0x3FFF;
-
- /* use this time to set up power management */
- tmp = usb_ohci_ci_read_reg(c,0x48/*HcRhDescriptorA*/);
- tmp &= ~0x1F00UL;
- tmp |= 0x0900UL; /* OCPM=1 PSM=1 NPS=0 */
- usb_ohci_ci_write_reg(c,0x48/*HcRhDescriptorA*/,tmp);
-
- usb_ohci_ci_update_frame_status(c);
- usb_ohci_ci_update_root_hub_status(c);
-
- return ret;
-}
-
-int usb_ohci_ci_update_ownership_status(struct usb_ohci_ci_ctx *c) {
- uint32_t tmp;
-
- if (c == NULL) return -1;
-
- tmp = usb_ohci_ci_read_reg(c,0x00);
- c->legacy_support = (tmp>>8)&1;
-
- if (c->legacy_support) tmp = usb_ohci_ci_read_reg(c,0x100);
- else tmp = 0;
-
- c->legacy_emulation_active = tmp&1;
- c->legacy_irq_enable = (tmp>>3)&1;
- c->legacy_external_irq_enable = (tmp>>4)&1;
- c->legacy_a20_state = (tmp>>8)&1;
-
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
- c->bios_is_using_it = c->control.f.InterruptRouting;
- return 0;
-}
-
-/* this is called at program startup or first use of the controller */
-int usb_ohci_ci_learn(struct usb_ohci_ci_ctx *c) {
- uint32_t tmp;
-
- if (c == NULL) return -1;
-
- tmp = usb_ohci_ci_read_reg(c,0x00);
- c->bcd_revision = tmp&0xFF;
- if (c->bcd_revision == 0) return -1;
- usb_ohci_ci_update_ownership_status(c);
- /* if the SMM trap is active or the controller was found active, then assume the BIOS was using it */
- c->bios_was_using_it = c->bios_is_using_it ||
- (c->control.f.HostControllerFunctionalState != 0/*USBReset*/ &&
- c->control.f.HostControllerFunctionalState != 3/*USBSuspend*/);
- c->bios_was_using_legacy_support = c->legacy_emulation_active && c->legacy_irq_enable;
- c->bios_was_using_legacy_external_irq = c->legacy_external_irq_enable;
-
- tmp = usb_ohci_ci_read_reg(c,0x34/*HcFmInterval*/);
- c->FrameInterval = tmp & 0x3FFF;
- c->FullSpeedLargestDataPacket = (tmp >> 16) & 0x7FFF;
-
- tmp = usb_ohci_ci_read_reg(c,0x40/*HcPeriodicStart*/);
- c->PeriodicStart = tmp & 0x3FFF;
-
- usb_ohci_ci_update_frame_status(c);
- usb_ohci_ci_update_root_hub_status(c);
- return 0;
-}
-
-int usb_ohci_ci_pci_device_is_ohci(struct usb_ohci_ci_ctx *ohci,uint8_t bus,uint8_t dev,uint8_t func) {
- /* make sure something is there before announcing it */
- uint16_t vendor,device,subsystem,subvendor_id;
- uint32_t class_code,t32a,t32b,t32c;
- uint8_t revision_id;
-
- ohci->IRQ = -1;
- ohci->mmio_base = 0;
- vendor = pci_read_cfgw(bus,dev,func,0x00); if (vendor == 0xFFFF) return 0;
- device = pci_read_cfgw(bus,dev,func,0x02); if (device == 0xFFFF) return 0;
- subvendor_id = pci_read_cfgw(bus,dev,func,0x2C);
- subsystem = pci_read_cfgw(bus,dev,func,0x2E);
-
- class_code = pci_read_cfgl(bus,dev,func,0x08);
- revision_id = class_code & 0xFF;
- class_code >>= 8UL;
-
- if (class_code == 0x0C0310UL) { /* USB OHCI controller */
- /* OK before we claim it, try to extract IRQ and MMIO base */
- {
- uint8_t l = pci_read_cfgb(bus,dev,func,0x3C);
- uint8_t p = pci_read_cfgb(bus,dev,func,0x3D);
- if (p != 0) ohci->IRQ = l;
- }
-
- {
- uint8_t bar;
-
- _cli();
- for (bar=0;bar < 6;bar++) {
- uint32_t lower=0,higher=0;
- uint8_t reg = 0x10+(bar*4);
-
- t32a = pci_read_cfgl(bus,dev,func,reg);
- if (t32a == 0xFFFFFFFFUL) continue;
-
- /* ignore BAR if I/O port */
- if (t32a & 1) continue;
-
- /* read/write BAR to test size, then readback location */
- lower = t32a & 0xFFFFFFF0UL;
- pci_write_cfgl(bus,dev,func,reg,0);
- t32b = pci_read_cfgl(bus,dev,func,reg);
- pci_write_cfgl(bus,dev,func,reg,~0UL);
- t32c = pci_read_cfgl(bus,dev,func,reg);
- pci_write_cfgl(bus,dev,func,reg,t32a); /* restore prior contents */
- if (t32a == t32b && t32b == t32c) {
- /* hm, can't change it? */
- continue;
- }
- else {
- uint32_t size = ~(t32c & ~(15UL));
- if ((size+1UL) == 0UL) continue;
- higher = lower + size;
- }
-
- if (higher == lower) continue;
- if (higher < (lower+0xFFFUL)) continue; /* must be at least 4KB large */
-
- ohci->mmio_base = (uint64_t)lower;
- break;
- }
- _sti();
- }
-
- return (ohci->mmio_base != 0ULL);
- }
-
- return 0;
-}
-
-int usb_ohci_ci_ownership_change(struct usb_ohci_ci_ctx *c,unsigned int bios_owner) {
- unsigned int patience;
- unsigned int cpu_flags;
- int ret = 0;
-
- if (c == NULL) return -1;
- if (!c->legacy_support) return 0;
-
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
- c->bios_is_using_it = c->control.f.InterruptRouting;
- if ((c->bios_is_using_it?1:0) == (bios_owner?1:0)) return 0; /* break loop when ownership becomes what we want */
-
- cpu_flags = get_cpu_flags(); _cli();
-
- if (bios_owner && !c->bios_is_using_it) {
- /* disable all other interrupts */
- usb_ohci_ci_write_reg(c,0x14/*HcInterruptDisable*/,0x8000007FUL); /* disable all event interrupts, except Ownership Change */
- }
-
- /* enable the Ownership Change interrupt, make sure BIOS responds to it */
- usb_ohci_ci_write_reg(c,0x10/*HcInterruptEnable*/,(1UL << 30UL)/*Ownership Change Interrupt*/ | (1UL << 31UL)/*Master Interrupt Enable*/);
-
- /* forcibly clear interrupt status to ensure it triggers */
- usb_ohci_ci_write_reg(c,0x0C/*HcInterruptStatus*/,0x7FFFFFFFUL);
-
- /* write InterruptStatus to change ownership */
- usb_ohci_ci_write_reg(c,0x08/*HcCommandStatus*/,1UL << 3UL);
-
- set_cpu_flags(cpu_flags);
-
- /* wait for status to clear (NTS: on one test system, the BIOS seems to take 3 seconds to regain control) */
- patience = 150; /* 100ms x 150 = 15 seconds */
- while (1) {
- /* the controller will reset the bit when ownership has changed hands */
- c->control.raw = usb_ohci_ci_read_reg(c,0x04/*HcControl*/);
- c->bios_is_using_it = c->control.f.InterruptRouting;
- if ((c->bios_is_using_it?1:0) == (bios_owner?1:0)) break; /* break loop when ownership becomes what we want */
-
- if (--patience == 0) {
- cpu_flags = get_cpu_flags(); _cli();
-
- /* the BIOS failed to get our change request */
- fprintf(stderr,"OHCI warning: Ownership Change not acknowledged\n");
-
- set_cpu_flags(cpu_flags);
- ret = -1;
- break;
- }
-
- t8254_wait(t8254_us2ticks(100000/*100ms*/));
- }
-
- if (!bios_owner && !c->control.f.InterruptRouting) {
- fprintf(stderr,"OHCI debug: Disabling all interrupts, I own the controller now\n");
- cpu_flags = get_cpu_flags(); _cli();
- usb_ohci_ci_write_reg(c,0x14/*HcInterruptDisable*/,0xC000007FUL); /* disable all event interrupts, including Ownership Change */
- set_cpu_flags(cpu_flags);
- }
-
- usb_ohci_ci_update_ownership_status(c);
- return ret;
-}
-
-int usb_ohci_ci_pcie_device_is_ohci(struct usb_ohci_ci_ctx *ohci,uint8_t bus,uint8_t dev,uint8_t func) {
- /* make sure something is there before announcing it */
- uint16_t vendor,device,subsystem,subvendor_id;
- uint32_t class_code,t32a,t32b,t32c;
- uint8_t revision_id;
-
- ohci->IRQ = -1;
- ohci->mmio_base = 0;
- vendor = pcie_read_cfgw(bus,dev,func,0x00); if (vendor == 0xFFFF) return 0;
- device = pcie_read_cfgw(bus,dev,func,0x02); if (device == 0xFFFF) return 0;
- subvendor_id = pcie_read_cfgw(bus,dev,func,0x2C);
- subsystem = pcie_read_cfgw(bus,dev,func,0x2E);
-
- class_code = pcie_read_cfgl(bus,dev,func,0x08);
- revision_id = class_code & 0xFF;
- class_code >>= 8UL;
-
- if (class_code == 0x0C0310UL) { /* USB OHCI controller */
- /* OK before we claim it, try to extract IRQ and MMIO base */
- {
- uint8_t l = pcie_read_cfgb(bus,dev,func,0x3C);
- uint8_t p = pcie_read_cfgb(bus,dev,func,0x3D);
- if (p != 0) ohci->IRQ = l;
- }
-
- {
- uint8_t bar;
-
- _cli();
- for (bar=0;bar < 6;bar++) {
- uint32_t lower=0,higher=0;
- uint8_t reg = 0x10+(bar*4);
-
- t32a = pcie_read_cfgl(bus,dev,func,reg);
- if (t32a == 0xFFFFFFFFUL) continue;
-
- /* ignore BAR if I/O port */
- if (t32a & 1) continue;
-
- /* read/write BAR to test size, then readback location */
- lower = t32a & 0xFFFFFFF0UL;
- pcie_write_cfgl(bus,dev,func,reg,0);
- t32b = pcie_read_cfgl(bus,dev,func,reg);
- pcie_write_cfgl(bus,dev,func,reg,~0UL);
- t32c = pcie_read_cfgl(bus,dev,func,reg);
- pcie_write_cfgl(bus,dev,func,reg,t32a); /* restore prior contents */
- if (t32a == t32b && t32b == t32c) {
- /* hm, can't change it? */
- continue;
- }
- else {
- uint32_t size = ~(t32c & ~(15UL));
- if ((size+1UL) == 0UL) continue;
- higher = lower + size;
- }
-
- if (higher == lower) continue;
- if (higher < (lower+0xFFFUL)) continue; /* must be at least 4KB large */
-
- ohci->mmio_base = (uint64_t)lower;
- break;
- }
- _sti();
- }
-
- return (ohci->mmio_base != 0ULL);
- }
-
- return 0;
-}
-
-static const char *hexes = "0123456789ABCDEF";
-static struct usb_ohci_ci_ctx *ohci = NULL;
-
-static void (interrupt *usb_old_irq)() = NULL;
-static void interrupt usb_irq() {
- uint32_t pending,tmp;
-
- /* show IRQ activity */
- (*vga_alpha_ram)++;
-
- /* read back what the USB controller says happened */
- pending = usb_ohci_ci_read_reg(ohci,0x0C/*HcInterruptStatus*/);
- vga_alpha_ram[1+0] = hexes[(pending>>28UL)&0xFUL] | 0x1E00;
- vga_alpha_ram[1+1] = hexes[(pending>>24UL)&0xFUL] | 0x1E00;
- vga_alpha_ram[1+2] = hexes[(pending>>20UL)&0xFUL] | 0x1E00;
- vga_alpha_ram[1+3] = hexes[(pending>>16UL)&0xFUL] | 0x1E00;
- vga_alpha_ram[1+4] = hexes[(pending>>12UL)&0xFUL] | 0x1E00;
- vga_alpha_ram[1+5] = hexes[(pending>> 8UL)&0xFUL] | 0x1E00;
- vga_alpha_ram[1+6] = hexes[(pending>> 4UL)&0xFUL] | 0x1E00;
- vga_alpha_ram[1+7] = hexes[(pending>> 0UL)&0xFUL] | 0x1E00;
-
- /* Frame Number Overflow */
- if (pending & 32) {
- tmp = usb_ohci_ci_read_reg(ohci,0x3C/*HcFmNumber*/);
- if (!(tmp & 0x8000)) ohci->FrameNumberHi++; /* if it carried 0xFFFF -> 0x0000 then increment high 16 bits */
- }
- /* Root Hub status change.
- NTS: We MUST handle it here to clear the interrupt. This is where VirtualBox is so goddam misleading:
- actual OHCI controllers will nag and pester and hammer the CPU with IRQ signals until the condition
- is cleared, and if we never clear it, the IRQ shitstorm is enough to slow the system to a crawl!
- So to be an effective USB driver, you HAVE to take care of it! */
- if (pending & 64) {
- unsigned int port;
-
- /* root hub */
- tmp = usb_ohci_ci_read_port_status(ohci,0/*root hub*/) & 0x00020000UL; /* mask off all but "status change" bits */
- usb_ohci_ci_write_port_status(ohci,0,tmp); /* write back to clear status */
- ohci->port_events[0] |= tmp; /* note them in our context so the main program can react */
-
- /* and ports */
- for (port=1;port <= ohci->RootHubDescriptor.f.NumberDownstreamPorts;port++) {
- tmp = usb_ohci_ci_read_port_status(ohci,port) & 0x001F0000UL; /* mask off all but "status change" bits */
- usb_ohci_ci_write_port_status(ohci,port,tmp); /* write back to clear status in HC */
- ohci->port_events[port] |= tmp; /* note them in our context so the main program can react */
- }
- }
-
- /* USB ack */
- ohci->irq_events |= pending & (~(4UL|32UL));
- if (pending != 0UL) usb_ohci_ci_write_reg(ohci,0x0C/*HcInterruptStatus*/,pending);
-
- /* PIC ack */
- if (ohci->IRQ >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
- p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
-}
-
-static const struct vga_menu_item menu_separator =
- {(char*)1, 's', 0, 0};
-
-
-static const struct vga_menu_item main_menu_file_quit =
- {"Quit", 'q', 0, 0};
-
-static const struct vga_menu_item* main_menu_file[] = {
- &main_menu_file_quit,
- NULL
-};
-
-
-static const struct vga_menu_item main_menu_port_acknowledge =
- {"Acknowledge", 'a', 0, 0};
-
-static const struct vga_menu_item main_menu_port_psm =
- {"Toggle PSM (Power Switching Mode) [root]", 'p', 0, 0};
-
-static const struct vga_menu_item main_menu_port_nps =
- {"Toggle NPS (No Power Switching) [root]", 'n', 0, 0};
-
-static const struct vga_menu_item main_menu_port_ocpm =
- {"Toggle OCPM (OverCurrentProtMode) [root]", 'o', 0, 0};
-
-static const struct vga_menu_item main_menu_port_nocp =
- {"Toggle NOCP [root]", 0, 0, 0};
-
-static const struct vga_menu_item main_menu_port_clear_global_power =
- {"Global Power Off [root]", 0, 0, 0};
-
-static const struct vga_menu_item main_menu_port_set_global_power =
- {"Global Power On [root]", 0, 0, 0};
-
-static const struct vga_menu_item main_menu_port_toggle_removeable =
- {"Toggle Device Removeable [port]", 'r', 0, 0};
-
-static const struct vga_menu_item main_menu_port_toggle_port_power_mask =
- {"Toggle Port Power Mask [port]", 'm', 0, 0};
-
-static const struct vga_menu_item main_menu_port_toggle_port_enable =
- {"Toggle Port Enable [port]", 'e', 0, 0};
-
-static const struct vga_menu_item main_menu_port_toggle_port_suspend =
- {"Toggle Port Suspend [port]", 's', 0, 0};
-
-static const struct vga_menu_item main_menu_port_enable_port_power =
- {"Enable Port Power [port]", 'p', 0, 0};
-
-static const struct vga_menu_item main_menu_port_disable_port_power =
- {"Disable Port Power [port]", 'd', 0, 0};
-
-static const struct vga_menu_item main_menu_port_do_port_reset =
- {"Reset Port [port]", 't', 0, 0};
-
-static const struct vga_menu_item* main_menu_port[] = {
- &main_menu_port_acknowledge,
- &main_menu_port_psm,
- &main_menu_port_nps,
- &main_menu_port_ocpm,
- &main_menu_port_nocp,
- &main_menu_port_clear_global_power,
- &main_menu_port_set_global_power,
- &menu_separator,
- &main_menu_port_toggle_removeable,
- &main_menu_port_toggle_port_power_mask,
- &main_menu_port_toggle_port_enable,
- &main_menu_port_toggle_port_suspend,
- &main_menu_port_disable_port_power,
- &main_menu_port_enable_port_power,
- &main_menu_port_do_port_reset,
- NULL
-};
-
-
-static const struct vga_menu_item main_menu_help_about =
- {"About", 'r', 0, 0};
-
-static const struct vga_menu_item* main_menu_help[] = {
- &main_menu_help_about,
- NULL
-};
-
-
-static const struct vga_menu_bar_item main_menu_bar[] = {
- /* name key scan x w id */
- {" File ", 'F', 0x21, 0, 6, &main_menu_file}, /* ALT-F */
- {" Port ", 'P', 0x19, 6, 6, &main_menu_port}, /* ALT-P */
- {" Help ", 'H', 0x23, 12, 6, &main_menu_help}, /* ALT-H */
- {NULL, 0, 0x00, 0, 0, 0}
-};
-
-static void ui_anim(int force) {
- sprintf(str_tmp,"Frame=%08lX IRQEV=0x%08lX",(unsigned long)ohci->FrameNumber,(unsigned long)ohci->irq_events);
- vga_moveto(10,0);
- vga_write_color(0xE);
- vga_write(str_tmp);
-}
-
-static void my_vga_menu_idle() {
- ui_anim(0);
-}
-
-void main_menu() {
- const struct vga_menu_item *mitem = NULL;
- unsigned char fullredraw=1,redraw=1;
- uint32_t last_redraw_usb_frame=0,redrawcount=0,tmp;
- unsigned int die=0;
- VGA_ALPHA_PTR vga;
- unsigned int x,y;
- int selector=0;
- int i,port,c;
-
- while (!die) {
- usb_ohci_ci_update_frame_status(ohci);
-
- if (fullredraw) {
- fullredraw=0;
- redraw=1;
-
- vga = vga_alpha_ram;
- x = vga_width * vga_height;
- for (y=0;y < x;y++) vga[y] = 0x0700 | ' ';
-
- vga_menu_bar_draw();
- }
-
- /* if the USB controller indicates a change of the USB root hub, update our GUI */
- _cli();
- if (ohci->irq_events & 0x40UL) {
- ohci->irq_events &= ~0x40UL;
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- /* or if some number of USB frames go by without any event, update our GUI */
- else {
- uint32_t dif = ohci->FrameNumber - last_redraw_usb_frame;
- if (dif >= 5000) { /* 5 seconds of USB frames */
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- _sti();
-
- if (redraw) {
- _cli();
- last_redraw_usb_frame = ohci->FrameNumber;
- _sti();
-
- vga_write_color(selector == 0 ? 0x70 : 0x07);
-
- vga_moveto(0,3);
- sprintf(str_tmp,"Root Hub Descriptor: %02u ports [redraw=%lu]\n",
- ohci->RootHubDescriptor.f.NumberDownstreamPorts,(unsigned long)(redrawcount++));
- vga_write(str_tmp);
-
- sprintf(str_tmp,"PSM=%u NPS=%u OCPM=%u NOCP=%u POTGT=%-3ums\n",
- ohci->RootHubDescriptor.f.PowerSwitchingMode,
- ohci->RootHubDescriptor.f.NoPowerSwitching,
- ohci->RootHubDescriptor.f.OverCurrentProtectionMode,
- ohci->RootHubDescriptor.f.NoOverCurrentProtection,
- (unsigned int)ohci->RootHubDescriptor.f.PowerOnToGoodTime * 2U);
- vga_write(str_tmp);
-
- sprintf(str_tmp,"REMOVEABLE=%08lX POWERCTRL=%08lX OCI=%u DRWE=%u OCIC=%u\n",
- (unsigned long)(ohci->RootHubDescriptor.f.DeviceRemovable),
- (unsigned long)(ohci->RootHubDescriptor.f.PortPowerControlMask),
- ohci->RootHubDescriptor.f.OverCurrentIndicator,
- ohci->RootHubDescriptor.f.DeviceRemoteWakeupEnable,
- ohci->RootHubDescriptor.f.OverCurrentIndicatorChange);
- vga_write(str_tmp);
-
- vga_write("\n");
-
- for (port=1;port <= ohci->RootHubDescriptor.f.NumberDownstreamPorts;port++) {
- uint32_t ps = usb_ohci_ci_read_port_status(ohci,port);
-
- if (!(ps&0x00000001UL)) /* not connected: grayed out */
- vga_write_color(selector == port ? 0x78 : 0x08);
- else if (ps&0x00000008UL) /* overcurrent: red */
- vga_write_color(selector == port ? 0x7C : 0x0C);
- else if (ps&0x001F0000UL) /* something changed: bright green */
- vga_write_color(selector == port ? 0x20 : 0x0A);
- else
- vga_write_color(selector == port ? 0x70 : 0x07);
-
- sprintf(str_tmp,"PORT%d Connected=%u Enabled=%u Suspended=%u OCI=%u Reset=%u Power=%u LowSpeed=%u\n",
- port,
- (ps&0x00000001UL)?1:0, /* CCS */
- (ps&0x00000002UL)?1:0, /* PES */
- (ps&0x00000004UL)?1:0, /* PSS */
- (ps&0x00000008UL)?1:0, /* POCI Overcurrent Indicator */
- (ps&0x00000010UL)?1:0, /* PRS */
- (ps&0x00000100UL)?1:0, /* PPS */
- (ps&0x00000200UL)?1:0); /* LSDA */
- vga_write(str_tmp);
-
- sprintf(str_tmp," ConnChg=%u EnChg=%u SuspChg=%u OCIC=%u ResetChg=%u CantRem=%u PerPortPwr=%u\n",
- (ps&0x00010000UL)?1:0, /* CSC */
- (ps&0x00020000UL)?1:0, /* PESC */
- (ps&0x00040000UL)?1:0, /* PSSC */
- (ps&0x00080000UL)?1:0, /* OCIC */
- (ps&0x00100000UL)?1:0, /* PRSC */
- (ohci->RootHubDescriptor.f.DeviceRemovable>>port)&1,
- (ohci->RootHubDescriptor.f.PortPowerControlMask>>port&1));
- vga_write(str_tmp);
- }
-
- redraw=0;
- }
-
- ui_anim(0);
-
- if ((mitem = vga_menu_bar_keymon()) != NULL) {
- /* act on it */
- if (mitem == &main_menu_file_quit) {
- die = 1;
- }
- else if (mitem == &main_menu_help_about) {
- struct vga_msg_box box;
- vga_msg_box_create(&box,"USB OHCI test program v1.0 for DOS\n\n(C) 2011-2012 Jonathan Campbell\nALL RIGHTS RESERVED\n"
-#if TARGET_MSDOS == 32
- "32-bit protected mode version"
-#elif defined(__LARGE__)
- "16-bit real mode (large model) version"
-#elif defined(__MEDIUM__)
- "16-bit real mode (medium model) version"
-#elif defined(__COMPACT__)
- "16-bit real mode (compact model) version"
-#else
- "16-bit real mode (small model) version"
-#endif
- ,0,0);
- while (1) {
- ui_anim(0);
- if (kbhit()) {
- i = getch();
- if (i == 0) i = getch() << 8;
- if (i == 13 || i == 27) break;
- }
- }
- vga_msg_box_destroy(&box);
- }
- else if (mitem == &main_menu_port_acknowledge) {
- if (selector == 0) {
- /* root hub */
- usb_ohci_ci_write_reg(ohci,0x50/*HcRhStatus*/,1UL<<17UL);
- redraw = 1;
- }
- else {
- /* port */
- usb_ohci_ci_write_port_status(ohci,selector,0x1F0000UL);
- redraw = 1;
- }
-
- usb_ohci_ci_update_root_hub_status(ohci);
- }
- else if (mitem == &main_menu_port_nps) {
- if (selector == 0) {
- tmp = usb_ohci_ci_read_reg(ohci,0x48/*HcRhDescriptorA*/);
- tmp ^= 0x200;/*NPS*/
- usb_ohci_ci_write_reg(ohci,0x48/*HcRhDescriptorA*/,tmp);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_psm) {
- if (selector == 0) {
- tmp = usb_ohci_ci_read_reg(ohci,0x48/*HcRhDescriptorA*/);
- tmp ^= 0x100;/*PSM*/
- usb_ohci_ci_write_reg(ohci,0x48/*HcRhDescriptorA*/,tmp);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_ocpm) {
- if (selector == 0) {
- tmp = usb_ohci_ci_read_reg(ohci,0x48/*HcRhDescriptorA*/);
- tmp ^= 0x800;/*OCPM*/
- usb_ohci_ci_write_reg(ohci,0x48/*HcRhDescriptorA*/,tmp);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_nocp) {
- if (selector == 0) {
- tmp = usb_ohci_ci_read_reg(ohci,0x48/*HcRhDescriptorA*/);
- tmp ^= 0x1000;/*NOCP*/
- usb_ohci_ci_write_reg(ohci,0x48/*HcRhDescriptorA*/,tmp);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_clear_global_power) {
- usb_ohci_ci_write_reg(ohci,0x50/*HcRhStatus*/,0x00000001UL);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- else if (mitem == &main_menu_port_set_global_power) {
- usb_ohci_ci_write_reg(ohci,0x50/*HcRhStatus*/,0x00010000UL);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- else if (mitem == &main_menu_port_toggle_removeable) {
- if (selector != 0) {
- ohci->RootHubDescriptor.f.DeviceRemovable ^= 1UL << (uint32_t)selector;
- usb_ohci_ci_write_reg(ohci,0x4C/*HcRhDescriptorB*/,ohci->RootHubDescriptor.raw.b);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_toggle_port_power_mask) {
- if (selector != 0) {
- ohci->RootHubDescriptor.f.PortPowerControlMask ^= 1UL << (uint32_t)selector;
- usb_ohci_ci_write_reg(ohci,0x4C/*HcRhDescriptorB*/,ohci->RootHubDescriptor.raw.b);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_toggle_port_enable) {
- if (selector != 0) {
- tmp = usb_ohci_ci_read_port_status(ohci,selector);
- if (tmp & 2UL) {
- /* port is enabled, disable */
- usb_ohci_ci_write_port_status(ohci,selector,1UL/*ClearPortEnable*/);
- }
- else {
- /* port is disabled, enable */
- usb_ohci_ci_write_port_status(ohci,selector,2UL/*SetPortEnable*/);
- }
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_toggle_port_suspend) {
- if (selector != 0) {
- tmp = usb_ohci_ci_read_port_status(ohci,selector);
- if (tmp & 4UL) {
- usb_ohci_ci_write_port_status(ohci,selector,8UL/*ClearPortSuspend*/);
- }
- else {
- usb_ohci_ci_write_port_status(ohci,selector,4UL/*SetPortSuspend*/);
- }
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- /* NTS: Some USB controllers, especially the "virtual" one in VirtualBox, don't reliably reset the
- Port Power state bit even when we do power it off. So we can't offer a "toggle" function */
- else if (mitem == &main_menu_port_enable_port_power) {
- if (selector != 0) {
- usb_ohci_ci_write_port_status(ohci,selector,0x100UL/*SetPortPower*/);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_disable_port_power) {
- if (selector != 0) {
- usb_ohci_ci_write_port_status(ohci,selector,0x200UL/*ClearPortPower*/);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- else if (mitem == &main_menu_port_do_port_reset) {
- if (selector != 0) {
- usb_ohci_ci_write_port_status(ohci,selector,16UL/*SetPortReset*/);
- usb_ohci_ci_update_root_hub_status(ohci);
- redraw = 1;
- }
- }
- }
-
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 0x4800) { /* uparrow */
- if (selector == 0) selector = ohci->RootHubDescriptor.f.NumberDownstreamPorts;
- else selector--;
- redraw = 1;
- }
- else if (c == 0x5000) { /* downarrow */
- if (selector == ohci->RootHubDescriptor.f.NumberDownstreamPorts) selector = 0;
- else selector++;
- redraw = 1;
- }
- }
- }
-}
-
-int main(int argc,char **argv) {
- char *arg_dev = NULL;
- int arg_list = 0;
- int bus,dev,func;
- int i,c;
-
- assert(sizeof(union usb_ohci_ci_rhd) == 12);
-
- for (i=1;i < argc;) {
- char *a = argv[i++];
-
- if (*a == '-' || *a == '/') {
- do { a++; } while (*a == '-' || *a == '/');
-
- if (!strcmp(a,"h") || !strcmp(a,"help") || !strcmp(a,"?")) {
- help();
- return 1;
- }
- else if (!strcmp(a,"list")) {
- arg_list = 1;
- }
- else if (!strcmp(a,"dev")) {
- arg_dev = argv[i++];
- }
- else {
- printf("Unknown switch '%s'\n",a);
- help();
- return 1;
- }
- }
- else {
- printf("Unknown arg '%s'\n",a);
- return 1;
- }
- }
-
- cpu_probe();
-#if TARGET_MSDOS == 32
- probe_dpmi();
- dos_ltp_probe();
-#endif
- if (!probe_8254()) {
- printf("8254 timer not found\n");
- return 1;
- }
-
- if (!probe_8259()) {
- printf("There does not appear to be a PIC on your system\n");
- return 1;
- }
-
- if (!probe_vga()) { /* NTS: By "VGA" we mean any VGA, EGA, CGA, MDA, or other common graphics hardware on the PC platform
- that acts in common ways and responds to I/O ports 3B0-3BF or 3D0-3DF as well as 3C0-3CF */
- printf("No VGA hardware!\n");
- return 1;
- }
-
- if (!llmem_init()) {
- printf("Your system is not suitable to use with the Long-Long memory access library\n");
- printf("Reason: %s\n",llmem_reason);
- }
-
-#if TARGET_MSDOS == 16
- if (!flatrealmode_setup(FLATREALMODE_4GB)) {
- printf("Unable to set up flat real mode (needed for 16-bit builds)\n");
- printf("Most ACPI functions require access to the full 4GB range.\n");
- }
-#endif
-
- if (pci_probe(-1) != PCI_CFG_NONE)
- printf("PCI bus detected\n");
- if (pcie_probe(-1) != PCIE_CFG_NONE)
- printf("PCIe bus detected\n");
-
- ohci = usb_ohci_ci_create();
- if (ohci == NULL) {
- printf("Failed to create OHCI context\n");
- return 1;
- }
-
- if (pci_cfg != PCI_CFG_NONE) {
- if (pci_bios_last_bus == -1) pci_probe_for_last_bus();
-
- if (arg_dev == NULL) {
- for (bus=0;(arg_list || ohci->mmio_base == 0ULL) && bus <= pci_bios_last_bus;bus++) {
- for (dev=0;(arg_list || ohci->mmio_base == 0ULL) && dev < 32;dev++) {
- uint8_t functions = pci_probe_device_functions(bus,dev);
- for (func=0;(arg_list || ohci->mmio_base == 0ULL) && func < functions;func++) {
- if (usb_ohci_ci_pci_device_is_ohci(ohci,bus,dev,func)) {
- if (arg_list) {
- printf("PCI:%u:%u:%u IRQ=%d MMIO=%08llX\n",bus,dev,
- func,ohci->IRQ,(unsigned long long)ohci->mmio_base);
- }
- }
- }
- }
- }
- }
- }
-
- if (pcie_cfg != PCIE_CFG_NONE) {
- if (arg_dev == NULL) {
- for (bus=0;(arg_list || ohci->mmio_base == 0ULL) && bus <= pcie_bios_last_bus;bus++) {
- for (dev=0;(arg_list || ohci->mmio_base == 0ULL) && dev < 32;dev++) {
- uint8_t functions = pcie_probe_device_functions(bus,dev);
- for (func=0;(arg_list || ohci->mmio_base == 0ULL) && func < functions;func++) {
- if (usb_ohci_ci_pcie_device_is_ohci(ohci,bus,dev,func)) {
- if (arg_list) {
- printf("PCIE:%u:%u:%u IRQ=%d MMIO=%08llX\n",bus,dev,
- func,ohci->IRQ,(unsigned long long)ohci->mmio_base);
- }
- }
- }
- }
- }
- }
- }
-
- if (!arg_list && ohci->mmio_base == 0ULL && arg_dev != NULL) {
- char *p = arg_dev;
-
- if (!strncasecmp(p,"pci:",4)) {
- p += 4;
- bus = (int)strtoul(p,&p,10);
- if (*p == ':') p++;
- dev = (int)strtoul(p,&p,10);
- if (*p == ':') p++;
- func = (int)strtoul(p,&p,10);
-
- if (!usb_ohci_ci_pci_device_is_ohci(ohci,bus,dev,func))
- fprintf(stderr,"PCI %u:%u:%u is not correct device\n",bus,dev,func);
- }
- else if (!strncasecmp(p,"pcie:",5)) {
- p += 5;
- bus = (int)strtoul(p,&p,10);
- if (*p == ':') p++;
- dev = (int)strtoul(p,&p,10);
- if (*p == ':') p++;
- func = (int)strtoul(p,&p,10);
-
- if (!usb_ohci_ci_pcie_device_is_ohci(ohci,bus,dev,func))
- fprintf(stderr,"PCIE %u:%u:%u is not correct device\n",bus,dev,func);
- }
- }
-
- if (arg_list || ohci->mmio_base == 0ULL || ohci->IRQ <= 0) {
- if (!arg_list) printf("No USB controllers found\n");
- ohci = usb_ohci_ci_destroy(ohci);
- return 1;
- }
-
- printf("Using USB OHCI controller @%08llX IRQ %d\n",(unsigned long long)ohci->mmio_base,ohci->IRQ);
- if (usb_ohci_ci_learn(ohci)) {
- fprintf(stderr,"Failed to learn about the controller\n");
- return 1;
- }
- printf("OHCI %u.%u compliant controller\n",ohci->bcd_revision>>4,ohci->bcd_revision&0xF);
- if (ohci->legacy_support) printf(" - With Legacy Support\n");
- if (ohci->legacy_emulation_active) printf(" - Legacy emulation is active\n");
- if (ohci->legacy_irq_enable) printf(" - Legacy IRQ enabled (IRQ1 and IRQ12)\n");
- if (ohci->legacy_external_irq_enable) printf(" - Keyboard controller IRQs cause Legacy Support emulation interrupt\n");
- if (ohci->legacy_a20_state) printf(" - Legacy A20 gate active\n");
- if (ohci->bios_is_using_it) printf(" - BIOS is using it now\n");
- if (ohci->bios_was_using_it) printf(" - BIOS was using it when we started\n");
- if (ohci->control.f.RemoteWakeupConnected) printf(" - Remote Wakeup connected\n");
- printf(" - Control Bulk Service Ratio: %u\n",ohci->control.f.ControlBulkServiceRatio);
- printf(" - Interrupt routine (to SMI): %u\n",ohci->control.f.InterruptRouting);
- printf(" - Raw control: %08lX\n",(unsigned long)(ohci->control.raw));
- printf(" - Full speed largest data packet %u\n",ohci->FullSpeedLargestDataPacket);
- printf(" - Frame interval/remain/number %u/%u/%lu Periodic start %u\n",ohci->FrameInterval,ohci->FrameRemaining,(unsigned long)ohci->FrameNumber,ohci->PeriodicStart);
- printf(" - Controller state: ");
- switch (ohci->control.f.HostControllerFunctionalState) {
- case 0: printf("Reset"); break;
- case 1: printf("Resume"); break;
- case 2: printf("Operational"); break;
- case 3: printf("Suspend"); break;
- };
- printf("\n");
-
- printf("Hit ENTER to continue. Continuation may include grabbing control of the\n");
- printf("USB controller from your BIOS, which may make your USB keyboard unresponsive.\n");
- printf("For reliability, connect a PS/2 keyboard and reboot before continuing.\n");
- printf("Hit ESC to exit\n");
- do {
- c = getch();
- if (c == 27) return 1;
- } while (c != 13);
-
- /* if the BIOS is using it then we have to request ownership */
- if (ohci->bios_is_using_it) {
- printf("Asking BIOS to relinquish control of OHCI controller...\n");
- if (usb_ohci_ci_ownership_change(ohci,0/*BIOS should release ownership*/))
- printf("Failed to change ownership.\n");
- if (ohci->bios_is_using_it)
- printf("Failed to change ownership, function succeeded but BIOS is still using it\n");
- }
-
- /* software reset the controller */
- printf("Resetting controller...\n");
- if (usb_ohci_ci_software_reset(ohci))
- printf("Controller reset failure\n");
-
- usb_old_irq = _dos_getvect(irq2int(ohci->IRQ));
- _dos_setvect(irq2int(ohci->IRQ),usb_irq);
- p8259_unmask(ohci->IRQ);
-
- printf("Resuming controller...\n");
- if (usb_ohci_ci_software_resume(ohci))
- printf("Controller resume failure\n");
-
- printf("Bringing controller online...\n");
- if (usb_ohci_ci_software_online(ohci))
- printf("Controller resume failure\n");
-
- /* we have the IRQ hooked, it's safe now to enable interrupts */
- /* NTS: Early versions of this code left the SOF interrupt enabled, which meant that at minimum the USB
- controller would fire an IRQ every 1ms. But an IRQ firing 1000 times/sec seems to cause stack overflows
- on slower machines under the DOS extender, and stack overflows on 16-bit real mode builds because of
- the overhead in checking and validating Flat Real Mode. So we leave it off. */
- usb_ohci_ci_write_reg(ohci,0x10/*HcInterruptEnable*/,0xC0000068); /* enable MIE+OC+RHSC+FNO+RD */
-
- printf(" - Controller state: ");
- switch (ohci->control.f.HostControllerFunctionalState) {
- case 0: printf("Reset"); break;
- case 1: printf("Resume"); break;
- case 2: printf("Operational"); break;
- case 3: printf("Suspend"); break;
- };
- printf("\n");
-
- usb_ohci_ci_update_root_hub_status(ohci);
-
- printf(" - Root Hub A=%08lX: %u ports, PSM=%u NPS=%u DT=%u OCPM=%u NOCP=%u POTGT=%u\n",
- (unsigned long)(ohci->RootHubDescriptor.raw.a),
- ohci->RootHubDescriptor.f.NumberDownstreamPorts,
- ohci->RootHubDescriptor.f.PowerSwitchingMode,
- ohci->RootHubDescriptor.f.NoPowerSwitching,
- ohci->RootHubDescriptor.f.DeviceType,
- ohci->RootHubDescriptor.f.OverCurrentProtectionMode,
- ohci->RootHubDescriptor.f.NoOverCurrentProtection,
- ohci->RootHubDescriptor.f.PowerOnToGoodTime);
- printf(" - Root hub B=%08lX REMOVEABLE=0x%08lX POWER=0x%08lX\n",
- (unsigned long)(ohci->RootHubDescriptor.raw.b),
- (unsigned long)(ohci->RootHubDescriptor.f.DeviceRemovable),
- (unsigned long)(ohci->RootHubDescriptor.f.PortPowerControlMask));
- printf(" - Root hub C=%08lX status LPS=%u OCI=%u DRWE=%u LPSC=%u OCIC=%u CRWE=%u\n",
- (unsigned long)(ohci->RootHubDescriptor.raw.c),
- ohci->RootHubDescriptor.f.LocalPowerStatus,
- ohci->RootHubDescriptor.f.OverCurrentIndicator,
- ohci->RootHubDescriptor.f.DeviceRemoteWakeupEnable,
- ohci->RootHubDescriptor.f.LocalPowerStatusChange,
- ohci->RootHubDescriptor.f.OverCurrentIndicatorChange,
- ohci->RootHubDescriptor.f.ClearRemoteWakeupEnable);
-
- printf("Hit ENTER to continue.\n");
- do {
- if (kbhit()) {
- c = getch();
- if (c == 13 || c == 27) break;
- }
- } while (1);
-
- if (ohci->RootHubDescriptor.f.NumberDownstreamPorts > 7)
- vga_bios_set_80x50_text();
-
- vga_menu_bar.bar = main_menu_bar;
- vga_menu_bar.sel = -1;
- vga_menu_bar.row = 1;
- vga_menu_idle = my_vga_menu_idle;
-
- main_menu();
-
- int10_setmode(3);
- update_state_from_vga();
-
- vga_clear();
- vga_moveto(0,0);
- vga_write_color(7);
- vga_sync_bios_cursor();
-
- /* restore IRQ. do NOT mask IRQ if the BIOS is involved in any way */
- _dos_setvect(irq2int(ohci->IRQ),usb_old_irq);
- if (!ohci->bios_was_using_it && !ohci->bios_is_using_it) p8259_mask(ohci->IRQ);
-
- /* shutdown process: reset the controller */
- printf("Resetting controller...\n");
- if (usb_ohci_ci_software_reset(ohci))
- printf("Controller reset failure\n");
- if (usb_ohci_ci_set_usb_reset_state(ohci))
- printf("Controller reset-state failure\n");
-
- /* if the BIOS was using it, then we have to give ownership back */
- if (ohci->bios_was_using_it) {
- printf("Giving control back to BIOS...\n");
-
- if (usb_ohci_ci_ownership_change(ohci,1/*BIOS should regain ownership*/))
- printf("Failed to change ownership.\n");
- if (!ohci->bios_is_using_it)
- printf("Failed to change ownership, function succeeded but BIOS didn't claim ownership\n");
- }
-
- ohci = usb_ohci_ci_destroy(ohci);
- return 0;
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos86c\*.*\r
-deltree /Y \r
-del /s /q dos86l\*.*\r
-deltree /Y \r
-del /s /q dos86m\*.*\r
-deltree /Y \r
-del /s /q dos86s\*.*\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos86c\r
-wmake -f ..\..\mak\dos86c.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86l\r
-wmake -f ..\..\mak\dos86l.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86m\r
-wmake -f ..\..\mak\dos86m.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos86s\r
-wmake -f ..\..\mak\dos86s.mak HPS=\ all REL=..\.. \r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ all REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-NOW_BUILDING = HW_VESA_LIB
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-
-C_SOURCE = vesa.c
-OBJS = $(SUBDIR)$(HPS)vesa.obj
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-MODESET_EXE = $(SUBDIR)$(HPS)modeset.exe
-
-!ifeq TARGET_MSDOS 16
-VESA240_EXE = $(SUBDIR)$(HPS)vesa240.exe
-!endif
-
-$(HW_VESA_LIB): $(OBJS)
- wlib -q -b -c $(HW_VESA_LIB) -+$(SUBDIR)$(HPS)vesa.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_VESA_LIB) .symbolic
-
-exe: $(TEST_EXE) $(MODESET_EXE) $(VESA240_EXE) .symbolic
-
-$(TEST_EXE): $(HW_VESA_LIB) $(HW_VESA_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(HW_FLATREAL_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)test.obj $(HW_VESA_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-$(MODESET_EXE): $(HW_VESA_LIB) $(HW_VESA_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(HW_FLATREAL_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)modeset.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)modeset.obj $(HW_VESA_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) name $(MODESET_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-!ifdef VESA240_EXE
-$(VESA240_EXE): $(HW_VESA_LIB) $(HW_VESA_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_FLATREAL_LIB) $(HW_FLATREAL_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)vesa240.obj
- %write tmp.cmd option quiet system $(WLINK_SYSTEM) file $(SUBDIR)$(HPS)vesa240.obj $(HW_VESA_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) name $(VESA240_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_VESA_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* TODO: This code needs to reject what appears to be a junk mode returned by Microsoft Virtual PC 2007
- * (mode 0x113) which reports itself as 32770 x 36866 CGA graphics mode 16-plane 1 bit/pixel and 8 banks (Ha!)
- * on the plus side the VESA BIOS doesn't let me set that mode. */
-
-/* bug fixes:
- 2011/10/21: Updated CPU detection library not to use 8086, 286, and
- v8086 detection routines when compiled as 32-bit protected
- mode code, since obviously if 32-bit code is executing the
- CPU is at least a 386. This resolves MODESET.EXE causing
- a system reboot when EMM386.EXE is resident, as the crash
- was traced to the cpu_detect().
-
- 2011/10/21: Added "single step" mode so crashes like the one described
- above can be traced to individual functions easier.
-
- 2011/10/21: Added /nd switch to allow debugging whether writing to
- VRAM is causing the crash. The switch causes MODESET to
- set the video mode, but not draw anything.
-
- 2011/10/21: Added /nwf switch which allows you to forcibly disable
- using the bank switch window function indicated by the BIOS,
- and to use instead INT 10H for bank switching. On some BIOSes,
- the 32-bit version seems unable to call it correctly and
- the drawn video ends up bunched up at the top of the screen.
- Running MODESET with /nwf seems to resolve that issue.
-*/
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/vesa/vesa.h>
-#include <hw/flatreal/flatreal.h>
-#include <hw/dos/doswin.h>
-
-static int sstep = 0; /* single step */
-
-static void help() {
- printf("modeset [options] <MODE>\n");
- printf(" /h /help This help\n");
- printf(" /l Use linear framebuffer\n");
- printf(" /b Use banked mode\n");
- printf(" /nwf Don't use direct 16-bit window function\n");
- printf(" /fwf Force using 16-bit window function\n");
- printf(" /6 Set DAC to 6-bit wide (16/256-color modes only)\n");
- printf(" /8 Set DAC to 8-bit wide (16/256-color modes only)\n");
- printf(" /s Single-step mode (hit ENTER)\n");
-}
-
-static void vbe_mode_test_pattern_svga_planar(struct vbe_mode_decision *md,struct vbe_mode_info *mi) {
- unsigned char *pal = malloc(16*4);
- unsigned long ofs;
- unsigned int x,y;
-
- /* the planar SVGA modes require VGA-style programming. init the standard VGA library */
- probe_vga();
-
- vga_write_sequencer(VGA_SC_MAP_MASK, 0xF); /* map mask register = enable all planes */
- vga_write_GC(VGA_GC_ENABLE_SET_RESET, 0x00); /* enable set/reset = no on all planes */
- vga_write_GC(VGA_GC_SET_RESET, 0x00); /* set/reset register = all zero */
- vga_write_GC(VGA_GC_BIT_MASK, 0xFF); /* all bits modified */
-
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_NONE); /* rotate=0 op=unmodified */
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 (copy CPU bits to each plane) */
-
- ofs = 0;
- for (y=0;y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x += 8) {
- vesa_writeb(ofs++,(y+x)>>3);
- }
- }
-
- while (getch() != 13);
-
- for (x=0;x < 16;x++) {
- pal[x*4+0] = x*4;
- pal[x*4+1] = x*4;
- pal[x*4+2] = x*4;
- }
-
- /* try to set DAC width */
- if (md->dac8 && (x=vbe_set_dac_width(8)) != 8) {
- vbe_reset_video_to_text();
- printf("Cannot set DAC width to 8 bits (ret=%u)\n",x);
- return;
- }
- else if (!md->dac8) {
- vbe_set_dac_width(6); /* don't care if it fails */
- }
-
- if (md->dac8) {
- for (x=0;x < 16*4;x++)
- pal[x] <<= 2;
- }
-
- /* modify the Attribute Controller since it's probably mapping indexes 8-15 to palette colors 0x38-0x3F */
- /* only then will our 16-color palette update show correctly */
- for (x=0;x < 16;x++) vga_write_AC(x,x);
- vga_AC_reenable_screen();
-
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE) {
- vesa_set_palette_data(0,16,pal);
- }
- else {
- outp(0x3C8,0);
- for (y=0;y < 16;y++) {
- outp(0x3C9,pal[y*4+0]);
- outp(0x3C9,pal[y*4+1]);
- outp(0x3C9,pal[y*4+2]);
- }
- }
-
- while (getch() != 13);
-
- for (x=0;x < 16;x++) {
- pal[x*4+0] = x*4;
- pal[x*4+1] = 0;
- pal[x*4+2] = 0;
- }
-
- if (md->dac8) {
- for (x=0;x < 16*4;x++)
- pal[x] <<= 2;
- }
-
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE) {
- vesa_set_palette_data(0,16,pal);
- }
- else {
- outp(0x3C8,0);
- for (y=0;y < 16;y++) {
- outp(0x3C9,pal[y*4+0]);
- outp(0x3C9,pal[y*4+1]);
- outp(0x3C9,pal[y*4+2]);
- }
- }
-
- while (getch() != 13);
-
- for (x=0;x < 16;x++) {
- pal[x*4+0] = 0;
- pal[x*4+1] = x*4;
- pal[x*4+2] = 0;
- }
-
- if (md->dac8) {
- for (x=0;x < 16*4;x++)
- pal[x] <<= 2;
- }
-
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE) {
- vesa_set_palette_data(0,16,pal);
- }
- else {
- outp(0x3C8,0);
- for (y=0;y < 16;y++) {
- outp(0x3C9,pal[y*4+0]);
- outp(0x3C9,pal[y*4+1]);
- outp(0x3C9,pal[y*4+2]);
- }
- }
-
- while (getch() != 13);
-
- for (x=0;x < 16;x++) {
- pal[x*4+0] = 0;
- pal[x*4+1] = 0;
- pal[x*4+2] = x*4;
- }
-
- if (md->dac8) {
- for (x=0;x < 16*4;x++)
- pal[x] <<= 2;
- }
-
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE) {
- vesa_set_palette_data(0,16,pal);
- }
- else {
- outp(0x3C8,0);
- for (y=0;y < 16;y++) {
- outp(0x3C9,pal[y*4+0]);
- outp(0x3C9,pal[y*4+1]);
- outp(0x3C9,pal[y*4+2]);
- }
- }
-
- free(pal);
- while (getch() != 13);
-
- if (!vbe_mode_decision_acceptmode(md,NULL)) {
- vbe_reset_video_to_text();
- printf("Failed to un-set up mode\n");
- }
- else {
- vbe_reset_video_to_text();
- }
-}
-
-static void vbe_mode_test_pattern_svga_packed(struct vbe_mode_decision *md,struct vbe_mode_info *mi) {
- unsigned int x,y,bypp;
- unsigned long ofs;
-
- bypp = (mi->bits_per_pixel+7)>>3;
- if (mi->bits_per_pixel == 4 && mi->number_of_planes == 1) {
- /* nonstandard packed 4-bit mode as seen on Toshiba Libretto Chips & Tech 65550 BIOS */
- unsigned char *pal = malloc(16*4);
-
- memset(pal,0,16*4);
- for (x=0;x < 16;x++) {
- pal[x*4+0] = x*4;
- pal[x*4+1] = x*4;
- pal[x*4+2] = x*4;
- }
-
- /* try to set DAC width */
- if (md->dac8 && (x=vbe_set_dac_width(8)) != 8) {
- vbe_reset_video_to_text();
- printf("Cannot set DAC width to 8 bits (ret=%u)\n",x);
- return;
- }
- else if (!md->dac8) {
- vbe_set_dac_width(6); /* don't care if it fails */
- }
-
- if (md->dac8) {
- for (x=0;x < 64;x++)
- pal[x] <<= 2;
- }
-
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE) {
- vesa_set_palette_data(0,16,pal);
- }
- else {
- outp(0x3C8,0);
- for (y=0;y < 16;y++) {
- outp(0x3C9,pal[y*4+0]);
- outp(0x3C9,pal[y*4+1]);
- outp(0x3C9,pal[y*4+2]);
- }
- }
-
- /* high nibble, low nibble */
- for (y=0;y < 32 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x += 2,ofs++) {
- vesa_writeb(ofs,(x << 4) | (x+1));
- }
- }
- for (y=32;y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x += 2,ofs++) {
- vesa_writeb(ofs,((x^y) << 4) | (((x+1)^y) & 0xF));
- }
- }
-
- free(pal);
- pal = NULL;
- }
- else if (bypp == 1) {
- unsigned char *pal = malloc(1024);
-
- memset(pal,0,1024);
- for (x=0;x < 64;x++) {
- pal[x*4+0] = x;
- pal[x*4+1] = x;
- pal[x*4+2] = x;
- }
- for (x=0;x < 64;x++) {
- pal[(x+64)*4+0] = x;
- pal[(x+64)*4+1] = 0;
- pal[(x+64)*4+2] = 0;
- }
- for (x=0;x < 64;x++) {
- pal[(x+128)*4+0] = 0;
- pal[(x+128)*4+1] = x;
- pal[(x+128)*4+2] = 0;
- }
- for (x=0;x < 64;x++) {
- pal[(x+192)*4+0] = 0;
- pal[(x+192)*4+1] = 0;
- pal[(x+192)*4+2] = x;
- }
-
- /* try to set DAC width */
- if (md->dac8 && (x=vbe_set_dac_width(8)) != 8) {
- vbe_reset_video_to_text();
- printf("Cannot set DAC width to 8 bits (ret=%u)\n",x);
- return;
- }
- else if (!md->dac8) {
- vbe_set_dac_width(6); /* don't care if it fails */
- }
-
- if (md->dac8) {
- for (x=0;x < 1024;x++)
- pal[x] <<= 2;
- }
-
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE) {
- vesa_set_palette_data(0,256,pal);
- }
- else {
- outp(0x3C8,0);
- for (y=0;y < 256;y++) {
- outp(0x3C9,pal[y*4+0]);
- outp(0x3C9,pal[y*4+1]);
- outp(0x3C9,pal[y*4+2]);
- }
- }
-
- for (y=0;y < 32 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=bypp) {
- vesa_writeb(ofs,x);
- }
- }
- for (y=32;y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=bypp) {
- vesa_writeb(ofs,x^y);
- }
- }
-
- free(pal);
- pal = NULL;
- }
- else if (bypp == 2) {
- unsigned int r,g,b;
- for (y=0;y < 16 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=2) {
- r = x & ((1 << mi->red_mask_size) - 1);
- vesa_writew(ofs,(r << mi->red_field_position));
- }
- }
- for (y=16;y < 32 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=2) {
- r = x & ((1 << mi->green_mask_size) - 1);
- vesa_writew(ofs,(r << mi->green_field_position));
- }
- }
- for (y=32;y < 48 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=2) {
- r = x & ((1 << mi->blue_mask_size) - 1);
- vesa_writew(ofs,(r << mi->blue_field_position));
- }
- }
- for (y=48;y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=2) {
- r = x & ((1 << mi->red_mask_size) - 1);
- g = y & ((1 << mi->green_mask_size) - 1);
- b = (((x >> mi->red_mask_size) ^ (y >> mi->green_mask_size)) & 1) ? (r^g) : 0;
- vesa_writew(ofs,
- (r << mi->red_field_position) |
- (g << mi->green_field_position) |
- (b << mi->blue_field_position));
- }
- }
- }
- else if (bypp == 3 || bypp == 4) {
- unsigned int r,g,b;
- for (y=0;y < 16 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=bypp) {
- r = x & ((1UL << (unsigned long)mi->red_mask_size) - 1UL);
- vesa_writed(ofs,((unsigned long)r << (unsigned long)mi->red_field_position));
- }
- }
- for (y=16;y < 32 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=bypp) {
- r = x & ((1UL << (unsigned long)mi->green_mask_size) - 1UL);
- vesa_writed(ofs,((unsigned long)r << mi->green_field_position));
- }
- }
- for (y=32;y < 48 && y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=bypp) {
- r = x & ((1UL << (unsigned long)mi->blue_mask_size) - 1UL);
- vesa_writed(ofs,((unsigned long)r << mi->blue_field_position));
- }
- }
- for (y=48;y < mi->y_resolution;y++) {
- ofs = ((unsigned long)y * (unsigned long)mi->bytes_per_scan_line);
- for (x=0;x < mi->x_resolution;x++,ofs+=bypp) {
- r = x & ((1UL << (unsigned long)mi->red_mask_size) - 1UL);
- g = y & ((1UL << (unsigned long)mi->green_mask_size) - 1UL);
- b = (((x >> mi->red_mask_size) ^ (y >> mi->green_mask_size)) & 1UL) ? (r^g) : 0UL;
- vesa_writed(ofs,
- ((unsigned long)r << (unsigned long)mi->red_field_position) |
- ((unsigned long)g << (unsigned long)mi->green_field_position) |
- ((unsigned long)b << (unsigned long)mi->blue_field_position));
- }
- }
- }
-
- while (getch() != 13);
-
- if (md->dac8 && mi->bits_per_pixel == 8 && (mi->memory_model == 4 || mi->memory_model == 6)) {
- unsigned char *pal = malloc(1024);
- unsigned int x,y;
-
- for (x=0;x < 256;x++) {
- pal[x*4+0] = x;
- pal[x*4+1] = x;
- pal[x*4+2] = x;
- pal[x*4+3] = 0;
- }
-
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE) {
- vesa_set_palette_data(0,256,pal);
- }
- else {
- outp(0x3C8,0);
- for (y=0;y < 256;y++) {
- outp(0x3C9,pal[y*4+0]);
- outp(0x3C9,pal[y*4+1]);
- outp(0x3C9,pal[y*4+2]);
- }
- }
-
- while (getch() != 13);
-
- free(pal);
- pal = NULL;
- }
-
- if (!vbe_mode_decision_acceptmode(md,NULL)) {
- vbe_reset_video_to_text();
- printf("Failed to un-set up mode\n");
- }
- else {
- vbe_reset_video_to_text();
- }
-}
-
-void sstep_wait() {
- char c;
-
- if (!sstep) return;
-
- do {
- c = 13;
- read(0,&c,1);
- } while (!(c == 13));
-}
-
-int main(int argc,char **argv) {
- struct vbe_mode_decision md;
- struct vbe_mode_info mi={0};
- int i,swi=0,no_draw=0;
-
- vbe_mode_decision_init(&md);
- for (i=1;i < argc;) {
- const char *a = argv[i++];
-
- if (*a == '-' || *a == '/') {
- do { a++; } while (*a == '-' || *a == '/');
-
- if (!strcmp(a,"h") || !strcmp(a,"help") || !strcmp(a,"?")) {
- help();
- return 1;
- }
- else if (!strcmp(a,"nwf")) {
- md.no_wf = 1;
- }
- else if (!strcmp(a,"fwf")) {
- md.force_wf = 1;
- }
- else if (!strcmp(a,"l")) {
- md.lfb = 1;
- }
- else if (!strcmp(a,"s")) {
- sstep = 1;
- }
- else if (!strcmp(a,"b")) {
- md.lfb = 0;
- }
- else if (!strcmp(a,"nd")) {
- no_draw = 1;
- }
- else if (!strcmp(a,"8")) {
- md.dac8 = 1;
- }
- else if (!strcmp(a,"6")) {
- md.dac8 = 0;
- }
- else {
- printf("I don't know what switch '%s' means\n",a);
- return 1;
- }
- }
- else {
- switch (swi++) {
- case 0:
- md.mode = (int)strtol(a,NULL,0);
- break;
- };
- }
- }
-
- printf("VESA VGA test program\n");
- if (md.mode < 0) {
- help();
- return 1;
- }
- sstep_wait();
-
- printf("cpu "); fflush(stdout);
- cpu_probe();
- sstep_wait();
- printf("dos "); fflush(stdout);
- probe_dos();
- sstep_wait();
- printf("win "); fflush(stdout);
- detect_windows();
- sstep_wait();
-
- printf("Probing bios "); fflush(stdout);
- if (!vbe_probe()) {
- printf("VESA BIOS not found\n");
- return 1;
- }
- sstep_wait();
-
- if (md.no_wf) printf("...not using direct window function\n");
-
- printf("mode "); fflush(stdout);
- sstep_wait();
- if (!vbe_read_mode_info(md.mode,&mi)) {
- printf("Cannot read mode info\n");
- return 1;
- }
- sstep_wait();
- vbe_fill_in_mode_info(md.mode,&mi);
- printf("OK\n");
- sstep_wait();
-
- if (!vbe_mode_decision_validate(&md,&mi)) {
- printf(" Parameter validation failed\n");
- return 1;
- }
- sstep_wait();
- if (!vbe_mode_decision_setmode(&md,&mi)) {
- vbe_reset_video_to_text();
- printf(" Failed to set mode\n");
- return 1;
- }
- sstep_wait();
- if (!vbe_mode_decision_acceptmode(&md,&mi)) {
- vbe_reset_video_to_text();
- printf("Failed to set up mode\n");
- return 1;
- }
- sstep_wait();
-
- if (no_draw) {
- printf("OK--No drawing!\n");
- while (getch() != 13);
- if (!vbe_mode_decision_acceptmode(&md,NULL)) {
- vbe_reset_video_to_text();
- printf("Failed to un-set up mode\n");
- return 1;
- }
- vbe_reset_video_to_text();
- }
- else if (mi.memory_model == 3)
- vbe_mode_test_pattern_svga_planar(&md,&mi);
- else if (mi.memory_model == 4 || mi.memory_model == 6)
- vbe_mode_test_pattern_svga_packed(&md,&mi);
- else {
- while (getch() != 13);
- if (!vbe_mode_decision_acceptmode(&md,NULL)) {
- vbe_reset_video_to_text();
- printf("Failed to un-set up mode\n");
- return 1;
- }
- vbe_reset_video_to_text();
- }
-
- sstep_wait();
- return 0;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/vesa/vesa.h>
-
-void printf_video_modeinfo(uint16_t mode,struct vbe_mode_info *mi) {
- printf("Mode 0x%04x:\n",mode);
- printf(" Attributes: 0x%04x ",(unsigned int)mi->mode_attributes);
- if (mi->mode_attributes & VESA_MODE_ATTR_HW_SUPPORTED)
- printf("H/W-SUPP ");
- if (mi->mode_attributes & VESA_MODE_ATTR_VBE_1X_MOREINFO)
- printf("VBE1.Xext ");
- if (mi->mode_attributes & VESA_MODE_ATTR_BIOS_TTY)
- printf("TTY ");
- if (mi->mode_attributes & VESA_MODE_ATTR_COLOR_MODE)
- printf("Color ");
- if (mi->mode_attributes & VESA_MODE_ATTR_GRAPHICS_MODE)
- printf("Graphics ");
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE)
- printf("!VGA ");
- if (mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE_WINDOWING)
- printf("!Window ");
- if (mi->mode_attributes & VESA_MODE_ATTR_LINEAR_FRAMEBUFFER_AVAILABLE)
- printf("LinFB ");
- if (mi->mode_attributes & VESA_MODE_ATTR_DOUBLESCAN_AVAILABLE)
- printf("Dblscan ");
- if (mi->mode_attributes & VESA_MODE_ATTR_INTERLACED_AVAILABLE)
- printf("Intlace ");
- if (mi->mode_attributes & VESA_MODE_ATTR_HARDWARE_TRIPLE_BUFFER_SUPPORT)
- printf("TripleBuf ");
- if (mi->mode_attributes & VESA_MODE_ATTR_HARDWARE_STEREO_SUPPORT)
- printf("Stereo ");
- if (mi->mode_attributes & VESA_MODE_ATTR_DUAL_DISPLAY_START_SUPPORT)
- printf("DualDisplay ");
- printf("\n");
- printf(" Win A Attr=0x%02x seg=0x%04x Win B Attr=0x%02x seg=0x%04x\n",
- mi->win_a_attributes,mi->win_a_segment,
- mi->win_b_attributes,mi->win_b_segment);
- printf(" Window granularity=%uKB size=%uKB function=%04x:%04x bytes/line=%u\n",
- mi->win_granularity,mi->win_size,
- (unsigned int)(mi->window_function>>16),
- (unsigned int)(mi->window_function&0xFFFF),
- mi->bytes_per_scan_line);
- printf(" %u x %u (char %u x %u) %u-plane %ubpp. %u banks. Model %u.\n",
- mi->x_resolution,mi->y_resolution,mi->x_char_size,mi->y_char_size,
- mi->number_of_planes,mi->bits_per_pixel,mi->number_of_banks,mi->memory_model);
- printf(" Model is '%s'. Bank size=%uKB. Image pages=%u\n",vbe_memory_model_to_str(mi->memory_model),
- mi->bank_size,mi->number_of_image_pages);
- printf(" RGBA (size,pos) R=(%u,%u) G=(%u,%u) B=(%u,%u) A=(%u,%u) DCModeInfo=0x%02X\n",
- mi->red_mask_size, mi->red_field_position,
- mi->green_mask_size, mi->green_field_position,
- mi->blue_mask_size, mi->blue_field_position,
- mi->reserved_mask_size, mi->reserved_field_position,
- mi->direct_color_mode_info);
- printf(" Physical addr: 0x%08lX Linbytes/scan=%u BankPages=%u LinPages=%u\n",(unsigned long)mi->phys_base_ptr,
- mi->lin_bytes_per_line, mi->bank_number_of_image_pages+1,
- mi->lin_number_of_image_pages);
- printf(" Lin RGBA (size,pos) R=(%u,%u) G=(%u,%u) B=(%u,%u) A=(%u,%u) maxpixelclock=%lu\n",
- mi->lin_red_mask_size, mi->lin_red_field_position,
- mi->lin_green_mask_size, mi->lin_green_field_position,
- mi->lin_blue_mask_size, mi->lin_blue_field_position,
- mi->lin_reserved_mask_size, mi->lin_reserved_field_position,
- mi->max_pixel_clock);
-}
-
-int main() {
- unsigned int entry;
- uint16_t mode;
- char tmp[128];
- int c;
-
- printf("VESA VGA test program\n");
- if (!vbe_probe()) {
- printf("VESA BIOS not found\n");
- return 1;
- }
-
- printf("VBE INFO:\n");
-
- *((uint32_t*)tmp) = vbe_info->signature; tmp[4] = 0;
- printf(" Signature: '%s'\n",tmp);
-
- printf(" Version: %u.%u\n",vbe_info->version >> 8,vbe_info->version & 0xFF);
-
- printf(" Capabilities: 0x%08lx\n",(unsigned long)(vbe_info->capabilities));
- if (vbe_info->capabilities & VBE_CAP_8BIT_DAC)
- printf(" 8-bit capable DAC\n");
- if (vbe_info->capabilities & VBE_CAP_NOT_VGA_COMPATIBLE)
- printf(" Not VGA compatible\n");
- if (vbe_info->capabilities & VBE_CAP_LARGE_XFER_BLANKING)
- printf(" Should blank the display during large transfers\n");
-
- printf(" Total memory: %luKB\n",(unsigned long)vbe_info->total_memory_64kb * 64UL);
- printf(" OEM software version: %u.%u\n",vbe_info->oem_software_rev >> 8,vbe_info->oem_software_rev & 0xFF);
-
- vbe_copystring(tmp,sizeof(tmp),vbe_info->oem_string_ptr,vbe_info);
- printf(" OEM string: %08lx '%s'\n",(unsigned long)(vbe_info->oem_string_ptr),tmp);
-
- vbe_copystring(tmp,sizeof(tmp),vbe_info->oem_vendor_name_ptr,vbe_info);
- printf(" OEM vendor: %08lx '%s'\n",(unsigned long)(vbe_info->oem_vendor_name_ptr),tmp);
-
- vbe_copystring(tmp,sizeof(tmp),vbe_info->oem_product_name_ptr,vbe_info);
- printf(" OEM product: %08lx '%s'\n",(unsigned long)(vbe_info->oem_product_name_ptr),tmp);
-
- vbe_copystring(tmp,sizeof(tmp),vbe_info->oem_product_rev_ptr,vbe_info);
- printf(" OEM product revision: %08lx '%s'\n",(unsigned long)(vbe_info->oem_product_rev_ptr),tmp);
-
- printf(" Video modes: @%08lx\n",(unsigned long)(vbe_info->video_mode_ptr));
- if (vbe_info->video_mode_ptr != 0UL) {
- for (entry=0;entry < 128;entry++) {
- mode = vbe_read_mode_entry(vbe_info->video_mode_ptr,entry);
- if (mode == 0xFFFF) break;
- printf("0x%04x ",mode);
- if ((entry%10) == 9) printf("\n");
- }
- printf("\n");
- }
-
- if (isatty(1) && isatty(0)) {
- while (getch() != 13);
- }
-
- if (vbe_info->video_mode_ptr != 0UL) {
- for (entry=0;entry < 128;entry++) {
- struct vbe_mode_info mi={0};
- mode = vbe_read_mode_entry(vbe_info->video_mode_ptr,entry);
- if (mode == 0xFFFF) break;
-
- if (vbe_read_mode_info(mode,&mi))
- printf_video_modeinfo(mode,&mi);
- else
- printf("Cannot get info on mode 0x%04x\n",mode);
-
- if (isatty(1) && isatty(0)) {
- while ((c=getch()) != 13) {
- if (c == 27) return 1;
- }
- }
- }
- }
-
- /* and the VBE 2.x mode 0x81FF? */
- {
- struct vbe_mode_info mi={0};
-
- mode = 0x81FF;
- if (vbe_read_mode_info(mode,&mi))
- printf_video_modeinfo(mode,&mi);
- }
-
- return 0;
-}
-
+++ /dev/null
-
-/* Test VBE scenarios:
- *
- * Setup Real B L Prot B L
- * --------------------------------------------------------------------
- * DOSBox 0.74 (machine=svga_s3)
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 16-color modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y Y
- * 16-color 5:5:5 modes YES Y Y YES Y Y
- * 16-color 5:6:5 modes YES Y Y YES Y Y
- * 24bpp 8:8:8 modes N/A N/A DOSBox does not emulate 24bpp VBE modes
- * 32bpp 8:8:8:8 modes YES Y Y YES Y Y
- * 8-bit DAC modes N/A N/A DOSBox does not emulate 8-bit DAC support
- * DOSBox 0.74 (machine=vesa_oldvbe)
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 16-color modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y Y
- * 16-color 5:5:5 modes YES Y Y YES Y Y
- * 16-color 5:6:5 modes YES Y Y YES Y Y
- * 24bpp 8:8:8 modes N/A N/A DOSBox does not emulate 24bpp VBE modes
- * 32bpp 8:8:8:8 modes YES Y Y YES Y Y
- * 8-bit DAC modes N/A N/A DOSBox does not emulate 8-bit DAC support
- * DOSBox 0.74 (machine=vesa_nolfb)
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 16-color modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y Y
- * 16-color 5:5:5 modes YES Y Y YES Y Y
- * 16-color 5:6:5 modes YES Y Y YES Y Y
- * 24bpp 8:8:8 modes N/A N/A DOSBox does not emulate 24bpp VBE modes
- * 32bpp 8:8:8:8 modes YES Y Y YES Y Y
- * 8-bit DAC modes N/A N/A DOSBox does not emulate 8-bit DAC support
- * DOSBox 0.74 (machine=svga_s3) + Microsoft Windows 3.0 Real Mode
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 256-color modes YES Y N YES N Y Real mode: fails to setup mode. Protected mode: bank switching doesn't work?
- * DOSBox 0.74 (machine=svga_s3) + Microsoft Windows 3.0 Standard Mode.
- * - Protected mode version of this program does not run, DOS extender complains about not having any memory to run it
- * Detection YES Y Y YES N N
- * OEM strings YES Y Y YES N N
- * Enumeration of modes YES Y Y YES N N
- * 256-color modes YES Y N YES N N Real mode: fails to setup mode.
- * DOSBox 0.74 (machine=svga_s3) + Microsoft Windows 3.0 386 Enhanced Mode
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y N DOSBox exits with error "TSS not busy". Hm..
- * DOSBox 0.74 (machine=svga_s3) + Microsoft Windows 3.1 Standard Mode.
- * - Protected mode version of this program does not run, DOS extender complains about not having any memory to run it
- * Detection YES Y Y YES N N
- * OEM strings YES Y Y YES N N
- * Enumeration of modes YES Y Y YES N N
- * 256-color modes YES Y N YES N N Real mode: fails to setup mode.
- * DOSBox 0.74 (machine=svga_s3) + Microsoft Windows 3.1 386 Enhanced Mode
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y N DOSBox exits with error "TSS not busy". Hm..
- * QEMU + Microsoft Windows 95 (4.00.950) Native DOS
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y Y
- * 8-bit DAC YES Y Y YES Y Y
- * QEMU + Microsoft Windows 95 (4.00.950) Normal
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y Y
- * 8-bit DAC YES Y Y YES Y Y
- * QEMU + Microsoft Windows ME (4.90.3000) Normal
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y
- * 256-color modes YES Y Y YES Y Y
- * 8-bit DAC YES Y Y YES Y Y
- * VirtualBox + Microsoft Windows 2000 Professional
- * Detection YES Y Y YES Y Y NTVDM.EXE apparently blocks VESA BIOS calls unless the DOS window is fullscreen.
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y?Y? YES Y?Y? I got it to enumerate modes... once. Then it crashed, and next boot NTVDM.EXE
- * is apparently blocking the modelist.
- * 256-color modes YES N N YES N N NTVDM.EXE's meddling with the VESA modelist screws up the test. It also seems
- * to confuse the VESA bios. Bank switching doesn't work. Linear framebuffer
- * modes don't work properly. The test scribbles gibberish on the screen, then
- * Windows 2000 hard crashes and reboots. Epic fail.
- * 8-bit DAC YES N N YES N N NTVDM.EXE appears to block 8-bit DAC calls, but otherwise pass through
- * flags stating that it's supported
- * VirtualBox + Microsoft Windows XP Professional
- * Detection YES Y Y YES Y Y NTVDM.EXE automatically switches the DOS box to fullscree in response.
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y?Y? YES Y?Y? I got it to enumerate modes... once. Then it crashed, and next boot NTVDM.EXE
- * is apparently blocking the modelist.
- * 256-color modes YES N N YES N N NTVDM.EXE's meddling with the VESA modelist screws up the test. It also seems
- * to confuse the VESA bios. Bank switching doesn't work. Linear framebuffer
- * modes don't work properly. The test scribbles gibberish on the screen, then
- * Windows XP hard crashes and reboots. Epic fail.
- * 8-bit DAC YES N N YES N N NTVDM.EXE appears to block 8-bit DAC calls, but otherwise pass through
- * flags stating that it's supported
- * Pentium Pro system + Trident TD8900D ISA SVGA hardware (ISA, 1993)
- * Detection YES Y Y YES Y Y VBE 1.2 compliant
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y For some reason, VESA BIOS reports 16bpp/24bpp modes when the card only goes up to 256-color modes.
- * 256-color modes YES Y Y YES Y Y
- * 8-bit DAC YES N N YES N N The card does not support 8-bit DAC output
- * - It is the older ISA variety that does not offer a linear framebuffer (bank-switching only)
- * - It also offers some SVGA alphanumeric modes
- * - It seems to map 800 x 600 x 16-color planar to mode 0x6A, while other VESA modes are >= 0x100. This is reported by the BIOS during mode enumeration.
- * - If asked to set 16bpp/24bpp modes the BIOS will program parameters that the chipset doesn't support, leaving you with a garbled 256-color display.
- * - Programming 24bpp mode and then writing to bank-switched RAM causes the computer to hang
- * Toshiba Libretto 50CT laptop + Chips & Tech 65550 (800x600 laptop LCD display)
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y Like most laptop BIOSes, lists modes > 800x600 but does not permit setting them unless external VGA is available.
- * 256-color modes YES Y Y YES Y Y
- * 8-bit DAC YES N N YES N N Does not support 8-bit DAC output (understandable, LCDs then were often dithered 5-6 bit RGB)
- * - Supports banked and linear framebuffers
- * - Supports 16-color 4-planar SVGA modes
- * - Supports 256-color, 16bpp and 24bpp modes
- * - For whatever interesting reason, the chipset also supports a packed 16-color mode (planes=1 bits_per_pixel=4).
- * Perhaps as a way of allowing 16-color graphics without needing legacy VGA planar I/O. As you'd expect, 4-bit
- * quantities are packed two to a byte, and index a 16-color CLUT. Unlike the planar modes, reprogramming the
- * attribute controller to 1:1 mapping is not necessary. The order appears to be high nibble first, then low nibble.
- * Toshiba Sattelite Pro 465CDX laptop + Chips & Tech 65554 (800x600 laptop LCD display)
- * Detection YES Y Y YES Y Y
- * OEM strings YES Y Y YES Y Y
- * Enumeration of modes YES Y Y YES Y Y Like most laptop BIOSes, lists modes > 800x600 but does not permit setting them unless external VGA is available.
- * 256-color modes YES Y Y YES Y Y
- * 8-bit DAC YES N N YES N N Does not support 8-bit DAC output (understandable, LCDs then were often dithered 5-6 bit RGB)
- * - Lacks the 4-bit packed mode the Libretto offered :(
- * - Unrelated ISA PnP test code note: Holy crap I actually found a BIOS that actually supporst the "power off" message. And it works :)
-
-*/
-
-/* TODO: Some of your laptops SVGA cards support a packed 16-color mode (planes=1 bits/pixel=4). Write a routine to target that mode.
- * Test it on the Libretto laptop to be sure. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/vesa/vesa.h>
-#include <hw/flatreal/flatreal.h>
-#include <hw/dos/doswin.h>
-
-#if TARGET_MSDOS == 32
-void vbe_realbnk(struct dpmi_realmode_call *rc) {
- if (dpmi_no_0301h > 0) {
- /* Fuck you DOS4/GW! */
- dpmi_alternate_rm_call(rc);
- }
- else {
- __asm {
- mov ax,0x0301
- xor bx,bx
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
- }
-}
-
-void vbe_realint(struct dpmi_realmode_call *rc) {
- __asm {
- mov ax,0x0300
- mov bx,0x0010
- xor cx,cx
- mov edi,rc ; we trust Watcom has left ES == DS
- int 0x31 ; call DPMI
- }
-}
-
-/* the VBE interface is realmode so we need a DOS segment to bounce data through */
-static unsigned char* vbe_dos_buffer = NULL;
-static uint16_t vbe_dos_buffer_selector = 0;
-#endif
-
-uint32_t vesa_lfb_base = 0;
-uint32_t vesa_bnk_rproc = 0;
-uint8_t vesa_bnk_window = 0; /* which window to use */
-uint16_t vesa_bnk_winseg = 0;
-uint16_t vesa_bnk_winshf = 0; /* window granularity shift value NOT window size */
-uint16_t vesa_bnk_winszshf = 0; /* window size shift value NOT window size */
-uint16_t vesa_bnk_wincur = 0;
-
-#if TARGET_MSDOS == 32
-void* vesa_lfb_dpmi_map = NULL;
-size_t vesa_lfb_dpmi_map_size = 0;
-uint8_t vesa_lfb_dpmi_pam = 0; /* set to 1: used DPMI function 0x0800 to obtain the pointer */
-/* TODO: what if we have to use the "alloc/map device linear pages" 1.0 API */
-#endif
-
-void (*vesa_writeb)(uint32_t ofs,uint8_t b) = NULL;
-void (*vesa_writew)(uint32_t ofs,uint16_t b) = NULL;
-void (*vesa_writed)(uint32_t ofs,uint32_t b) = NULL;
-
-struct vbe_info_block* vbe_info = NULL;
-
-void vbe_free() {
- if (vbe_info) free(vbe_info);
- vbe_info = NULL;
-
-#if TARGET_MSDOS == 32
- if (vbe_dos_buffer != NULL) dpmi_free_dos(vbe_dos_buffer_selector);
- vbe_dos_buffer_selector = 0;
- vbe_dos_buffer = NULL;
-#endif
-}
-
-int vbe_probe() {
- unsigned int retv = 0;
-
-#if TARGET_MSDOS == 32
- /* WAIT! We might be running under DOS4/GW which does not implement
- function 0301H: Call real-mode subroutine. If that is true, then
- we cannot use the window bank switching routine provided by the
- BIOS */
- if (dpmi_no_0301h < 0) probe_dpmi();
-#endif
-
- vbe_free();
-
- vbe_info = malloc(sizeof(struct vbe_info_block));
- if (vbe_info == NULL) return 0;
- memset(vbe_info,0,sizeof(*vbe_info));
-
- /* you can get VBE2 extensions by setting the signature now */
- vbe_info->signature = *((const uint32_t*)("VBE2"));
-
-#if TARGET_MSDOS == 32
- vbe_dos_buffer = dpmi_alloc_dos(VBE_DOS_BUFFER_SIZE,&vbe_dos_buffer_selector);
- if (vbe_dos_buffer == NULL) {
- vbe_free();
- return 0;
- }
-
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4F00;
- memcpy(vbe_dos_buffer,vbe_info,sizeof(struct vbe_info_block));
- rc.edi = ((size_t)vbe_dos_buffer) & 0xF;
- rc.es = ((size_t)vbe_dos_buffer) >> 4;
- vbe_realint(&rc);
- retv = rc.eax & 0xFFFF;
- if ((retv >> 8) == 0) {
- uint32_t ofs;
-
- memcpy(vbe_info,vbe_dos_buffer,sizeof(struct vbe_info_block));
- /* more often than not the VESA BIOS copies it's strings into the "reserved" area
- * of our struct then writes the memory address of it there. unforunately this
- * realmode buffer is not the final destination, so we need to translate them.
- * the string reading code understands that if the segment portion is zero, then
- * the offset is relative to the vbe info struct.
- *
- * this kind of hackery is why we have accessor functions for the data... :( */
- ofs = (((uint32_t)vbe_info->oem_string_ptr >> 16UL) << 4UL) + ((uint32_t)vbe_info->oem_string_ptr & 0x1FF);
- if (ofs >= (uint32_t)vbe_dos_buffer && ofs < ((uint32_t)vbe_dos_buffer + 512))
- vbe_info->oem_string_ptr = ofs - (uint32_t)vbe_dos_buffer;
-
- ofs = (((uint32_t)vbe_info->oem_vendor_name_ptr >> 16UL) << 4UL) + ((uint32_t)vbe_info->oem_vendor_name_ptr & 0x1FF);
- if (ofs >= (uint32_t)vbe_dos_buffer && ofs < ((uint32_t)vbe_dos_buffer + 512))
- vbe_info->oem_vendor_name_ptr = ofs - (uint32_t)vbe_dos_buffer;
-
- ofs = (((uint32_t)vbe_info->oem_product_name_ptr >> 16UL) << 4UL) + ((uint32_t)vbe_info->oem_product_name_ptr & 0x1FF);
- if (ofs >= (uint32_t)vbe_dos_buffer && ofs < ((uint32_t)vbe_dos_buffer + 512))
- vbe_info->oem_product_name_ptr = ofs - (uint32_t)vbe_dos_buffer;
-
- ofs = (((uint32_t)vbe_info->oem_product_rev_ptr >> 16UL) << 4UL) + ((uint32_t)vbe_info->oem_product_rev_ptr & 0x1FF);
- if (ofs >= (uint32_t)vbe_dos_buffer && ofs < ((uint32_t)vbe_dos_buffer + 512))
- vbe_info->oem_product_rev_ptr = ofs - (uint32_t)vbe_dos_buffer;
-
- /* the mode list might be stuck in the reserved section too. the VBE standard says that's perfectly fine. so we gotta deal with it */
- ofs = (((uint32_t)vbe_info->video_mode_ptr >> 16UL) << 4UL) + ((uint32_t)vbe_info->video_mode_ptr & 0x1FF);
- if (ofs >= (uint32_t)vbe_dos_buffer && ofs < ((uint32_t)vbe_dos_buffer + 512))
- vbe_info->video_mode_ptr = ofs - (uint32_t)vbe_dos_buffer;
- }
- }
-#else
- {
- const unsigned int s = FP_SEG(vbe_info);
- const unsigned int o = FP_OFF(vbe_info);
- __asm {
- push es
- mov ax,0x4F00
- mov di,s
- mov es,di
- mov di,o
- int 0x10
- pop es
- mov retv,ax
- }
-
- /* WARNING: Our buffer is filled with the information. But some of the information involves pointers
- * to strings stuck in the reserved section. If we move the structure, then those pointers
- * become invalid. We normally don't move the structure, so it should be fine unless for
- * whatever reason the caller does it for us. */
- }
-#endif
- if ((retv >> 8) != 0 || (retv & 0xFF) != 0x4F) { /* AH = 0x00 && AL = 0x4F */
- vbe_free();
- return 0;
- }
-
- return 1;
-}
-
-void vbe_copystring(char *s,size_t max,uint32_t rp,struct vbe_info_block *b) {
- s[0] = 0; if (rp == 0 || max < 2) return; s[max-1] = 0;
-#if TARGET_MSDOS == 32
- if ((rp>>16) == 0) /* HACK: Any strings returned to us in the reserved section are translated to 0000:offset format */
- memcpy(s,(char*)vbe_info + (rp&0x1FF),max-1);
- else
- memcpy(s,(char*)((((unsigned long)(rp >> 16UL)) << 4UL) + ((unsigned long)rp & 0xFFFFUL)),max-1);
-#else
- _fmemcpy((char far*)s,MK_FP(rp>>16,rp&0xFFFF),max-1);
-#endif
-}
-
-uint16_t vbe_read_mode_entry(uint32_t mode_ptr,unsigned int entry) {
-#if TARGET_MSDOS == 32
- uint16_t *ptr;
- if ((mode_ptr>>16) == 0) /* HACK: The VESA BIOS probably stuck it in the "reserved" section, so fetch it from our copy */
- ptr = (uint16_t*)((char*)vbe_info + (mode_ptr&0x1FF));
- else
- ptr = (uint16_t*)(((mode_ptr >> 16UL) << 4UL) + (mode_ptr & 0xFFFF));
- return ptr[entry];
-#else
- uint16_t far *ptr = MK_FP(mode_ptr>>16,mode_ptr&0xFFFF);
- return ptr[entry];
-#endif
-}
-
-const char *vbe_memory_model_to_str(uint8_t m) {
- switch (m) {
- case 0x00: return "Text";
- case 0x01: return "CGA graphics";
- case 0x02: return "Hercules graphics";
- case 0x03: return "Planar";
- case 0x04: return "Packed";
- case 0x05: return "Unchained 4/256-color";
- case 0x06: return "Direct color";
- case 0x07: return "YUV";
- };
- return "?";
-}
-
-int vbe_read_mode_info(uint16_t mode,struct vbe_mode_info *mi) {
-#if TARGET_MSDOS == 32
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4F01;
- rc.ecx = mode;
- rc.edi = (uint32_t)vbe_dos_buffer & 0xF;
- rc.es = (uint32_t)vbe_dos_buffer >> 4;
- memset(vbe_dos_buffer,0,256);
- vbe_realint(&rc);
- if (((rc.eax >> 8) & 0xFF) == 0) {
- memcpy((char*)mi,(char*)vbe_dos_buffer,sizeof(*mi));
- return 1;
- }
- return 0;
-#else
- int retv = 0;
- const unsigned int s = FP_SEG(mi);
- const unsigned int o = FP_OFF(mi);
-
- memset(mi,0,sizeof(*mi));
- __asm {
- push es
- mov ax,0x4F01
- mov cx,mode
- mov di,s
- mov es,di
- mov di,o
- int 0x10
- pop es
- mov retv,ax
- }
-
- return (retv >> 8) == 0;
-#endif
-}
-
-int vbe_fill_in_mode_info(uint16_t mode,struct vbe_mode_info *mi) {
- if (mi->bank_size == 0 && mi->win_granularity != 0)
- mi->bank_size = mi->win_granularity;
-
- return 1;
-}
-
-int vbe_set_mode(uint16_t mode,struct vbe_mode_custom_crtc_info *ci) {
-#if TARGET_MSDOS == 32
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4F02;
- rc.ebx = mode;
- rc.edi = (uint32_t)vbe_dos_buffer & 0xF;
- rc.es = (uint32_t)vbe_dos_buffer >> 4;
- memcpy(vbe_dos_buffer,ci,sizeof(*ci));
- vbe_realint(&rc);
- return (((rc.eax >> 8) & 0xFF) == 0);
-#else
- int retv = 0;
- const unsigned int s = FP_SEG(ci);
- const unsigned int o = FP_OFF(ci);
-
- __asm {
- push es
- mov ax,0x4F02
- mov bx,mode
- mov di,s
- mov es,di
- mov di,o
- int 0x10
- pop es
- mov retv,ax
- }
-
- return (retv >> 8) == 0;
-#endif
-}
-
-void vbe_bank_switch(uint32_t rproc,uint8_t window,uint8_t bank) {
-#if TARGET_MSDOS == 32
- if (rproc == 0) {
- __asm {
- mov ax,0x4F05
- mov bl,window
- xor bh,bh
- mov dl,bank
- xor dh,dh
- int 0x10
- }
- }
- else {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4F05;
- rc.ebx = ((uint32_t)window & 0xFFUL);
- rc.edx = ((uint32_t)bank & 0xFFUL);
- rc.cs = (uint16_t)(rproc >> 16UL);
- rc.ip = (uint16_t)(rproc & 0xFFFF);
- vbe_realbnk(&rc);
- }
-#else
- if (rproc == 0) {
- __asm {
- mov ax,0x4F05
- mov bl,window
- xor bh,bh
- mov dl,bank
- xor dh,dh
- int 0x10
- }
- }
- else {
- __asm {
- mov ax,0x4F05
- mov bl,window
- xor bh,bh
- mov dl,bank
- xor dh,dh
- call dword ptr [rproc]
- }
- }
-#endif
-}
-
-int vbe_set_dac_width(int w) {
- signed short int retv = 6;
-
- if (w < 1) w = 6;
- if (w > 8) w = 8;
-
- __asm {
- mov ax,0x4F08
- xor bl,bl
- mov bh,byte ptr w
- int 0x10
- cmp ah,0
- jnz cnt
- mov byte ptr retv,bh
-cnt:
- }
-
- return retv;
-}
-
-void vesa_set_palette_data(unsigned int first,unsigned int count,char *pal) {
- if (count > 256) count = 256;
- if (count == 0) return;
-
-#if TARGET_MSDOS == 32
- {
- struct dpmi_realmode_call rc={0};
- rc.eax = 0x4F09;
- rc.ebx = 0;
- rc.ecx = count;
- rc.edx = first;
- rc.edi = (uint32_t)vbe_dos_buffer & 0xF;
- rc.es = (uint32_t)vbe_dos_buffer >> 4;
- memcpy(vbe_dos_buffer,pal,count*4);
- vbe_realint(&rc);
- }
-#else
- {
- const unsigned int s = FP_SEG(pal);
- const unsigned int o = FP_OFF(pal);
- __asm {
- push es
- mov ax,0x4F09
- xor bx,bx
- mov cx,count
- mov dx,first
- mov di,s
- mov es,di
- mov di,o
- int 0x10
- pop es
- }
- }
-#endif
-}
-
-void vesa_lfb_writeb(uint32_t ofs,uint8_t b) {
-#if TARGET_MSDOS == 32
- *((uint8_t*)((char*)vesa_lfb_dpmi_map+ofs)) = b;
-#else
- flatrealmode_writeb(vesa_lfb_base+ofs,b);
-#endif
-}
-
-void vesa_lfb_writew(uint32_t ofs,uint16_t b) {
-#if TARGET_MSDOS == 32
- *((uint16_t*)((char*)vesa_lfb_dpmi_map+ofs)) = b;
-#else
- flatrealmode_writew(vesa_lfb_base+ofs,b);
-#endif
-}
-
-void vesa_lfb_writed(uint32_t ofs,uint32_t b) {
-#if TARGET_MSDOS == 32
- *((uint32_t*)((char*)vesa_lfb_dpmi_map+ofs)) = b;
-#else
- flatrealmode_writed(vesa_lfb_base+ofs,b);
-#endif
-}
-
-void vesa_bnk_writeb(uint32_t ofs,uint8_t b) {
- uint8_t bnk = (uint8_t)(ofs >> vesa_bnk_winshf);
- if (bnk != vesa_bnk_wincur) vbe_bank_switch(vesa_bnk_rproc,vesa_bnk_window,vesa_bnk_wincur=bnk);
-#if TARGET_MSDOS == 32
- *((uint8_t*)((vesa_bnk_winseg << 4) + (ofs & ((1 << (unsigned long)vesa_bnk_winshf) - 1)))) = b;
-#else
- *((uint8_t far*)MK_FP(vesa_bnk_winseg,(uint16_t)(ofs & ((1UL << (unsigned long)vesa_bnk_winshf) - 1UL)))) = b;
-#endif
-}
-
-void vesa_bnk_writew(uint32_t ofs,uint16_t b) {
- uint8_t bnk = (uint8_t)(ofs >> vesa_bnk_winshf);
- if (bnk != vesa_bnk_wincur) vbe_bank_switch(vesa_bnk_rproc,vesa_bnk_window,vesa_bnk_wincur=bnk);
-#if TARGET_MSDOS == 32
- *((uint16_t*)((vesa_bnk_winseg << 4) + (ofs & ((1 << (unsigned long)vesa_bnk_winshf) - 1)))) = b;
-#else
- *((uint16_t far*)MK_FP(vesa_bnk_winseg,(uint16_t)(ofs & ((1UL << (unsigned long)vesa_bnk_winshf) - 1UL)))) = b;
-#endif
-}
-
-void vesa_bnk_writed(uint32_t ofs,uint32_t b) {
- uint8_t bnk = (uint8_t)(ofs >> vesa_bnk_winshf);
- if (bnk != vesa_bnk_wincur) vbe_bank_switch(vesa_bnk_rproc,vesa_bnk_window,vesa_bnk_wincur=bnk);
-#if TARGET_MSDOS == 32
- *((uint32_t*)((vesa_bnk_winseg << 4) + (ofs & ((1 << (unsigned long)vesa_bnk_winshf) - 1)))) = b;
-#else
- *((uint32_t far*)MK_FP(vesa_bnk_winseg,(uint16_t)(ofs & ((1UL << (unsigned long)vesa_bnk_winshf) - 1UL)))) = b;
-#endif
-}
-
-void vbe_reset_video_to_text() {
- __asm {
- mov ax,3
- int 0x10
- }
-}
-
-void vbe_mode_decision_init(struct vbe_mode_decision *m) {
- m->force_wf = 0;
- m->no_wf = 0;
- m->mode = -1;
- m->dac8 = -1;
- m->lfb = -1;
-}
-
-int vbe_mode_decision_validate(struct vbe_mode_decision *md,struct vbe_mode_info *mi) {
- /* general rule of thumb: if the mode involves is a planar VGA 16-color type, then you generally DONT want to
- * use the linear framebuffer. Most SVGA cards limit VGA read/write emulation to the legacy 0xA0000-0xAFFFF
- * area only. Most BIOSes (correctly) do not allow you to use linear framebuffer modes with planar SVGA
- * but there are some implementations that will. On these incorrect implementations, attempts to write the
- * linear framebuffer VGA style will generate only gibberish.
- * - DOSBox 0.74 [correct] 16-color SVGA modes require banked SVGA modes
- * - Microsoft Virtual PC 2007 [*WRONG*] 16-color SVGA modes allow linear framebuffer,
- * but doesn't emulate VGA read/write latch system when accessed through linear framebuffer.
- * also their 1024x768 and 1280x1024 16-color modes are broken */
- if (mi->memory_model == 3 && (mi->bits_per_pixel == 4 || mi->number_of_planes == 4) &&
- !(mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE_WINDOWING)) {
- if (md->lfb < 0) md->lfb = 0;
- else if (md->lfb == 1) return 0;
- }
- if (!(mi->mode_attributes & VESA_MODE_ATTR_LINEAR_FRAMEBUFFER_AVAILABLE) || mi->phys_base_ptr == 0) {
- if (md->lfb < 0) md->lfb = 0;
- else if (md->lfb == 1) return 0;
- }
- if ((mi->mode_attributes & VESA_MODE_ATTR_NOT_VGA_COMPATIBLE_WINDOWING) || mi->win_a_segment == 0 || mi->win_a_segment == 0xFFFF) {
- if (md->lfb < 0) md->lfb = 1;
- else if (md->lfb == 1) return 0;
- }
-
-#if TARGET_MSDOS == 16
- /* the linear framebuffer is often above the 1MB mark, so if we're on a 286 or lower we can't reach it */
- /* even on a 386 or higher there are plenty of scenarios where flat real mode might not be available.
- * in those scenarios we cannot offer LFB modes */
- if (!flatrealmode_allowed() || cpu_basic_level < 3) {
- if (md->lfb < 0) md->lfb = 0;
- else if (md->lfb == 1) return 0;
- }
-#endif
-
- /* 16-color planar modes: if the bios announces 8-bit DAC support it's quite
- * possible it still won't enable it even though the call doesn't return an
- * error code. VirtualBox does this for example. */
- if (mi->memory_model == 3 && (mi->bits_per_pixel == 4 || mi->number_of_planes == 4)) {
- if (md->dac8 < 0) md->dac8 = 0;
- else if (md->dac8 == 1) return 0;
- }
-
- if (md->dac8 < 0)
- md->dac8 = (vbe_info->capabilities & VBE_CAP_8BIT_DAC) ? 1 : 0;
-
- return 1;
-}
-
-int vbe_mode_decision_setmode(struct vbe_mode_decision *md,struct vbe_mode_info *mi) {
- int ok = 0;
- if (!ok && (md->lfb == -1 || md->lfb == 1)) { ok = vbe_set_mode(md->mode | VBE_MODE_LINEAR,NULL); md->lfb = 1; }
- if (!ok && (md->lfb == -1 || md->lfb == 0)) { ok = vbe_set_mode(md->mode,NULL); md->lfb = 0; }
- return ok;
-}
-
-int vbe_mode_decision_acceptmode(struct vbe_mode_decision *md,struct vbe_mode_info *mi) {
-#if TARGET_MSDOS == 32
- if (vesa_lfb_dpmi_map != NULL) {
- if (vesa_lfb_dpmi_pam) dpmi_phys_addr_free(vesa_lfb_dpmi_map);
- vesa_lfb_dpmi_map = NULL;
- }
- vesa_lfb_dpmi_map_size = 0;
- vesa_lfb_dpmi_pam = 0;
-#endif
-
- if (mi == NULL)
- return 1;
-
-#if TARGET_MSDOS == 16
- if (md->lfb) { /* for real-mode to access the linear framebuffer we'll need to init flat real mode */
- if (flatrealmode_allowed()) {
- if (!flatrealmode_ok() && !flatrealmode_setup(FLATREALMODE_4GB))
- return 0;
- }
- else {
- return 0;
- }
- }
-#else
- if (md->lfb) {
- /* in protected mode, we need to ask the DPMI server what linear memory address to use
- * to access the VESA framebuffer */
- /* TODO: Does this work under Windows 95/98/ME?
- * Does this also work under Windows 2000/XP? */
- vesa_lfb_dpmi_map_size = (unsigned long)mi->bytes_per_scan_line * (unsigned long)mi->y_resolution;
- if (vesa_lfb_dpmi_map_size < 4096 || vesa_lfb_dpmi_map_size > (64UL * 1024UL * 1024UL)) return 0;
- if (mi->phys_base_ptr == 0 || mi->phys_base_ptr == 0xFFFFFFFFUL) return 0;
- vesa_lfb_dpmi_map = (void*)dpmi_phys_addr_map(mi->phys_base_ptr,vesa_lfb_dpmi_map_size);
- if (vesa_lfb_dpmi_map != NULL)
- vesa_lfb_dpmi_pam = 1;
- else
- return 0;
- }
-#endif
-
- if (md->lfb) {
- vesa_lfb_base = mi->phys_base_ptr;
- vesa_writeb = vesa_lfb_writeb;
- vesa_writew = vesa_lfb_writew;
- vesa_writed = vesa_lfb_writed;
- }
- else {
- vesa_bnk_window = 0; /* TODO */
- vesa_bnk_winseg = mi->win_a_segment;
- switch (mi->win_granularity) {
- case 1: vesa_bnk_winshf = 10; break;
- case 2: vesa_bnk_winshf = 11; break;
- case 4: vesa_bnk_winshf = 12; break;
- case 8: vesa_bnk_winshf = 13; break;
- case 16: vesa_bnk_winshf = 14; break;
- case 32: vesa_bnk_winshf = 15; break;
- case 64: vesa_bnk_winshf = 16; break;
- case 128: vesa_bnk_winshf = 17; break;
- default: vesa_bnk_winshf = 14; break;
- }
- switch (mi->win_size) {
- case 1: vesa_bnk_winszshf = 10; break;
- case 2: vesa_bnk_winszshf = 11; break;
- case 4: vesa_bnk_winszshf = 12; break;
- case 8: vesa_bnk_winszshf = 13; break;
- case 16: vesa_bnk_winszshf = 14; break;
- case 32: vesa_bnk_winszshf = 15; break;
- case 64: vesa_bnk_winszshf = 16; break;
- case 128: vesa_bnk_winszshf = 17; break;
- default: vesa_bnk_winszshf = 14; break;
- }
-
- /* sanity check: window SIZE cannot be smaller than window GRANULARITY */
- if (vesa_bnk_winszshf < vesa_bnk_winshf)
- vesa_bnk_winszshf = vesa_bnk_winshf;
-
- vesa_bnk_wincur = 0xFF;
- vesa_bnk_rproc = md->no_wf ? 0UL : mi->window_function;
- vesa_writeb = vesa_bnk_writeb;
- vesa_writew = vesa_bnk_writew;
- vesa_writed = vesa_bnk_writed;
- }
-
- return 1;
-}
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-/* DAC can do 8-bit color */
-#define VBE_CAP_8BIT_DAC (1 << 0)
-/* controller is NOT VGA compatible */
-#define VBE_CAP_NOT_VGA_COMPATIBLE (1 << 1)
-/* RAMDAC recommended blanking during large data transfers (in other words: an older SVGA controller that is single ported and can cause "snow" on screen if RAM is written during active display----same problem as the IBM Color Graphics Adapter) */
-#define VBE_CAP_LARGE_XFER_BLANKING (1 << 2)
-
-#define VESA_MODE_ATTR_HW_SUPPORTED (1 << 0)
-#define VESA_MODE_ATTR_VBE_1X_MOREINFO (1 << 1)
-#define VESA_MODE_ATTR_BIOS_TTY (1 << 2)
-#define VESA_MODE_ATTR_COLOR_MODE (1 << 3)
-#define VESA_MODE_ATTR_GRAPHICS_MODE (1 << 4)
-#define VESA_MODE_ATTR_NOT_VGA_COMPATIBLE (1 << 5)
-#define VESA_MODE_ATTR_NOT_VGA_COMPATIBLE_WINDOWING (1 << 6)
-#define VESA_MODE_ATTR_LINEAR_FRAMEBUFFER_AVAILABLE (1 << 7)
-#define VESA_MODE_ATTR_DOUBLESCAN_AVAILABLE (1 << 8)
-#define VESA_MODE_ATTR_INTERLACED_AVAILABLE (1 << 9)
-#define VESA_MODE_ATTR_HARDWARE_TRIPLE_BUFFER_SUPPORT (1 << 10)
-#define VESA_MODE_ATTR_HARDWARE_STEREO_SUPPORT (1 << 11)
-#define VESA_MODE_ATTR_DUAL_DISPLAY_START_SUPPORT (1 << 12)
-
-#if TARGET_MSDOS == 32
-# define VBE_DOS_BUFFER_SIZE 4096
-#endif
-
-#pragma pack(push,1)
-struct vbe_info_block { /* for 1.x (256-byte) or 2.x/3.x (512-byte) */
- uint32_t signature; /* +0x000 'VESA' */
- uint16_t version; /* +0x004 */
- uint32_t oem_string_ptr; /* +0x006 */
- uint32_t capabilities; /* +0x00A */
- uint32_t video_mode_ptr; /* +0x00E */
- uint16_t total_memory_64kb; /* +0x012 */
- uint16_t oem_software_rev; /* +0x014 */
- uint32_t oem_vendor_name_ptr; /* +0x016 */
- uint32_t oem_product_name_ptr; /* +0x01A */
- uint32_t oem_product_rev_ptr; /* +0x01E */
- uint8_t scratch[222]; /* +0x022 */
- /* VBE 2.x */
- uint8_t oem_data[256]; /* +0x100 */
-}; /* +0x200 */
-
-struct vbe_mode_info {
- uint16_t mode_attributes; /* +0x000 */
- uint8_t win_a_attributes; /* +0x002 */
- uint8_t win_b_attributes; /* +0x003 */
- uint16_t win_granularity; /* +0x004 */
- uint16_t win_size; /* +0x006 */
- uint16_t win_a_segment; /* +0x008 */
- uint16_t win_b_segment; /* +0x00A */
- uint32_t window_function; /* +0x00C */
- uint16_t bytes_per_scan_line; /* +0x010 */
- /* VBE 1.2 */ /* =0x012 */
- uint16_t x_resolution; /* +0x012 */
- uint16_t y_resolution; /* +0x014 */
- uint8_t x_char_size; /* +0x016 */
- uint8_t y_char_size; /* +0x017 */
- uint8_t number_of_planes; /* +0x018 */
- uint8_t bits_per_pixel; /* +0x019 */
- uint8_t number_of_banks; /* +0x01A */
- uint8_t memory_model; /* +0x01B */
- uint8_t bank_size; /* +0x01C */
- uint8_t number_of_image_pages; /* +0x01D */
- uint8_t reserved_1; /* +0x01E */
- /* direct color fields */ /* =0x01F */
- uint8_t red_mask_size; /* +0x01F */
- uint8_t red_field_position; /* +0x020 */
- uint8_t green_mask_size; /* +0x021 */
- uint8_t green_field_position; /* +0x022 */
- uint8_t blue_mask_size; /* +0x023 */
- uint8_t blue_field_position; /* +0x024 */
- uint8_t reserved_mask_size; /* +0x025 */
- uint8_t reserved_field_position;/* +0x026 */
- uint8_t direct_color_mode_info; /* +0x027 */
- /* VBE 2.0 */ /* =0x028 */
- uint32_t phys_base_ptr; /* +0x028 */
- uint32_t reserved_2; /* +0x02C */
- uint16_t reserved_3; /* +0x030 */
- /* VBE 3.0 */
- uint16_t lin_bytes_per_line; /* +0x032 */
- uint8_t bank_number_of_image_pages;/*+0x034 */
- uint8_t lin_number_of_image_pages;/*+0x035 */
- uint8_t lin_red_mask_size; /* +0x036 */
- uint8_t lin_red_field_position; /* +0x037 */
- uint8_t lin_green_mask_size; /* +0x038 */
- uint8_t lin_green_field_position;/* +0x039 */
- uint8_t lin_blue_mask_size; /* +0x03A */
- uint8_t lin_blue_field_position;/* +0x03B */
- uint8_t lin_reserved_mask_size; /* +0x03C */
- uint8_t lin_reserved_field_position;/* +0x03D */
- uint32_t max_pixel_clock; /* +0x03E */
- uint8_t reserved[190]; /* +0x042 */
-}; /* =0x100 */
-
-struct vbe_mode_custom_crtc_info {
- uint16_t horizontal_total;
- uint16_t horizontal_sync_start;
- uint16_t horizontal_sync_end;
- uint16_t vertical_total;
- uint16_t vertical_sync_start;
- uint16_t vertical_sync_end;
- uint8_t flags;
- uint32_t pixel_clock;
- uint16_t refresh_rate;
- uint8_t reserved[45];
-};
-
-struct vbe_mode_decision {
- int mode;
- signed char dac8;
- signed char lfb;
- unsigned char no_wf:1;
- unsigned char force_wf:1;
- unsigned char _pad_:6;
-};
-#pragma pack(pop)
-
-extern struct vbe_info_block* vbe_info;
-
-void vbe_free();
-int vbe_probe();
-const char *vbe_memory_model_to_str(uint8_t m);
-void vbe_realint(struct dpmi_realmode_call *rc);
-void vbe_realbnk(struct dpmi_realmode_call *rc);
-int vbe_read_mode_info(uint16_t mode,struct vbe_mode_info *mi);
-void vbe_bank_switch(uint32_t rproc,uint8_t window,uint8_t bank);
-int vbe_fill_in_mode_info(uint16_t mode,struct vbe_mode_info *mi);
-uint16_t vbe_read_mode_entry(uint32_t mode_ptr,unsigned int entry);
-int vbe_set_mode(uint16_t mode,struct vbe_mode_custom_crtc_info *ci);
-void vesa_set_palette_data(unsigned int first,unsigned int count,char *pal);
-void vbe_copystring(char *s,size_t max,uint32_t rp,struct vbe_info_block *b);
-int vbe_set_dac_width(int w);
-void vbe_reset_video_to_text();
-void vbe_mode_decision_init(struct vbe_mode_decision *m);
-int vbe_mode_decision_setmode(struct vbe_mode_decision *md,struct vbe_mode_info *mi);
-int vbe_mode_decision_validate(struct vbe_mode_decision *md,struct vbe_mode_info *mi);
-int vbe_mode_decision_acceptmode(struct vbe_mode_decision *md,struct vbe_mode_info *mi);
-
-#define VBE_MODE_CUSTOM_REFRESH (1 << 11)
-#define VBE_MODE_LINEAR (1 << 14)
-#define VBE_MODE_DONT_CLEAR_RAM (1 << 15)
-
-extern uint32_t vesa_lfb_base;
-extern uint32_t vesa_bnk_rproc;
-extern uint8_t vesa_bnk_window; /* which window to use */
-extern uint16_t vesa_bnk_winseg;
-extern uint16_t vesa_bnk_winshf;
-extern uint16_t vesa_bnk_winszshf;
-extern uint16_t vesa_bnk_wincur;
-
-#if TARGET_MSDOS == 32
-extern void* vesa_lfb_dpmi_map;
-extern size_t vesa_lfb_dpmi_map_size;
-extern uint8_t vesa_lfb_dpmi_pam; /* set to 1: used DPMI function 0x0800 to obtain the pointer */
-/* TODO: what if we have to use the "alloc/map device linear pages" 1.0 API */
-#endif
-
-void vesa_lfb_writeb(uint32_t ofs,uint8_t b);
-void vesa_lfb_writew(uint32_t ofs,uint16_t b);
-void vesa_lfb_writed(uint32_t ofs,uint32_t b);
-void vesa_bnk_writeb(uint32_t ofs,uint8_t b);
-void vesa_bnk_writew(uint32_t ofs,uint16_t b);
-void vesa_bnk_writed(uint32_t ofs,uint32_t b);
-
-extern void (*vesa_writeb)(uint32_t ofs,uint8_t b);
-extern void (*vesa_writew)(uint32_t ofs,uint16_t b);
-extern void (*vesa_writed)(uint32_t ofs,uint32_t b);
-
+++ /dev/null
-
-/* TODO: Make the 320x200x256-color override hack optional (and off by default).
- *
- * On an S3 Virge PCI card I own, substituting a VESA BIOS mode for mode
- * 13h causes additional compatability problems because things like
- * horizontal pel and other standard VGA tricks don't work at all.
- * Considering you just finished the Standard VGA version of this hack,
- * the mode 13h hack is no longer necessary and it should be disabled by
- * default though available as an option. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-#include <hw/vesa/vesa.h>
-
-struct mode_remap {
- uint16_t source_mode;
- uint16_t target_mode;
-};
-
-#define MAX_REMAP 256
-
-void (__interrupt __far *old_int10)();
-struct mode_remap remap[MAX_REMAP];
-int remap_count=0;
-union REGS remap_rr;
-
-void __interrupt __far new_int10(union INTPACK ip) {
- if (ip.h.ah == 0x00) {
- unsigned int i,j;
-
- for (i=0;i < remap_count;i++) {
- if (remap[i].source_mode == (ip.h.al&0x7F)) {
- j = remap[i].target_mode | ((ip.h.al&0x80)?0x8000:0x0000);
- __asm {
- push ds
- mov ax,seg old_int10
- mov ds,ax
- mov ax,0x4F02
- mov bx,j
- pushf
- callf dword ptr [old_int10]
- pop ds
- }
-
- return;
- }
- }
- }
- else if (ip.w.ax == 0x4F02) {
- unsigned int i;
-
- for (i=0;i < remap_count;i++) {
- if (remap[i].source_mode == (ip.w.bx&0x3FFF)) {
- ip.w.bx = remap[i].target_mode | (ip.w.bx & 0xC000);
- break;
- }
- }
- }
-
- _chain_intr(old_int10);
-}
-
-static void help() {
- printf("VESA240 /INSTALL\n");
- printf("\n");
- printf("Intercept VESA BIOS calls to force video modes with at least 480 scan lines,\n");
- printf("which may improve video quality with scan converters or enable capture/viewing\n");
- printf("where devices would normally ignore 400-line output.\n");
- printf("(C) 2014 Jonathan Campbell\n");
-}
-
-void end_of_resident();
-
-void install_320x200x256_remap() {
- struct vbe_mode_info nmi;
- uint16_t nmode,tnmode;
- int nentry;
-
- nmode=0;
- for (nentry=0;nentry < 1024;nentry++) {
- tnmode = vbe_read_mode_entry(vbe_info->video_mode_ptr,nentry);
- if (tnmode == 0xFFFF) break;
- memset(&nmi,0,sizeof(nmi));
- if (!vbe_read_mode_info(tnmode,&nmi)) continue;
- if (!(nmi.mode_attributes & VESA_MODE_ATTR_HW_SUPPORTED)) continue;
- if (!(nmi.mode_attributes & VESA_MODE_ATTR_GRAPHICS_MODE)) continue;
- if (nmi.x_resolution != 320) continue;
- if (nmi.y_resolution != 240) continue;
- if (nmi.number_of_planes != 1) continue;
- if (nmi.bits_per_pixel != 8) continue;
- if (!(nmi.memory_model == 5/*non-chain 4 256-color*/ || nmi.memory_model == 4/*packed*/ || nmi.memory_model == 3/*4-plane*/)) continue;
- nmode = tnmode;
- break;
- }
-
- if (nmode != 0) {
- printf(" Remapping mode 0x13 to 0x%03x (%ux%ux%u)\n",nmode,
- nmi.x_resolution,nmi.y_resolution,nmi.bits_per_pixel);
-
- if (remap_count < MAX_REMAP) {
- remap[remap_count].source_mode = 0x13;
- remap[remap_count].target_mode = nmode&0x3FFF;
- remap_count++;
- }
- }
- else {
- printf(" No mapping available for mode 0x13\n");
- }
-}
-
-int main(int argc,char **argv) {
- char *a,*command=NULL;
- unsigned int entry;
- uint16_t mode;
- int i;
-
-#if TARGET_MSDOS != 16
-# error you are not supposed to compile this for protected mode!
-#endif
-
- for (i=1;i < argc;) {
- a = argv[i++];
- if (*a == '/' || *a == '-') {
- do { a++; } while (*a == '/' || *a == '-');
-
- if (!strcasecmp(a,"i") || !strcasecmp(a,"install")) {
- command = a;
- }
- else {
- fprintf(stderr,"Unknown switch %s\n",a);
- command = NULL;
- break;
- }
- }
- else {
- fprintf(stderr,"Unknown switch %s\n",a);
- command = NULL;
- break;
- }
- }
-
- if (command == NULL) {
- help();
- return 1;
- }
- if (!vbe_probe() || vbe_info == NULL) {
- printf("VESA BIOS not found\n");
- return 1;
- }
- if (vbe_info->video_mode_ptr == 0UL) {
- printf("VBE bios does not provide a mode list\n");
- return 1;
- }
-
- /* also find a mapping from mode 0x13 (320x200x256) to VESA BIOS */
- install_320x200x256_remap();
-
- for (entry=0;entry < 1024;entry++) {
- struct vbe_mode_info mi={0},nmi;
- uint16_t nmode,tnmode;
- int nentry;
-
- mode = vbe_read_mode_entry(vbe_info->video_mode_ptr,entry);
- if (mode == 0xFFFF) break;
- if (!vbe_read_mode_info(mode,&mi)) continue;
- if (!(mi.mode_attributes & VESA_MODE_ATTR_HW_SUPPORTED)) continue;
- if (!(mi.mode_attributes & VESA_MODE_ATTR_GRAPHICS_MODE)) continue;
-
- if (mi.y_resolution < 240 || (mi.y_resolution > 240 && mi.y_resolution < 480)) {
- printf("Mode 0x%03x (%ux%ux%u) has less than 480 lines\n",mode,
- mi.x_resolution,mi.y_resolution,mi.bits_per_pixel);
-
- /* look for a target mode to remap to */
- nmode=0;
- for (nentry=0;nentry < 1024;nentry++) {
- tnmode = vbe_read_mode_entry(vbe_info->video_mode_ptr,nentry);
- if (tnmode == 0xFFFF) break;
- memset(&nmi,0,sizeof(nmi));
- if (!vbe_read_mode_info(tnmode,&nmi)) continue;
- if (!(nmi.mode_attributes & VESA_MODE_ATTR_HW_SUPPORTED)) continue;
- if (!(nmi.mode_attributes & VESA_MODE_ATTR_GRAPHICS_MODE)) continue;
- if (nmi.x_resolution != mi.x_resolution) continue;
- if (nmi.number_of_planes != mi.number_of_planes) continue;
- if (nmi.bits_per_pixel != mi.bits_per_pixel) continue;
- if (nmi.number_of_banks != mi.number_of_banks) continue;
- if (nmi.memory_model != mi.memory_model) continue;
-
- if (mi.y_resolution < 240 && nmi.y_resolution == 240) {
- /* found one: should remap 320x200 -> 320x240 */
- nmode = tnmode;
- break;
- }
- else if (mi.y_resolution >= 240 && nmi.y_resolution == 480) {
- /* found one: should remap 320/640x350/400 to 320/640x480 */
- nmode = tnmode;
- break;
- }
- }
-
- if (nmode != 0) {
- printf(" Remap to 0x%03x (%ux%ux%u)\n",nmode,
- nmi.x_resolution,nmi.y_resolution,nmi.bits_per_pixel);
- }
- else {
- printf(" Remap to nothing\n");
- }
-
- if (remap_count >= MAX_REMAP) break;
- remap[remap_count].source_mode = mode&0x3FFF;
- remap[remap_count].target_mode = nmode&0x3FFF;
- remap_count++;
- }
- }
-
- if (remap_count == 0) {
- printf("Nothing to remap\n");
- return 0;
- }
-
- _cli();
- old_int10 = _dos_getvect(0x10);
- _dos_setvect(0x10,new_int10);
- _sti();
- printf("INT 10h hooked\n"); fflush(stdout);
- _dos_keep(0,(34000+sizeof(remap))>>4); /* FIXME! */
- return 0;
-}
-
-void end_of_resident() {
-}
-
+++ /dev/null
-@echo off\r
-\r
-deltree /Y \r
-del /s /q dos386f\*.*\r
-del *.obj\r
-del *.exe\r
-del *.lib\r
-del *.com\r
-del foo.gz\r
+++ /dev/null
-@echo off\r
-rem ----- Auto-generated by make.sh and Linux make system do not modify\r
-\r
-rem ----- shut up DOS4G/W\r
-set DOS4G=quiet\r
-\r
-if "%1" == "clean" call clean.bat\r
-if "%1" == "clean" goto end\r
-\r
-mkdir dos386f\r
-wmake -f ..\..\mak\dos386f.mak HPS=\ lib REL=..\.. \r
-\r
-\r
-:end\r
+++ /dev/null
-# this makefile is included from all the dos*.mak files, do not use directly
-# NTS: HPS is either \ (DOS) or / (Linux)
-
-CFLAGS_THIS = -fr=nul -fo=$(SUBDIR)$(HPS).obj -i=.. -i..$(HPS)..
-NOW_BUILDING = HW_VGA_LIB
-
-TEST_EXE = $(SUBDIR)$(HPS)test.exe
-
-!ifeq TARGET_MSDOS 16
-!ifndef TARGET_WINDOWS
-VGA240_EXE = $(SUBDIR)$(HPS)vga240.exe
-!endif
-!endif
-
-!ifndef TARGET_WINDOWS
-TMODESET_EXE = $(SUBDIR)$(HPS)tmodeset.exe
-!endif
-
-$(HW_VGA_LIB): $(SUBDIR)$(HPS)vga.obj
- wlib -q -b -c $(HW_VGA_LIB) -+$(SUBDIR)$(HPS)vga.obj
-
-$(HW_VGATTY_LIB): $(SUBDIR)$(HPS)vgatty.obj $(HW_VGA_LIB)
- wlib -q -b -c $(HW_VGATTY_LIB) -+$(SUBDIR)$(HPS)vgatty.obj
-
-$(HW_VGAGUI_LIB): $(SUBDIR)$(HPS)vgagui.obj $(HW_VGATTY_LIB)
- wlib -q -b -c $(HW_VGAGUI_LIB) -+$(SUBDIR)$(HPS)vgagui.obj
-
-# NTS we have to construct the command line into tmp.cmd because for MS-DOS
-# systems all arguments would exceed the pitiful 128 char command line limit
-.C.OBJ:
- %write tmp.cmd $(CFLAGS_THIS) $(CFLAGS_CON) $[@
- $(CC) @tmp.cmd
-
-all: lib exe
-
-lib: $(HW_VGA_LIB) $(HW_VGATTY_LIB) $(HW_VGAGUI_LIB) .symbolic
-
-exe: $(TEST_EXE) $(TMODESET_EXE) $(VGA240_EXE) .symbolic
-
-$(TEST_EXE): $(HW_VGATTY_LIB) $(HW_VGATTY_LIB_DEPENDENCIES) $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)test.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(HW_VGATTY_LIB_WLINK_LIBRARIES) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)test.obj name $(TEST_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-
-!ifdef TMODESET_EXE
-$(TMODESET_EXE): $(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_8254_LIB) $(HW_8254_LIB_DEPENDENCIES) $(SUBDIR)$(HPS)tmodeset.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_8254_LIB_WLINK_LIBRARIES) file $(SUBDIR)$(HPS)tmodeset.obj name $(TMODESET_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-!ifdef VGA240_EXE
-$(VGA240_EXE): $(SUBDIR)$(HPS)vga240.obj
- %write tmp.cmd option quiet system $(WLINK_CON_SYSTEM) file $(SUBDIR)$(HPS)vga240.obj name $(VGA240_EXE)
- @wlink @tmp.cmd
- @$(COPY) ..$(HPS)..$(HPS)dos32a.dat $(SUBDIR)$(HPS)dos4gw.exe
-!endif
-
-clean: .SYMBOLIC
- del $(SUBDIR)$(HPS)*.obj
- del $(HW_VGA_LIB)
- del tmp.cmd
- @echo Cleaning done
-
+++ /dev/null
-/* FIXME: This program needs a way to hook into the "winfcon" library. It needs to:
- - Pass all messages through the DispDib hook function.
- - Restore VGA and exit if the user ALT+TAB's out of our app */
-
-/* TODO: This program has TOO MANY TEST ROUTINES IN IT and needs to be split up into utilities */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/vga/vgatty.h>
-#include <hw/dos/doswin.h>
-
-#ifdef TARGET_WINDOWS
-# define WINFCON_STOCK_WIN_MAIN
-# include <hw/dos/winfcon.h>
-# include <windows/apihelp.h>
-# include <windows/dispdib/dispdib.h>
-# include <windows/win16eb/win16eb.h>
-#else
-# include <hw/8254/8254.h>
-#endif
-
-unsigned char paltmp[392*3];
-
-#define VGA_GET_BUF_SIZE 255
-
-char *vga_get_buf = NULL;
-
-void vga_write_state_DEBUG(FILE *f) {
- unsigned char tmp[128];
- sprintf(tmp,"VGA=%u EGA=%u CGA=%u MDA=%u MCGA=%u HGC=%u(%u) Tandy/PCjr=%u Amstrad=%u\n",
- (vga_flags & VGA_IS_VGA) ? 1 : 0,
- (vga_flags & VGA_IS_EGA) ? 1 : 0,
- (vga_flags & VGA_IS_CGA) ? 1 : 0,
- (vga_flags & VGA_IS_MDA) ? 1 : 0,
- (vga_flags & VGA_IS_MCGA) ? 1 : 0,
- (vga_flags & VGA_IS_HGC) ? 1 : 0,vga_hgc_type,
- (vga_flags & VGA_IS_TANDY) ? 1 : 0,
- (vga_flags & VGA_IS_AMSTRAD) ? 1 : 0);
- if (f == NULL)
- vga_write(tmp);
- else
- fputs(tmp,f);
-
- sprintf(tmp," 3x0 I/O base = 0x%03x RAM @ 0x%05lx-0x%05lx ALPHA=%u 9W=%u\n",
- vga_base_3x0,
- (unsigned long)vga_ram_base,
- (unsigned long)vga_ram_base+vga_ram_size-1UL,
- vga_alpha_mode,
- vga_9wide);
- if (f == NULL)
- vga_write(tmp);
- else
- fputs(tmp,f);
-}
-
-char *vga_gets(unsigned int maxlen) {
- unsigned char bx=vga_pos_x,by=vga_pos_y;
- unsigned int pos;
- int c;
-
- if (vga_get_buf == NULL) {
- vga_get_buf = malloc(VGA_GET_BUF_SIZE+1);
- if (vga_get_buf == NULL) return NULL;
- }
-
- if (maxlen > VGA_GET_BUF_SIZE)
- maxlen = VGA_GET_BUF_SIZE;
-
- pos = 0;
- vga_get_buf[pos] = 0;
- vga_moveto(bx+pos,by);
- vga_write_sync();
- vga_sync_bios_cursor();
-
- do {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 8) {
- if (pos > 0) {
- pos--;
- vga_moveto(bx+pos,by);
- vga_writec(' ');
- vga_moveto(bx+pos,by);
- vga_write_sync();
- vga_sync_bios_cursor();
- }
- }
- else if (c == 27) {
- pos = 0;
- vga_get_buf[pos] = 0;
- vga_moveto(bx+pos,by);
- vga_write_sync();
- vga_sync_bios_cursor();
- return NULL;
- }
- else if (c == 13) {
- break;
- }
- else if (c >= 32 || c < 0) {
- if (pos < maxlen) {
- vga_moveto(bx+pos,by);
- vga_writec(c);
- vga_get_buf[pos++] = c;
- vga_moveto(bx+pos,by);
- vga_write_sync();
- vga_sync_bios_cursor();
- }
- }
- } while (1);
- vga_get_buf[pos] = 0;
- vga_moveto(bx,by);
- vga_write_sync();
- vga_sync_bios_cursor();
- return vga_get_buf;
-}
-
-int main() {
-#if defined(TARGET_WINDOWS)
- HWND hwnd;
-#endif
- unsigned char vga_want_9wide;
- int c;
-
- probe_dos();
- detect_windows();
-
-#if !defined(TARGET_WINDOWS)
- if (!probe_8254()) {
- printf("8254 not found (I need this for time-sensitive portions of the driver)\n");
- return 1;
- }
-#endif
-
-#if defined(TARGET_WINDOWS)
-# ifdef WIN_STDOUT_CONSOLE
- hwnd = _win_hwnd();
-# else
- hwnd = GetFocus();
-
- printf("WARNING: The Win32 console version is experimental. It generally works...\n");
- printf(" but can run into problems if focus is taken or if the console window\n");
- printf(" is started minimized or maximized. ENTER to continue, ESC to cancel.\n");
- printf(" If this console is full-screen, hit ALT+ENTER to switch to window.\n");
- do {
- c = getch();
- if (c == 27) return 1;
- } while (c != 13);
-# endif
-
-# if TARGET_WINDOWS == 32
- if (!InitWin16EB()) {
- MessageBox(hwnd,"Failed to init win16eb","Win16eb",MB_OK);
- return 1;
- }
-# endif
-
- /* setup DISPDIB */
- if (DisplayDibLoadDLL()) {
- MessageBox(hwnd,dispDibLastError,"Failed to load DISPDIB.DLL",MB_OK);
- return 1;
- }
-
- if (DisplayDibCreateWindow(hwnd)) {
- MessageBox(hwnd,dispDibLastError,"Failed to create DispDib window",MB_OK);
- return 1;
- }
-
- if (DisplayDibGenerateTestImage()) {
- MessageBox(hwnd,dispDibLastError,"Failed to generate test card",MB_OK);
- return 1;
- }
-
- if (DisplayDibDoBegin()) {
- MessageBox(hwnd,dispDibLastError,"Failed to begin display",MB_OK);
- return 1;
- }
-#endif
-
- if (!probe_vga()) { /* NTS: By "VGA" we mean any VGA, EGA, CGA, MDA, or other common graphics hardware on the PC platform
- that acts in common ways and responds to I/O ports 3B0-3BF or 3D0-3DF as well as 3C0-3CF */
-#if defined(TARGET_WINDOWS)
- DisplayDibDoEnd();
- DisplayDibUnloadDLL();
- MessageBox(hwnd,"Probe failed","VGA lib",MB_OK);
-#else
- printf("VGA probe failed\n");
-#endif
- return 1;
- }
-
- vga_want_9wide = 0xFF;
- vga_write_state_DEBUG(stdout);
- assert(vga_ram_base != 0UL);
- assert(vga_ram_size != 0UL);
- assert(vga_graphics_ram != NULL);
- assert(vga_alpha_ram != NULL);
-
-#if defined(TARGET_WINDOWS)
- int10_setmode(3); /* 80x25 */
- update_state_from_vga();
-#else
- if (!vga_alpha_mode) {
- int10_setmode(3); /* 80x25 */
- update_state_from_vga();
- if (!vga_alpha_mode) {
- printf("Unable to determine that the graphics card is in an alphanumeric mode\n");
- return 1;
- }
- }
-#endif
-
- while (1) {
- vga_clear(); vga_moveto(0,0);
- vga_write_color(0x7);
- vga_write_state_DEBUG(NULL);
- vga_write("\n");
- vga_write(" 1: Set video mode M: Make mono\n");
- vga_write(" T: Restore 80x25 C: Make color\n");
- vga_write(" H: HGC graphics tst !: VGA mmap test\n");
- vga_write(" D: CGA graphics tst P: Tandy graphics tst\n");
- vga_write(" V: EGA/VGA graphics W: EGA/VGA grph II\n");
- vga_write(" X: VGA/MCGA 256-col Y: VGA 256-col modex\n");
- vga_write(" R: VGA raster tst S: EGA raster tst\n");
- vga_write(" s: EGA/VGA split sc F: VGA/EGA font tst\n");
- vga_write(" x: VGA raster fx m: VGA modesetting\n");
- vga_write(" A: Amstrad graphics test\n");
- if (vga_9wide)
- vga_write(" 9: VGA 8-bit wide \n");
- else
- vga_write(" 9: VGA 9-bit wide \n");
- vga_write(" z: Measurements o: Change overscan\n");
-
- vga_write("ESC: quit\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- c = getch();
-
- if (c == 27)
- break;
-
- if (c == '1') {
- const char *str;
- unsigned char c=3;
- vga_write("Video mode? ");
- str = vga_gets(10);
- if (str) {
- c = atoi(str);
- int10_setmode(c);
- update_state_from_vga();
- if (c > 3) {
- do { c=getch(); } while (!(c == 13 || c == 10));
- int10_setmode(3);
- update_state_from_vga();
- }
- }
- }
- else if (c == 'A') {
-#ifdef TARGET_WINDOWS
-#elif TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
- if (vga_flags & VGA_IS_AMSTRAD) {
- static unsigned char pat[4] = {0x11,0x55,0xEE,0xFF};
- static unsigned char shf[4] = {2,1,2,0};
- unsigned int x,y,c,b,s;
- VGA_RAM_PTR w;
-
- /* so apparently, you set up CGA 640x200 mono and then modify some bits */
- int10_setmode(6);
- outp(0x3D8,0x1B); /* graphics mode 2, graphics mode, 80-char mode for completeness, enable video display */
-#if TARGET_MSDOS == 32
- vga_graphics_ram = (unsigned char*)0xB8000;
- vga_graphics_ram_fence = vga_graphics_ram + 0x8000;
-#else
- vga_graphics_ram = (unsigned char far*)MK_FP(0xB800,0);
- vga_graphics_ram_fence = vga_graphics_ram + 0x8000;
-#endif
-
- for (y=0;y < 200;y++) {
- w = vga_graphics_ram + ((y >> 1) * 80) + ((y & 1) * 0x2000);
-
- for (x=0;x < 80;x++) {
- c = (x >> 2) & 0xF;
- b = pat[x&3];
- s = (y & 3) * shf[x&3];
- b = (b << s) | (b >> (8 - s));
- outp(0x3DD,c ^ 0xF); w[x] = 0;
- outp(0x3DD,c); w[x] = b;
- }
- }
- while (getch() != 13);
- int10_setmode(3);
- }
- else {
- vga_write("Only Amstrad may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
-#endif
- }
- else if (c == 'm') {
- int c;
- char tmp[256];
- unsigned char redraw=1;
- unsigned char disable=0;
- struct vga_mode_params mp,omp;
-
- if (vga_flags & VGA_IS_VGA) {
- vga_read_crtc_mode(&mp); omp = mp;
-
- do {
- if (redraw) {
- unsigned long rate;
- double hrate,vrate;
-
- rate = vga_clock_rates[mp.clock_select];
- if (mp.clock_div2) rate >>= 1;
- hrate = (double)rate / ((mp.clock9 ? 9 : 8) * mp.horizontal_total);
- vrate = hrate / mp.vertical_total;
-
- vga_clear();
- vga_moveto(0,0);
- vga_write_color(0x7);
-
- sprintf(tmp,
- "Clk=%u(%luHz) H%c V%c 9clk=%u div2=%u w/dw=%u/%u hr=%.3fKHz vr=%.3fHz\n",
- mp.clock_select,
- vga_clock_rates[mp.clock_select] >> (mp.clock_div2 ? 1 : 0),
- mp.hsync_neg?'-':'+',
- mp.vsync_neg?'-':'+',
- mp.clock9,
- mp.clock_div2,
- mp.word_mode,
- mp.dword_mode,
- hrate / 1000,
- vrate);
- vga_write(tmp);
-
- sprintf(tmp,
- "ref_cycles/scanline=%u inc_only_4th=%u\n",
- mp.refresh_cycles_per_scanline,
- mp.inc_mem_addr_only_every_4th);
- vga_write(tmp);
-
- sprintf(tmp,
- "V: total=%u s/e-rtrace=%u <= x < %u de=%u s/e-blank=%u <= x < %u\n",
- mp.vertical_total,
- mp.vertical_start_retrace,
- mp.vertical_end_retrace,
- mp.vertical_display_end,
- mp.vertical_blank_start,
- mp.vertical_blank_end);
- vga_write(tmp);
-
- sprintf(tmp,
- "H: total=%u s/e-rtrace=%u <= x < %u de=%u s/e-blank=%u <= x < %u d@t=%u d@r=%u\n",
- mp.horizontal_total,
- mp.horizontal_start_retrace,
- mp.horizontal_end_retrace,
- mp.horizontal_display_end,
- mp.horizontal_blank_start,
- mp.horizontal_blank_end,
- mp.horizontal_start_delay_after_total,
- mp.horizontal_start_delay_after_retrace);
- vga_write(tmp);
-
- sprintf(tmp,
- "SLR=%u shift4=%u aws=%u memadiv2=%u scandiv2=%u map14=%u map13=%u sd=%u max=%u\n",
- mp.shift_load_rate,
- mp.shift4_enable,
- mp.address_wrap_select,
- mp.memaddr_div2,
- mp.scanline_div2,
- mp.map14,
- mp.map13,
- mp.scan_double,
- mp.max_scanline);
- vga_write(tmp);
-
- sprintf(tmp,
- "offset=%u\n",
- mp.offset);
- vga_write(tmp);
-
- vga_write("\n");
- vga_write("h/H htotal v/V vtotal c/C clock 9/9 8/9clk 2/2 div2 w/W word d/D dword\n");
- vga_write("[/[ HS+/- ]/] VS+/- b/B hblnks n/N hblnke j/J vblnks k/K vblnke = reread\n");
- }
- redraw = 0;
- c = getch();
- if (c == 27) break;
- else if (c == '=') {
- if (!disable) {
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- vga_read_crtc_mode(&mp);
- redraw = 1;
- }
- }
- else if (c == 'b' || c == 'B') {
- if (c == 'b' && mp.horizontal_blank_start > 4)
- mp.horizontal_blank_start--;
- else if (c == 'B' && mp.horizontal_blank_start < 1024)
- mp.horizontal_blank_start++;
-
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'j' || c == 'J') {
- if (c == 'j' && mp.vertical_blank_start > 4)
- mp.vertical_blank_start--;
- else if (c == 'J' && mp.vertical_blank_start < 1024)
- mp.vertical_blank_start++;
-
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'n' || c == 'N') {
- if (c == 'n' && mp.horizontal_blank_end > 4)
- mp.horizontal_blank_end--;
- else if (c == 'N' && mp.horizontal_blank_end < 1024)
- mp.horizontal_blank_end++;
-
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'k' || c == 'K') {
- if (c == 'k' && mp.vertical_blank_end > 4)
- mp.vertical_blank_end--;
- else if (c == 'K' && mp.vertical_blank_end < 1024)
- mp.vertical_blank_end++;
-
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == '2') {
- mp.clock_div2 = !mp.clock_div2;
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == '[') {
- mp.hsync_neg = !mp.hsync_neg;
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == ']') {
- mp.vsync_neg = !mp.vsync_neg;
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == '9' || c == '(') {
- mp.clock9 = !mp.clock9;
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'w' || c == 'W') {
- mp.word_mode = (c == 'W');
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'd' || c == 'D') {
- mp.dword_mode = (c == 'D');
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'c' || c == 'C') {
- if (c == 'C') mp.clock_select++;
- else if (c == 'c') mp.clock_select--;
- mp.clock_select &= 3;
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'v' || c == 'V') {
- if (c == 'v') {
- if (mp.vertical_total > 4)
- mp.vertical_total--;
- }
- else {
- if (mp.vertical_total < 1023)
- mp.vertical_total++;
- }
-
- /* recompute start/end retrace/blank in proportion to the new value */
- mp.vertical_start_retrace =
- (((long)mp.vertical_total * omp.vertical_start_retrace) / omp.vertical_total);
- mp.vertical_end_retrace = mp.vertical_start_retrace +
- (omp.vertical_end_retrace - omp.vertical_start_retrace);
- mp.vertical_blank_start =
- (((long)mp.vertical_total * omp.vertical_blank_start) / omp.vertical_total);
- mp.vertical_blank_end = mp.vertical_blank_start +
- (omp.vertical_blank_end - omp.vertical_blank_start);
- mp.vertical_display_end =
- (((long)mp.vertical_total * omp.vertical_display_end) / omp.vertical_total);
-
- /* experience points:
- *
- * nVidia VGA seems to demand a minimum 2 clocks between horizontal_blank_end
- * and horizontal_total, or else it ends up blanking through the next line.
- *
- * Intel VGA emulation hates this code especially when the output is the LVDS
- * laptop display :( */
- if ((mp.vertical_blank_end+2) > mp.vertical_total) {
- mp.vertical_blank_end = mp.vertical_total - 2;
- mp.vertical_blank_start = mp.vertical_blank_end -
- (omp.vertical_blank_end - omp.vertical_blank_start);
- }
- if (mp.vertical_blank_start < mp.vertical_display_end)
- mp.vertical_blank_start = mp.vertical_display_end;
-
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'h' || c == 'H') {
- if (c == 'h') {
- if (mp.horizontal_total > 4)
- mp.horizontal_total--;
- }
- else {
- if (mp.horizontal_total < 255)
- mp.horizontal_total++;
- }
-
- /* recompute start/end retrace/blank in proportion to the new value */
- mp.horizontal_start_retrace =
- (((long)mp.horizontal_total * omp.horizontal_start_retrace) / omp.horizontal_total);
- mp.horizontal_end_retrace = mp.horizontal_start_retrace +
- (omp.horizontal_end_retrace - omp.horizontal_start_retrace);
- mp.horizontal_blank_start =
- (((long)mp.horizontal_total * omp.horizontal_blank_start) / omp.horizontal_total);
- mp.horizontal_blank_end = mp.horizontal_blank_start +
- (omp.horizontal_blank_end - omp.horizontal_blank_start);
- mp.horizontal_display_end =
- (((long)mp.horizontal_total * omp.horizontal_display_end) / omp.horizontal_total);
-
- /* experience points:
- *
- * Intel VGA emulation hates this code especially when the output is the LVDS
- * laptop display :( */
- if ((mp.horizontal_blank_end+2) > mp.horizontal_total) {
- mp.horizontal_blank_end = mp.horizontal_total - 2;
- mp.horizontal_blank_start = mp.horizontal_blank_end -
- (omp.horizontal_blank_end - omp.horizontal_blank_start);
- }
- if (mp.horizontal_blank_start < mp.horizontal_display_end)
- mp.horizontal_blank_start = mp.horizontal_display_end;
-
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'T') {
- if (!disable) {
- redraw=1;
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- }
- else if (c == ' ') {
- if (!disable) {
- vga_correct_crtc_mode(&mp);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'r') {
- if (!disable) {
- vga_read_crtc_mode(&mp);
- redraw = 1;
- }
- }
- } while (1);
- }
- else {
- vga_write("Only VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'x') {
-/* FIXME: All this wonderful code overflows the 64KB code limit in Watcom C++ under Compact memory model */
-#if TARGET_MSDOS == 16 && defined(__COMPACT__)
- /* NOTHING */
-#else
- /* FIXME: Would these tests actually work on an EGA? */
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA)) {
- VGA_RAM_PTR wr;
- VGA_ALPHA_PTR awr;
- unsigned int x,y,cc,sino=0,divpt,divpt2;
- unsigned char sine[128];
- unsigned int h;
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- h = (vga_flags & VGA_IS_VGA) ? 400 : 350;
-
- /* -------------------------------------------------------------------------------- */
- /* test #1: does your VGA double-buffer the horizontal panning register? */
- /* -------------------------------------------------------------------------------- */
- /* DOSBox 0.74: yes [rock solid]
- * ATI Radeon: no [shimmering effect, cursor shimmers with text]
- * nVidia Geforce: yes [rock solid]
- * Intel 855GM: yes [rock solid]
- */
- awr = vga_alpha_ram;
- for (y=0;y < (80*25);y++)
- awr[y] = 0x1E00 | 176;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_write("Horizontal PEL double-buffering test\n");
- vga_write("Some VGA chipsets do not double-buffer the horizontal pixel offset register\n");
- vga_write("If your screen is shimmering right now, then it's one of them");
- vga_write_sync();
-
- for (y=0;y < 128;y++)
- sine[y] = (unsigned char)((sin((double)y * 3.14159 / 16) * 4) + 4);
-
- do {
- _sti();
- if (kbhit()) {
- if (getch() == 27) break;
- }
- _cli();
-
- vga_wait_for_vsync();
- /* set offset to zero so that VGA chipsets that DO buffer it have a static screen */
- vga_set_xpan(vga_9wide ? 8 : 0);
- vga_wait_for_vsync_end();
- for (cc=0;cc < 12;cc++) { /* make sure we're far enough into the active area that our changes do not take effect immediately
- on chipsets that DO double buffer */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- /* now twiddle with the register */
- for (y=0;y < (h - 24);y++) {
- vga_wait_for_hsync();
- vga_set_xpan(sine[(y+sino)&127]);
- vga_wait_for_hsync_end();
- }
- vga_set_xpan(vga_9wide ? 8 : 0);
- sino++;
- } while(1);
-
- /* -------------------------------------------------------------------------------- */
- /* test #2: does your VGA double-buffer the max scan line register? */
- /* -------------------------------------------------------------------------------- */
- /* DOSBox 0.74: ?? [every write to the register triggers a full screen redraw]
- * ATI Radeon: no [screen warps]
- * Intel: no [screen warps---very jumpy possibly due to Fujitsu BIOS]
- */
- awr = vga_alpha_ram;
- for (y=0;y < (80*25);y++)
- awr[y] = 0x1E00 | 176;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_write("Max scan line register double-buffering test\n");
- vga_write("Some VGA chipsets do not double-buffer this register.\n");
- vga_write("If your screen is warping right now, then it's one of them");
- vga_write_sync();
-
- for (y=0;y < 128;y++) {
- sine[y] = (unsigned char)((sin((double)y * 3.14159 / 128) * 9) + 8);
- if (sine[y] & 0x80) sine[y] = 0;
- }
-
- do {
- _sti();
- if (kbhit()) {
- if (getch() == 27) break;
- }
- _cli();
-
- vga_wait_for_vsync();
- /* set correct count so that VGA chipsets that DO buffer it have a static screen */
- vga_write_CRTC(9,15);
- vga_wait_for_vsync_end();
- for (cc=0;cc < 12;cc++) { /* make sure we're far enough into the active area that our changes do not take effect immediately
- on chipsets that DO double buffer */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- /* now twiddle with the register */
- for (y=0;y < (h - 24);y++) {
- vga_wait_for_hsync();
- vga_write_CRTC(9,sine[(y+sino)&127]);
- vga_wait_for_hsync_end();
- }
- vga_write_CRTC(9,vga_flags & VGA_IS_VGA ? 15 : 13);
- sino++;
- } while(1);
-
- if (vga_flags & VGA_IS_VGA) {
- /* now do it in mode 19 */
- /* DOSBox 0.74: no [screen warps]
- * ATI Radeon: no [screen warps]
- * Intel: no [screen warps---very jumpy possibly due to Fujitsu BIOS]
- */
- int10_setmode(19);
- update_state_from_vga();
- wr = vga_graphics_ram;
- for (y=0;y < 200;y++) {
- for (x=0;x < 320;x++) {
- *wr++ = y ^ x;
- }
- }
-
- {
- double err = 0,a;
- for (y=0;y < 128;y++) {
- a = sin((double)y * 3.14159 / 128) * 2;
- sine[y] = (unsigned char)((int)(a + err) + 1);
- err = a + err;
- err -= floor(err);
- if (sine[y] & 0x80) sine[y] = 0;
- }
- }
-
- do {
- _sti();
- if (kbhit()) {
- if (getch() == 27) break;
- }
- _cli();
-
- vga_wait_for_vsync();
- /* set correct count so that VGA chipsets that DO buffer it have a static screen */
- vga_write_CRTC(9,1);
- vga_wait_for_vsync_end();
- for (cc=0;cc < 12;cc++) { /* make sure we're far enough into the active area that our changes do not take effect immediately
- on chipsets that DO double buffer */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- /* now twiddle with the register */
- for (y=0;y < (h - 24);y++) {
- vga_wait_for_hsync();
- vga_write_CRTC(9,sine[(y+sino)&127]);
- vga_wait_for_hsync_end();
- }
- vga_write_CRTC(9,1);
- sino++;
- } while(1);
- /* restore mode 3 */
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
-
- /* -------------------------------------------------------------------------------- */
- /* test #3: does your VGA double-buffer the line compare register (splitscreen)? */
- /* -------------------------------------------------------------------------------- */
- /* VGA splitscreen happens when the line compare register equals the scan line of
- * the raster. On a VGA that doesn't double-buffer, we can set up the screen as if
- * splitscreen but then deliberately confuse it into not displaying the splitscreen.
- * We do this by setting line compare to something (say, the middle of the screen)
- * and then just before the raster gets there, setting line compare to a scan line
- * prior to where the raster is. The VGA never has a chance to match the scan line
- * and splitscreen never happens. */
- /* -------------------------------------------------------------------------------- */
- /* chipsets that double buffer line compare: */
- /* DOSBox 0.74: yes [mirror image]
- * ATI Radeon: no [no mirror]
- * Intel: no [no mirror]
- */
- awr = vga_alpha_ram;
- for (y=0;y < (80*25*2);y++) /* 2 h/w pages */
- awr[y] = 0x1E00 | 176;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_write("Line compare double-buffer test\n");
- vga_write("Most VGA chipsets do not double-buffer the line compare register\n");
- vga_write("If you can see the splitscreen (a mirror of this text halfway down)\n");
- vga_write("your chipset is NOT one of them.");
- vga_write_sync();
-
- do {
- _sti();
- if (kbhit()) {
- if (getch() == 27) break;
- }
- _cli();
-
- vga_wait_for_vsync();
- vga_splitscreen(h/2);
- vga_wait_for_vsync_end();
- for (cc=0;cc < ((h/2)-32);cc++) { /* wait until just before the scan line (give or take 32) */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_splitscreen(1); /* whoops! :) */
- } while(1);
- vga_splitscreen(0x3FF);
-
- /* ----------------------------- 2nd test ---------------------------- */
- /* if it doesn't double-buffer line compare, then we can probably trick
- * it into splitting the screen (resetting to address 0) more than once,
- * since the card is designed to do so when line count == line compare. */
- awr = vga_alpha_ram;
- for (y=0;y < (80*25*2);y++) /* 2 h/w pages */
- awr[y] = 0x1E00 | 176;
-
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_write("Line compare double-buffer test II\n");
- vga_write("It follows that if the split happens when row counter == line compare,\n");
- vga_write("and line compare is NOT buffered, that we can modify the line compare during\n");
- vga_write("active display and trick the VGA into split-screening multiple times.");
- vga_write_sync();
-
- do {
- _sti();
- if (kbhit()) {
- if (getch() == 27) break;
- }
- _cli();
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- vga_splitscreen(80);
- for (cc=0;cc < 84;cc++) { /* wait until just before the scan line (give or take 32) */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- for (y=80+64;y < (h-8);y += 64) {
- vga_splitscreen(y);
- for (cc=0;cc < 64;cc++) { /* wait until just before the scan line (give or take 32) */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- }
- } while(1);
- vga_splitscreen(0x3FF);
-
- /* -------------------------------------------------------------------------------- */
- /* test #4: does your VGA double-buffer the offset register (stride, line to line)? */
- /* -------------------------------------------------------------------------------- */
- /* chipsets that double buffer it: */
- /* DOSBox 0.74 [vgaonly]: no
- * DOSBox 0.74 [other vga]: ?? [kind of... resolution is coarse about 1/4th the screen]
- * DOSBox 0.74 [ega]: yes
- * ATI Radeon: no
- * Intel: no
- */
- awr = vga_alpha_ram;
- for (y=0;y < (80*25);y++) /* 2 h/w pages */
- awr[y] = 0x1E00 | 176;
-
- divpt2 = ((15+5) * ((vga_flags & VGA_IS_VGA) ? 16 : 14)) + 1; /* give the VGA chipset time to latch into the offset of the box */
- divpt = (15 * ((vga_flags & VGA_IS_VGA) ? 16 : 14)) + 1; /* give the VGA chipset time to latch into the offset of the box */
- vga_moveto(0,0);
- vga_write_color(0x0E);
- vga_write("Offset register double-buffer test\n");
- vga_write("The offset register determines the number of bytes per scan line.\n");
- vga_write("Most VGA chipsets do not buffer this register, making it possible\n");
- vga_write("to change bytes/line mid-screen.\n");
- vga_write("\n");
- vga_write("If you can see the box below whole, then your chipset is one of them\n");
-
- vga_moveto(0,14);
- vga_write_color(0x0A);
- vga_write("This text should be on the left side, and the box should show up below:\n");
- vga_write_sync();
- {
- unsigned int ofs = 80*15;
- for (y=16;y <= 18;y++) {
- awr[ofs+((y-15)*120)] = 0x0E00 | 186;
- awr[ofs+((y-15)*120)+22] = 0x0E00 | 186;
- }
- for (x=1;x <= 21;x++)
- awr[ofs+x] = 0x0E00 | 205;
- for (x=1;x <= 21;x++)
- awr[ofs+x+(4*120)] = 0x0E00 | 205;
- awr[ofs+((0*120)+0)] = 0x0E00 | 201;
- awr[ofs+((0*120)+22)] = 0x0E00 | 187;
- awr[ofs+((4*120)+0)] = 0x0E00 | 200;
- awr[ofs+((4*120)+22)] = 0x0E00 | 188;
- }
- {
- unsigned int ofs = (80*15)+(120*5);
- const char *msg = "This text should be on the left side, and repeating";
- VGA_ALPHA_PTR w = vga_alpha_ram + ofs;
- while (*msg) *w++ = 0x0A00 | *msg++;
- }
- {
- unsigned int ofs = (80*15)+(120*5)+(80*1);
- const char *msg = "You should not be able to see this text";
- VGA_ALPHA_PTR w = vga_alpha_ram + ofs;
- while (*msg) *w++ = 0x0C00 | *msg++;
- }
-
- do {
- _sti();
- if (kbhit()) {
- if (getch() == 27) break;
- }
- _cli();
-
- vga_wait_for_vsync();
- vga_write_CRTC(0x13,80 / 2); /* byte mode, right? */
- vga_wait_for_vsync_end();
- for (cc=0;cc < divpt;cc++) { /* wait until the text line prior to where want to change */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- /* change the stride */
- vga_write_CRTC(0x13,120 / 2); /* byte mode, right? */
- for (;cc < divpt2;cc++) { /* wait until the text line prior to where want to change */
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_write_CRTC(0x13,0 / 2); /* byte mode, right? */
- } while(1);
- vga_write_CRTC(0x13,80 / 2); /* word mode, right? */
-
- /* FIXME: Windows 98 bootdisk + Bochs 2.4.6: Emulator hangs at this point */
-
- {
- unsigned char blobs[14*2],bdir[14];
- unsigned char check1=0,check2=0,c1a,counter;
- /* -------------------------------------------------------------------------------- */
- /* test #5: if I set stride == 0, can I write over the VRAM mid-scan to fake a picture */
- /* -------------------------------------------------------------------------------- */
- /* [another common trick by old demos: set stride == 0 and then once per scanline
- * change the VRAM contents. This is usually associated with a moving checkerboard and
- * a "3D" moving platform that, on older hardware, would normally be impossible to draw
- * realtime. This is usually done in VGA graphics modes. We're probably the first to
- * try it in alphanumeric text mode :) */
- vga_write_CRTC(9,0);
- vga_write_CRTC(0x13,0 / 2); /* byte mode, right? */
-
- /* also reprogram character ram to turn chars into 1:1 mapping with bits */
- vga_alpha_switch_to_font_plane();
- for (x=0;x < 256;x++) vga_graphics_ram[x*32] = x;
- vga_alpha_switch_from_font_plane();
- if (vga_flags & VGA_IS_VGA) vga_set_9wide(0);
-
- for (y=0;y < 14;y++) {
- blobs[y*2 + 0] = rand()%80;
- blobs[y*2 + 1] = rand()%256;
- bdir[y] = ((rand()&1)*2) - 1;
- }
-
- counter = 0;
- do {
- _sti();
- if (kbhit()) {
- if (getch() == 27) break;
- }
- _cli();
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- awr = vga_alpha_ram;
- for (y=0;y < 80;y++) awr[y] = 0;
- for (cc=0;cc < 4;cc++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- for (cc=0;cc < 4;cc++) {
- vga_wait_for_hsync();
- for (y=0;y < 80;y++) awr[y] = (0x55 << (cc&1)) | 0x0800;
- vga_wait_for_hsync_end();
- }
- for (y=0;y < 80;y++) awr[y] = 0;
- for (cc=0;cc < 2;cc++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
-
- /* checkerfield, and "blobs" */
- {
- unsigned short a=0x07FF,b=0;
- for (cc=0;cc < 80;cc += 4) {
- awr[cc+0] = a;
- awr[cc+1] = a;
- awr[cc+2] = b;
- awr[cc+3] = b;
- }
- }
-
- c1a=check1;
- for (y=0;y < (h-32);y++) {
- vga_wait_for_hsync_end();
- for (cc=0;cc < 14;cc++) {
- unsigned char cmp = blobs[cc*2 + 1];
- if (y == cmp) {
- awr[blobs[cc*2]] = ((cc+1) << 8) | 0xFF;
- }
- }
-
- vga_wait_for_hsync();
- c1a++;
- if ((c1a & 15) == 0 || y == 0) {
- vga_write_AC(0,(c1a & 16) ? 7 : 0);
- vga_write_AC(7,(c1a & 16) ? 0 : 7);
- vga_AC_reenable_screen();
- }
- }
-
- vga_write_AC(0,0);
- vga_write_AC(7,7);
- vga_AC_reenable_screen();
- for (cc=0;cc < 80;cc++) awr[cc] = 0;
- for (cc=0;cc < 14;cc++) {
- blobs[cc*2] += bdir[cc];
- if ((signed char)blobs[cc*2] < 0) {
- blobs[cc*2] = 0;
- bdir[cc] = 1;
- }
- else if (blobs[cc*2] >= 80) {
- blobs[cc*2] = 79;
- bdir[cc] = -1;
- }
- }
-
- counter++;
- if ((counter & 1) == 1) check1++;
- check2++;
- } while(1);
- vga_write_CRTC(9,vga_flags & VGA_IS_VGA ? 15 : 13);
- vga_write_CRTC(0x13,80 / 2); /* word mode, right? */
- }
-
- int10_setmode(3);
- update_state_from_vga();
- }
- else {
- vga_write("Only VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
-#endif
- }
- else if (c == '9') {
- if (vga_flags & VGA_IS_VGA) {
- if (!vga_alpha_mode) {
- int10_setmode(3);
- update_state_from_vga();
- }
-
- vga_set_9wide(!vga_9wide);
- update_state_from_vga();
- vga_want_9wide = vga_9wide;
- }
- else {
- vga_write("Only VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'F') { /* in this test we fuck around with EGA/VGA character RAM */
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA)) {
- unsigned int lineheight = (vga_flags & VGA_IS_VGA) ? 16 : 14;
- unsigned int x,y;
- VGA_ALPHA_PTR wr;
- VGA_RAM_PTR fr;
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
-
- wr = vga_alpha_ram;
- for (x=0;x < (80*25);x++) {
- wr[x] = 0x400 + x;
- }
- while (getch() != 13);
-
- vga_alpha_switch_to_font_plane();
- for (x=0;x < 16;x++) {
- fr = vga_graphics_ram + (x*32);
- for (y=0;y < lineheight;y++) {
- vga_wait_for_vsync();
- fr[y] = 0x55 << (y&1);
- vga_wait_for_vsync_end();
- }
- }
- for (x=127;x < 256;x++) {
- fr = vga_graphics_ram + (x*32);
- for (y=0;y < lineheight;y++) {
- fr[y] = 0x55 << (y&1);
- }
- }
- vga_alpha_switch_from_font_plane();
- wr = vga_alpha_ram;
- {
- const char *msg = "TADAAAAaaaa!";
- while (*msg) *wr++ = ((unsigned char)(*msg++)) | 0x1A00;
- }
- while (getch() != 13);
- vga_alpha_switch_to_font_plane();
- fr = vga_graphics_ram;
- for (x=0;x < (256*32);x++) {
- /* NTS: XOR and then NOT, make them different to discourage the compiler from optimizing them out */
- *fr ^= 0xFF;
- *fr = ~(*fr);
- }
- vga_alpha_switch_from_font_plane();
- while (getch() != 13);
-
- /* read and copy back the font----make sure we're reading it correctly */
-
- /* now play with the 512-code mode */
- /* NTS: Nobody seems to mention this, but if the bitfields were extended from EGA in the
- * exact same manner that would imply the EGA also has the ability to do 512-char
- * mode! Right? Perhaps someday I'll find some EGA hardware to verify this on */
- {
- vga_write_CRTC(9,7); /* transition to 80x50 */
- wr = vga_alpha_ram;
- for (y=0;y < 50;y++) {
- for (x=0;x < 80;x++) {
- *wr++ = (x + 16) | ((y&1) << 11) | (((y>>1)&7) << 8) | ((y>>4) << 12);
- }
- }
-
- vga_alpha_switch_to_font_plane();
- /* FIXME: What's with the FONT CORRUPTION seen on actual ATI & Intel hardware here?? */
- /* in-place convert 8x16 -> 8x8 */
- for (x=0;x < 256;x++) {
- unsigned char a,b;
- fr = vga_graphics_ram + (x*32);
- for (y=1;y < 8;y++) {
- a = vga_force_read(fr+(y<<1));
- b = vga_force_read(fr+(y<<1)+1);
- vga_force_write(fr+y,a|b);
- }
- }
- /* then make the 2nd set a mirror image */
- fr = vga_graphics_ram;
- for (x=0;x < (256*32);x++) {
- unsigned char c=0,i=fr[x];
- for (y=0;y < 8;y++) {
- if (i & (1 << y))
- c |= 128 >> y;
- }
- fr[x+0x2000] = c;
- }
- for (x=0;x < (256*32);x++) {
- fr[(x^7)+0x4000] = fr[x+0x2000];
- }
- for (x=0;x < (256*32);x++) {
- fr[(x^7)+0x6000] = fr[x];
- }
- vga_alpha_switch_from_font_plane();
- while (getch() != 13);
- vga_select_charset_a_b(0,0x2000);
- while (getch() != 13);
- vga_select_charset_a_b(0,0x4000);
- while (getch() != 13);
- vga_select_charset_a_b(0,0x6000);
- while (getch() != 13);
- for (x=8;x < 16;x++) vga_write_AC(x,x&7);
- vga_AC_reenable_screen();
- while (getch() != 13);
- /* play with the underline location reg */
- vga_write_CRTC(0x14,(vga_read_CRTC(0x14) & 0xE0) | 7);
- while (getch() != 13);
- for (y=6;1;) {
- vga_wait_for_vsync_end();
- vga_wait_for_vsync();
- for (x=0;x < 32;x++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_write_CRTC(0x14,(vga_read_CRTC(0x14) & 0xE0) | y);
- if (y == 0) break;
- y--;
- }
- while (getch() != 13);
- }
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 's') {
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA)) {
- unsigned int lineheight = (vga_flags & VGA_IS_VGA) ? 16 : 14;
- unsigned int y,h = (vga_flags & VGA_IS_VGA) ? 400 : 350,v,cc;
- unsigned int charw = 8;
- unsigned int yofs;
- VGA_ALPHA_PTR wr;
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA) {
- if (vga_want_9wide != 0xFF) {
- vga_set_9wide(vga_want_9wide);
- charw = vga_want_9wide ? 9 : 8;
- }
- else {
- charw = vga_9wide ? 9 : 8;
- }
- }
-
- /* NTS: everyone knows the VGA holds on to your register updates until vertical retrace, but
- * when exactly after retrace they take effect seems to wildly vary between VGA cards.
- * to ensure our new values are latched on time, we delay (using HSYNC) 32 scanlines
- * so that our new values are written at a time when we're well into the active picture
- * and the CRTC would have to be WAY out of compliance to have not updated itself by then!
- *
- * DOSBox 0.74 [vgaonly]: a good 8-10 scanlines after vblank, or else ypan is jumpy
- * ATI: ypan takes effect, hpel might or might not [jumpy horz. scrolling]
- * NVidia: a good 8-10 scanlines, or else ypan is jumpy
- * Intel (855/915/945/etc) right after vblank [perfect scrolling] */
-
- vga_set_start_location(80*25); /* show 2nd page */
- wr = vga_alpha_ram + (80*25);
- { /* draw pattern on 2nd page */
- for (y=0;y < (80*25);y++) {
- wr[y] = y + 0x200;
- }
- }
- { /* draw message on first page */
- const char *msg = "EGA/VGA Split-screen!";
- wr = vga_alpha_ram;
- while (*msg) *wr++ = (unsigned char)(*msg++) | 0x1E00;
- while (wr < (vga_alpha_ram+(80*25))) *wr++ = 0x1FB1;
- }
- y = 0; v = 1;
- do { /* loop */
- if (kbhit()) {
- if (getch() == 27) break;
- }
-
- /* NTS: ATI and Intel VGA do not double-buffer the splitscreen register.
- * Updating it during the active display area would cause a visible jump
- * and possible flash whenever the split point crossed our 32-scanline
- * wait loop. So we need to wait until VBLANK to update it */
- _cli();
- vga_wait_for_vsync_end();
- for (cc=0;cc < 32;cc++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_wait_for_vsync();
- vga_splitscreen(y);
- vga_wait_for_vsync_end();
- _sti();
- y += v;
- if (y == 0) v = 1;
- else if (y == (h+5)) v = -1;
- } while (1);
-
- y = 0; v = 1;
- do { /* loop */
- if (kbhit()) {
- if (getch() == 27) break;
- }
-
- /* NTS: ATI chipsets DO double-buffer the offset register and ypan (as expected by the VGA
- * standard) but DO NOT double-buffer the horizontal pel register. Same comments apply
- * regarding the splitscreen register */
- _cli();
- vga_wait_for_vsync_end();
- for (cc=0;cc < 32;cc++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- yofs = h - y;
- /* NTS: offset and ypan need to be updated during active area, for CRTC to latch in on VBLANK */
- vga_set_start_location(80*25 + ((yofs/lineheight)*80)); /* show 2nd page */
- vga_set_ypan_sub(yofs%lineheight);
- vga_wait_for_vsync();
- /* NTS: splitscreen register needs to be updated DURING VBLANK because some chipsets (ATI) do not buffer them */
- vga_splitscreen(y);
- vga_wait_for_vsync_end();
- y += v;
- if (y == 0) v = 1;
- else if (y == (h+1)) v = -1;
- _sti();
- } while (1);
-
- y = 0; v = 1;
- if (vga_flags & VGA_IS_VGA)
- vga_write_AC(0x10|0x20,vga_read_AC(0x10) | 0x20); /* disable hpen on splitscreen */
- else
- vga_write_AC(0x10|0x20,0x20); /* disable hpen on splitscreen */
-
- do { /* loop */
- if (kbhit()) {
- if (getch() == 27) break;
- }
-
- /* NTS: ATI chipsets DO double-buffer the offset register and ypan (as expected by the VGA
- * standard) but DO NOT double-buffer the horizontal pel register. Same comments apply
- * regarding the splitscreen register */
- _cli();
- vga_wait_for_vsync_end();
- for (cc=0;cc < 32;cc++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- yofs = h - y;
- /* NTS: ATI chipsets DO buffer ypan and offset registers but DO NOT buffer horizontal pel
- * and splitscreen */
- vga_set_start_location(80*25 + ((yofs/lineheight)*80) + (yofs/charw)); /* show 2nd page */
- vga_set_ypan_sub(yofs%lineheight);
- vga_wait_for_vsync();
- /* NTS: splitscreen & hpel need to be updated DURING VBLANK because some chipsets (ATI) do not buffer them */
- vga_splitscreen(y);
- if (charw == 9) vga_set_xpan((yofs+8)%charw); /* apparently in 9-bit mode it's off by 1 and 8 -> 0 */
- else vga_set_xpan(yofs%charw);
- vga_wait_for_vsync_end();
- y += v;
- if (y == 0) v = 1;
- else if (y == (h+1)) v = -1;
- _sti();
- } while (1);
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'S') {
- if (vga_flags & VGA_IS_EGA) {
- uint16_t color16;
- unsigned char mode,c;
- volatile VGA_RAM_PTR wr;
- unsigned int w,h,x,y,v,rv;
-
- w = 640;
- if (vga_flags & VGA_IS_VGA) {
- mode = 18;
- h = 480;
- }
- else {
- mode = 16;
- h = 350;
- }
-
- int10_setmode(mode);
- update_state_from_vga();
- vga_write_sequencer(VGA_SC_MAP_MASK, 0xF); /* map mask register = enable all planes */
- vga_write_GC(VGA_GC_ENABLE_SET_RESET, 0x00); /* enable set/reset = no on all planes */
- vga_write_GC(VGA_GC_SET_RESET, 0x00); /* set/reset register = all zero */
- vga_write_GC(VGA_GC_BIT_MASK, 0xFF); /* all bits modified */
-
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_NONE); /* rotate=0 op=unmodified */
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 (copy CPU bits to each plane) */
- {
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- color16 = (y>>3) * 0x101;
- /* NTS: performance hack: issue 16-bit memory I/O */
- for (x=0;x < 64;x += 16) {
- *((VGA_ALPHA_PTR)wr) = (uint16_t)color16;
- wr += 2;
- }
- wr += (w-64)/8;
- }
- }
-
- /* play with attribute controller */
- for (c=0;c < 4;c++) vga_write_AC(c,vga_AC_RGB_to_code(c,c,c));
- for ( ;c < 7;c++) vga_write_AC(c,vga_AC_RGB_to_code(c-3,0,0));
- for ( ;c < 10;c++) vga_write_AC(c,vga_AC_RGB_to_code(c-6,c-6,0));
- for ( ;c < 13;c++) vga_write_AC(c,vga_AC_RGB_to_code(0,c-9,0));
- for ( ;c < 16;c++) vga_write_AC(c,vga_AC_RGB_to_code(0,0,c-12));
- vga_AC_reenable_screen();
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- for (y=0;y < h;y++) {
- vga_wait_for_hsync();
- if (vga_in_vsync()) break;
- vga_wait_for_hsync_end();
- }
- if (h > y) h = y;
- if (h > 24) h -= 24;
-
- /* NTS: Apparently on Intel chipsets the timing isn't granular enough and the I/O is slow enough
- * that on the right-hand side of the screen you can see a flickering black band followed by
- * brief junk data and then the picture. That's what IBM gets for making EGA "palette registers"
- * that blank the screen when you write them-hah! [seen on: Intel 855GM/Fujitsu laptop, but only
- * when displayed on the internal LCD display. External VGA does not show this glitch] */
-
- x = 0; v = 1;
- do {
- vga_wait_for_vsync();
- /* TODO: When you get your keyboard code finished, poll the keyboard controller directly. Do NOT enable interrupts.
- * Hopefully never enabling interrupts resolves the horrible "pulsating" I'm seeing on one Fujitsu laptop I own */
- _sti();
- if (kbhit()) {
- if (getch() == 13) break;
- }
- _cli();
- vga_wait_for_vsync_end();
-
- rv = x;
- for (y=0;y < h;y++,rv++) {
- vga_wait_for_hsync();
- vga_write_AC(0,vga_AC_RGB_to_code((rv>>3)&3,(rv>>5)&3,(rv>>7)&3));
- vga_AC_reenable_screen();
- vga_wait_for_hsync_end();
- }
-
- x += v;
- if (x == 0) v = 1;
- else if (x == 392) v = -1;
- } while (1);
- _sti();
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'R') {
- if (vga_flags & VGA_IS_VGA) {
- signed char tr,tg,tb,cc,cd;
- unsigned char r,g,b,*pal;
- volatile VGA_RAM_PTR wr;
- unsigned int w,h,x,y,v;
- int iy;
-
- int10_setmode(19);
- tr=63;tg=63;tb=63;cc=0;cd=1;
- update_state_from_vga();
- vga_enable_256color_modex();
- w = 320; h = (0x10000 / (w/4));
- x = 0; v = 1;
-
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- *wr++ = y;
- *wr++ = y;
- *wr++ = y;
- *wr++ = (y&1)?15:0;
- /* NTS: Some chipsets change how they interpret RAM depending on whether we
- * enable "Mode X" especially Intel chipsets */
- for (x=16;x < w;x += 4) *wr++ = 0;
- }
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- for (y=0;y < h;y++) {
- vga_wait_for_hsync();
- if (vga_in_vsync()) break;
- vga_wait_for_hsync_end();
- }
- if (y > 392) y = 392;
- h = y;
- if (h > 24) h -= 24;
-
- do {
- vga_wait_for_vsync();
- /* TODO: When you get your keyboard code finished, poll the keyboard controller directly. Do NOT enable interrupts.
- * Hopefully never enabling interrupts resolves the horrible "pulsating" I'm seeing on one Fujitsu laptop I own */
- _sti();
- if (kbhit()) {
- if (getch() == 13) break;
- }
- _cli();
-
- pal = paltmp;
- for (y=0;y < h;y++) {
- iy = 64 - abs((int)y - (int)x); if (iy < 0) iy = 0;
- *pal++ = (tr*iy)>>6;
- *pal++ = (tg*iy)>>6;
- *pal++ = (tb*iy)>>6;
- }
-
- vga_wait_for_vsync_end();
- pal = paltmp;
- for (y=0;y < h;y++) {
- r = *pal++;
- g = *pal++;
- b = *pal++;
- vga_wait_for_hsync();
- vga_palette_lseek(0);
- vga_palette_write(r,g,b);
- vga_palette_lseek(15);
- vga_palette_write(63-r,63-g,63-b);
- vga_wait_for_hsync_end();
- }
-
- switch (cc) {
- case 0:
- tr += cd;
- if (tr > 63) { tr=63; cd = -1; cc++; }
- else if (tr < 0) { tr=0; cd = 1; cc++; }
- break;
- case 1:
- tg += cd;
- if (tg > 63) { tg=63; cd = -1; cc++; }
- else if (tg < 0) { tg=0; cd = 1; cc++; }
- break;
- case 2:
- tb += cd;
- if (tb > 63) { tb=63; cd = -1; cc++; }
- else if (tb < 0) { tb=0; cd = 1; cc++; }
- break;
- default:
- cc = 0;
- break;
- }
-
- x += v;
- if (x == 0) v = 1;
- else if (x == 392) v = -1;
- } while (1);
- _sti();
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'Y') {
- if (vga_flags & VGA_IS_VGA) {
- volatile VGA_RAM_PTR wr;
- unsigned int w,h,x,y,v,ii;
-
- int10_setmode(19);
- update_state_from_vga();
- vga_enable_256color_modex();
- w = 320; h = (0x10000 / (w/4));
-
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- *wr++ = y;
- *wr++ = y;
- *wr++ = y;
- *wr++ = (y&1)?15:0;
- wr += (w/4)-4;
- }
-
- for (x=16;x < w;x++) {
- vga_write_sequencer(VGA_SC_MAP_MASK,1 << (x&3));
- wr = vga_graphics_ram + (x>>2);
- for (y=0;y < h;y++) {
- *wr++ = (x^y);
- wr += (w/4)-1;
- }
- }
- while (getch() != 13);
-
- for (y=0;y < (h-200);y++) {
- if (kbhit()) {
- int c = getch();
- if (c == ' ' || c == 27) break;
- }
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- for (ii=0;ii < 32;ii++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_set_start_location(y*(w/4));
- }
- while (getch() != 13);
-
- vga_palette_lseek(0);
- for (x=0;x < 64;x++) vga_palette_write(x,x,x);
- for (x=0;x < 64;x++) vga_palette_write(x,0,0);
- for (x=0;x < 64;x++) vga_palette_write(0,x,0);
- for (x=0;x < 64;x++) vga_palette_write(0,0,x);
- while (getch() != 13);
-
- for (y=31;1;) {
- vga_wait_for_vsync();
- vga_palette_lseek(0);
- for (x=0;x < 64;x++) {
- v = (x*y)>>5;
- vga_palette_write(v,v,v);
- }
- vga_wait_for_vsync_end();
- if (y-- == 0) break;
- }
- for (y=31;1;) {
- vga_wait_for_vsync();
- vga_palette_lseek(64);
- for (x=0;x < 64;x++) {
- v = (x*y)>>5;
- vga_palette_write(v,0,0);
- }
- vga_wait_for_vsync_end();
- if (y-- == 0) break;
- }
- for (y=31;1;) {
- vga_wait_for_vsync();
- vga_palette_lseek(128);
- for (x=0;x < 64;x++) {
- v = (x*y)>>5;
- vga_palette_write(0,v,0);
- }
- vga_wait_for_vsync_end();
- if (y-- == 0) break;
- }
- for (y=31;1;) {
- vga_wait_for_vsync();
- vga_palette_lseek(192);
- for (x=0;x < 64;x++) {
- v = (x*y)>>5;
- vga_palette_write(0,0,v);
- }
- vga_wait_for_vsync_end();
- if (y-- == 0) break;
- }
- while (getch() != 13);
-
- /* now play with panning */
- w = 640; h = 400;
- vga_set_start_location(0);
- vga_set_stride(w);
- for (x=0;x < w;x++) {
- vga_write_sequencer(VGA_SC_MAP_MASK,1 << (x&3));
- wr = vga_graphics_ram + (x>>2);
- for (y=0;y < h;y++) {
- *wr++ = (x^y);
- wr += (w/4)-1;
- }
- }
- vga_write_sequencer(VGA_SC_MAP_MASK,0xF);
- for (y=128;y < h;y += 56) {
- wr = vga_graphics_ram + ((w>>2)*y);
- for (x=0;x < w;x += 4) *wr++ = 63;
- }
- vga_write_sequencer(VGA_SC_MAP_MASK,0x8);
- for (x=256;x < w;x += 56) {
- wr = vga_graphics_ram + (x>>2);
- for (y=0;y < h;y++) {
- *wr++ = 63;
- wr += (w/4)-1;
- }
- }
- vga_palette_lseek(0);
- for (x=0;x < 64;x++) vga_palette_write(x,x,x);
- for (x=0;x < 64;x++) vga_palette_write(x,0,0);
- for (x=0;x < 64;x++) vga_palette_write(0,x,0);
- for (x=0;x < 64;x++) vga_palette_write(0,0,x);
-
- x = y = 0;
- v = 0;
- do {
- if (kbhit()) {
- int c = getch();
- if (c == 27) break;
- }
-
- switch (v) {
- case 0: if (++x == (w-320)) v++; break;
- case 1: if (++y == (h-200)) v++; break;
- case 2: if (--x == 0) v++; break;
- case 3: if (--y == 0) v=0; break;
- }
-
- _cli();
- /* NTS: The CRTC double-buffers the offset register and updates at VBLANK
- * but some chipsets (ATI) don't double-buffer the hpel. If we don't
- * watch out for that our smooth pan will turn into a jumpy picture */
- /* So: Wait until raster scan is into the active area, then write offset register */
- vga_wait_for_vsync_end();
- for (ii=0;ii < 32;ii++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_set_start_location((y*(w/4))+(x>>2));
- /* Then wait for VBLANK and update hpel */
- vga_wait_for_vsync();
- vga_set_xpan((x&3)<<1);
- _sti();
- } while (1);
-
- vga_write_CRTC(0x09,0);
- x = y = 0;
- v = 0;
- do {
- if (kbhit()) {
- int c = getch();
- if (c == 27) break;
- }
-
- switch (v) {
- case 0: if (++x == (w-320)) v += 2; break;
- case 2: if (--x == 0) v = 0; break;
- }
-
- _cli();
- vga_wait_for_vsync_end();
- for (ii=0;ii < 32;ii++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_set_start_location((y*(w/4))+(x>>2));
- vga_wait_for_vsync();
- vga_set_xpan((x&3)<<1);
- _sti();
- } while (1);
-
- x = 0; v = 0;
- vga_set_xpan(0);
- vga_set_start_location(0);
- do {
- if (kbhit()) {
- int c = getch();
- if (c == 27) break;
- }
-
- switch (v) {
- case 0: if (++x == 31) v++; break;
- case 1: if (--x == 0) v=0; break;
- }
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- for (ii=0;ii < 32;ii++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_write_CRTC(9,x);
- } while (1);
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'X') {
- if (vga_flags & (VGA_IS_VGA|VGA_IS_MCGA)) {
- volatile VGA_RAM_PTR wr;
- unsigned int w,h,x,y,ii;
-
- int10_setmode(19);
- update_state_from_vga();
-
- w = 320; h = 200;
- wr = vga_graphics_ram;
-
- for (y=0;y < (h/4);y++) {
- for (x=0;x < w;x++)
- *wr++ = x;
- }
- for (;y < h;y++) {
- for (x=0;x < w;x++)
- *wr++ = (x^y);
- }
- while (getch() != 13);
-
- vga_palette_lseek(0);
- for (c=0;c < 64;c++) vga_palette_write(c,c,c);
- for (c=0;c < 64;c++) vga_palette_write(c,0,0);
- for (c=0;c < 64;c++) vga_palette_write(0,c,0);
- for (c=0;c < 64;c++) vga_palette_write(0,0,c);
- while (getch() != 13);
-
- for (y=0;y < 200;y++) {
- if (kbhit()) {
- int c = getch();
- if (c == ' ' || c == 27) break;
- }
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- for (ii=0;ii < 32;ii++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_set_start_location(y*(w/4));
- }
- while (getch() != 13);
-
- for (y=0;y < (0x40000 / w);y++) {
- if (kbhit()) {
- int c = getch();
- if (c == ' ' || c == 27) break;
- }
-
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- for (ii=0;ii < 32;ii++) {
- vga_wait_for_hsync();
- vga_wait_for_hsync_end();
- }
- vga_set_start_location(y*(w/4));
- }
- while (getch() != 13);
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only VGA/MCGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'W') {
- if (vga_flags & VGA_IS_EGA) {
- uint16_t color16;
- unsigned char mode,c;
- unsigned int w,h,x,y;
- volatile VGA_RAM_PTR wr;
-
- w = 640;
- if (vga_flags & VGA_IS_VGA) {
- mode = 18;
- h = 480;
- }
- else {
- mode = 16;
- h = 350;
- }
-
- int10_setmode(mode);
- update_state_from_vga();
- vga_write_sequencer(VGA_SC_MAP_MASK, 0xF); /* map mask register = enable all planes */
- vga_write_GC(VGA_GC_ENABLE_SET_RESET, 0x00); /* enable set/reset = no on all planes */
- vga_write_GC(VGA_GC_SET_RESET, 0x00); /* set/reset register = all zero */
- vga_write_GC(VGA_GC_BIT_MASK, 0xFF); /* all bits modified */
-
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_NONE); /* rotate=0 op=unmodified */
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 (copy CPU bits to each plane) */
- {
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- color16 = (y>>3) * 0x101;
- /* NTS: performance hack: issue 16-bit memory I/O */
- for (x=0;x < w;x += 16) {
- *((VGA_ALPHA_PTR)wr) = (uint16_t)color16;
- wr += 2;
- }
- }
- }
- while (getch() != 13);
-
- /* play with attribute controller */
- for (c=0;c < 4;c++) vga_write_AC(c,vga_AC_RGB_to_code(c,c,c));
- for ( ;c < 7;c++) vga_write_AC(c,vga_AC_RGB_to_code(c-3,0,0));
- for ( ;c < 10;c++) vga_write_AC(c,vga_AC_RGB_to_code(c-6,c-6,0));
- for ( ;c < 13;c++) vga_write_AC(c,vga_AC_RGB_to_code(0,c-9,0));
- for ( ;c < 16;c++) vga_write_AC(c,vga_AC_RGB_to_code(0,0,c-12));
- vga_AC_reenable_screen();
- while (getch() != 13);
-
- /* VGA only: play with the color palette registers */
- if (vga_flags & VGA_IS_VGA) {
- for (c=0;c < 16;c++) vga_write_AC(c,c);
- vga_AC_reenable_screen();
- vga_palette_lseek(0);
- for (c=0;c < 16;c++) {
- x = ((unsigned int)c * 63) / 15;
- vga_palette_write(x,x,x);
- }
- while (getch() != 13);
-
- vga_palette_lseek(0);
- for (c=0;c < 16;c++) {
- x = ((unsigned int)c * 63) / 15;
- vga_palette_write(x,0,0);
- }
- while (getch() != 13);
-
- vga_palette_lseek(0);
- for (c=0;c < 16;c++) {
- x = ((unsigned int)c * 63) / 15;
- vga_palette_write(0,x,0);
- }
- while (getch() != 13);
-
- vga_palette_lseek(0);
- for (c=0;c < 16;c++) {
- x = ((unsigned int)c * 63) / 15;
- vga_palette_write(0,0,x);
- }
- while (getch() != 13);
- }
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
-
- }
- else if (c == 'V') {
- if (vga_flags & VGA_IS_EGA) {
- uint16_t color16;
- unsigned char mode,color;
- unsigned int w,h,x,y;
- volatile VGA_RAM_PTR wr;
-
- /* FIXME:
- * Emulator: Oracle VirtualBox VGA emulation
- * Env: 32-BIT flat MS-DOS
- * Problem: Seems to get stuck after drawing the first test pattern
- *
- * Also related to:
- *
- * Emulator: Microsoft Virtual PC
- * Problem: DOS32A complains that INT 43H was modified (only after running this routine)
- */
-
- for (mode=13;mode <= 18;mode++) {
- if (mode == 15 || mode == 17) continue; /* skip mono modes */
- if (mode == 18 && (vga_flags & VGA_IS_VGA) == 0) continue; /* skip 640x480x16 if not VGA */
-
- if (mode == 13)
- w = 320;
- else
- w = 640;
-
- if (mode >= 17)
- h = 480;
- else if (mode >= 15)
- h = 350;
- else
- h = 200;
-
- int10_setmode(mode);
- update_state_from_vga();
- vga_write_sequencer(VGA_SC_MAP_MASK, 0xF); /* map mask register = enable all planes */
- vga_write_GC(VGA_GC_ENABLE_SET_RESET, 0x00); /* enable set/reset = no on all planes */
- vga_write_GC(VGA_GC_SET_RESET, 0x00); /* set/reset register = all zero */
- vga_write_GC(VGA_GC_BIT_MASK, 0xFF); /* all bits modified */
-
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_NONE); /* rotate=0 op=unmodified */
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 (copy CPU bits to each plane) */
- {
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- color16 = (y>>3) * 0x101;
- /* NTS: performance hack: issue 16-bit memory I/O */
- for (x=0;x < w;x += 16) {
- *((VGA_ALPHA_PTR)wr) = (uint16_t)color16;
- wr += 2;
- }
- }
- }
- while (getch() != 13);
-
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 */
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_NONE); /* rotate=0 op=none */
- {
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- vga_write_GC(VGA_GC_BIT_MASK,0x55 << (y & 1));
- color = y>>4;
- for (x=0;x < w;x += 8) {
- vga_force_read(wr); /* NTS: or else Watcom C++ optimizes the read out.
- without the read the VGA latches will contain
- other unexpected junk and we get the pattern wrong */
- vga_force_write(wr,color);
- wr++;
- }
- }
- while (getch() != 13);
- }
-
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 */
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_AND); /* rotate=0 op=AND */
- {
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- vga_write_GC(VGA_GC_BIT_MASK,((y&6) == 0 ? 0xFF : 0xC0));
- color = 1 << ((y>>5)&3);
- for (x=0;x < w;x += 8) {
- vga_force_read(wr); /* NTS: or else Watcom C++ optimizes the read out.
- without the read the VGA latches will contain
- other unexpected junk and we get the pattern wrong */
- vga_force_write(wr,color);
- wr++;
- }
- }
- while (getch() != 13);
- }
-
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 */
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_OR); /* rotate=0 op=OR */
- {
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- vga_write_GC(VGA_GC_BIT_MASK,((y&6) == 0 ? 0xFF : 0xC0));
- color = 8 << ((y>>5)&3);
- for (x=0;x < w;x += 8) {
- vga_force_read(wr); /* NTS: or else Watcom C++ optimizes the read out.
- without the read the VGA latches will contain
- other unexpected junk and we get the pattern wrong */
- vga_force_write(wr,color);
- wr++;
- }
- }
- while (getch() != 13);
- }
-
- vga_write_GC(VGA_GC_MODE, 0x02); /* 256=0 CGAstyle=0 odd/even=0 readmode=0 writemode=2 */
- vga_write_GC(VGA_GC_DATA_ROTATE, 0 | VGA_GC_DATA_ROTATE_OP_XOR); /* rotate=0 op=XOR */
- {
- wr = vga_graphics_ram;
- for (y=0;y < h;y++) {
- vga_write_GC(VGA_GC_BIT_MASK,((y&6) == 0 ? 0xFF : 0xC0));
- for (x=0;x < w;x += 8) {
- vga_force_read(wr); /* NTS: or else Watcom C++ optimizes the read out.
- without the read the VGA latches will contain
- other unexpected junk and we get the pattern wrong */
- vga_force_write(wr,15);
- wr++;
- }
- }
- while (getch() != 13);
- }
- }
-
- /* now play with Attribute Controller registers (EGA palette mapping) */
- vga_write_AC(0,0);
- vga_write_AC(1,8);
- vga_write_AC(2,7);
- vga_write_AC(3,15);
- vga_AC_reenable_screen();
- while (getch() != 13);
-
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'P') {
-#if TARGET_MSDOS == 16 && defined(__COMPACT__)
-#else
- if (vga_flags & VGA_IS_TANDY) {
- /* 160x200x16 */
- int10_setmode(8);
- {
- unsigned char row[160];
- unsigned int x,y;
- VGA_RAM_PTR wr;
-
- for (y=0;y < (160/2);y++)
- row[y] = ((y * 0x10) / 80) * 0x11;
-
- for (y=0;y < 80;y++) {
- wr = vga_graphics_ram + ((160/2) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (160/2);x++) wr[x] = row[x];
- }
-
- for (y=0;y < (160/2);y++) {
- x = (y * 0x20) / 80;
- row[y] = (x>>1) * 0x11;
- if (row[y] == 0xFF || (x&1) == 0) {
- row[y+(160/2)] = row[y];
- }
- else {
- row[y+(160/2)] = row[y] + 0x10;
- row[y] += 0x01;
- }
- }
-
- for (y=80;y < 160;) {
- wr = vga_graphics_ram + ((160/2) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (160/2);x++) wr[x] = row[x];
- y++;
-
- wr = vga_graphics_ram + ((160/2) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (160/2);x++) wr[x] = row[x+(160/2)];
- y++;
- }
- }
- while (getch() != 13);
- vga_tandy_setpalette(1,8);
- vga_tandy_setpalette(2,7);
- vga_tandy_setpalette(3,15);
- while (getch() != 13);
-
- /* 320x200x16 */
- int10_setmode(9);
- {
- unsigned char row[320];
- unsigned int x,y;
- VGA_RAM_PTR wr;
-
- for (y=0;y < (320/2);y++)
- row[y] = ((y * 0x10) / 160) * 0x11;
-
- for (y=0;y < 80;y++) {
- wr = vga_graphics_ram + ((320/2) * (y>>2)) + ((y&3) << 13);
- for (x=0;x < (320/2);x++) wr[x] = row[x];
- }
-
- for (y=0;y < (320/2);y++) {
- x = (y * 0x20) / 160;
- row[y] = (x>>1) * 0x11;
- if (row[y] == 0xFF || (x&1) == 0) {
- row[y+(320/2)] = row[y];
- }
- else {
- row[y+(320/2)] = row[y] + 0x10;
- row[y] += 0x01;
- }
- }
-
- for (y=80;y < 160;) {
- wr = vga_graphics_ram + ((320/2) * (y>>2)) + ((y&3) << 13);
- for (x=0;x < (320/2);x++) wr[x] = row[x];
- y++;
-
- wr = vga_graphics_ram + ((320/2) * (y>>2)) + ((y&3) << 13);
- for (x=0;x < (320/2);x++) wr[x] = row[x+(320/2)];
- y++;
- }
- }
- while (getch() != 13);
- vga_tandy_setpalette(1,8);
- vga_tandy_setpalette(2,7);
- vga_tandy_setpalette(3,15);
- while (getch() != 13);
-
- /* 640x200x4 */
- /* NTS: Oh, ick. I see... the 640x mode could be thought of as groups of pixels
- * per 16-bit WORD, where each byte is a monochromatic bitmap 8 pixels wide
- * and the two put together form 2-bit values!
- *
- * byte 0 = 8x wide mono bitmap, forms lsb
- * byte 1 = 8x wide mono bitmap, forms msb */
- int10_setmode(10);
- {
- static uint16_t t4pat[4] = {
- 0x0055,
- 0x55AA,
- 0xFF55,
- 0xFFFF
- };
- uint16_t row[(640/8)*2];
- unsigned int x,y;
- VGA_ALPHA_PTR wr;
-
- for (y=0;y < (640/8);y++) {
- x = (y * 4) / (640/8);
- row[y] = (x & 1) * 0xFFU;
- row[y] |= ((x & 2) >> 1) * 0xFF00U;
- }
-
- for (y=0;y < 80;y++) {
- wr = vga_alpha_ram + ((640/8) * (y>>2)) + (((y&3) << 13)>>1);
- for (x=0;x < (640/8);x++) wr[x] = row[x];
- }
-
- for (y=0;y < (640/8);y++) {
- x = (y * 8) / (640/8);
- if (x & 1) {
- unsigned int c = t4pat[x>>1];
- row[y] = c;
- row[y+(640/8)] =
- ((((c&0xFF) << 1) | ((c&0xFF) >> 7)) & 0x00FF) |
- (((((c>>8)&0xFF) << 1) | (((c>>8)&0xFF) >> 7)) << 8);
- }
- else {
- row[y] = ((x & 2) >> 1) * 0xFFU;
- row[y] |= ((x & 4) >> 2) * 0xFF00U;
- row[y+(640/8)] = row[y];
- }
- }
-
- for (y=80;y < 160;) {
- wr = vga_alpha_ram + ((640/8) * (y>>2)) + (((y&3) << 13)>>1);
- for (x=0;x < (640/8);x++) wr[x] = row[x];
- y++;
-
- wr = vga_alpha_ram + ((640/8) * (y>>2)) + (((y&3) << 13)>>1);
- for (x=0;x < (640/8);x++) wr[x] = row[x+(640/8)];
- y++;
- }
- }
- while (getch() != 13);
- vga_tandy_setpalette(1,8);
- vga_tandy_setpalette(2,7);
- vga_tandy_setpalette(3,15);
- while (getch() != 13);
-
- /* TODO: figure out 640x200x16 */
-
- int10_setmode(3);
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only Tandy/CGA or compatible may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
-#endif
- }
- else if (c == 'D') {
- if (vga_flags & VGA_IS_CGA) { /* NTS: This test also works on EGA/VGA */
- int10_setmode(4);
- if ((vga_flags & (VGA_IS_EGA|VGA_IS_VGA|VGA_IS_TANDY)) == 0) /* this part of the test doesn't work on EGA/VGA nor does it work on Tandy/PCjr */
- vga_set_cga_palette_and_background(0,0);
-
- {
- unsigned int x,y;
- VGA_RAM_PTR wr;
-
- for (y=0;y < 80;y++) {
- wr = vga_graphics_ram + ((320/4) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (((320/4)*1)/4);x++) *wr++ = 0;
- for ( ;x < (((320/4)*2)/4);x++) *wr++ = 0x55;
- for ( ;x < (((320/4)*3)/4);x++) *wr++ = 0xAA;
- for ( ;x < (((320/4)*4)/4);x++) *wr++ = 0xFF;
- }
- for (;y < 160;y++) {
- wr = vga_graphics_ram + ((320/4) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (((320/4)*1)/8);x++) *wr++ = 0;
- for ( ;x < (((320/4)*2)/8);x++) *wr++ = 0x11 << ((y&1)<<1);
- for ( ;x < (((320/4)*3)/8);x++) *wr++ = 0x55;
- for ( ;x < (((320/4)*4)/8);x++) *wr++ = (y&1) ? 0x66 : 0x99;
- for ( ;x < (((320/4)*5)/8);x++) *wr++ = 0xAA;
- for ( ;x < (((320/4)*6)/8);x++) *wr++ = (y&1) ? 0xBB : 0xEE;
- for ( ;x < (((320/4)*8)/8);x++) *wr++ = 0xFF;
- }
- }
- if ((vga_flags & (VGA_IS_EGA|VGA_IS_VGA|VGA_IS_TANDY)) == 0) {/* this part of the test doesn't work on EGA/VGA */
- while (getch() != 13);
- vga_set_cga_palette_and_background(0,VGA_CGA_PALETTE_CS_BLUE);
- while (getch() != 13);
- vga_set_cga_palette_and_background(0,VGA_CGA_PALETTE_CS_ALT_INTENSITY);
- while (getch() != 13);
- vga_set_cga_palette_and_background(1,0);
- while (getch() != 13);
- vga_set_cga_palette_and_background(1,VGA_CGA_PALETTE_CS_ALT_INTENSITY);
- while (getch() != 13);
- vga_set_cga_mode(VGA_CGA_MODE_40WIDE|VGA_CGA_MODE_GRAPHICS|VGA_CGA_MODE_BW|VGA_CGA_MODE_VIDEO_ENABLE|VGA_CGA_MODE_VIDEO_640);
- vga_set_cga_palette_and_background(0,0xF); /* RGBI=1 aka white */
- while (getch() != 13);
- /* heheh... CGA composite mode. DOSBox actually emulates it too :) */
- /* see how it works? You're supposed to set BW=1 in 640x200 mode but we don't. on the composite video
- * out this leaves the color subcarrier on where the fine pixels can get confused with the color subcarrier */
- vga_set_cga_mode(VGA_CGA_MODE_40WIDE|VGA_CGA_MODE_GRAPHICS|VGA_CGA_MODE_VIDEO_ENABLE|VGA_CGA_MODE_VIDEO_640);
- vga_set_cga_palette_and_background(0,0xF); /* RGBI=1 aka white */
- while (getch() != 13);
- {
- unsigned char c,color;
- unsigned int x,y;
- VGA_RAM_PTR wr;
-
- /* in composite mode make up something to show more colors */
- for (y=0;y < 200;y++) {
- color = (y*0x10)/200;
- c = color * 0x11;
- wr = vga_graphics_ram + ((320/4) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (320/4);x++) *wr++ = c;
- }
- }
- while (getch() != 13);
- /* heheh... CGA composite mode. DOSBox actually emulates it too :) */
- /* see how it works? You're supposed to set BW=1 in 640x200 mode but we don't. on the composite video
- * out this leaves the color subcarrier on where the fine pixels can get confused with the color subcarrier */
- vga_set_cga_mode(VGA_CGA_MODE_40WIDE|VGA_CGA_MODE_GRAPHICS|VGA_CGA_MODE_BW|VGA_CGA_MODE_VIDEO_ENABLE|VGA_CGA_MODE_VIDEO_640);
- vga_set_cga_palette_and_background(0,0xF); /* RGBI=1 aka white */
- while (getch() != 13);
- vga_set_cga_mode(VGA_CGA_MODE_40WIDE|VGA_CGA_MODE_GRAPHICS|VGA_CGA_MODE_VIDEO_ENABLE);
- vga_set_cga_palette_and_background(1,VGA_CGA_PALETTE_CS_ALT_INTENSITY);
- while (getch() != 13);
- vga_set_cga_mode(VGA_CGA_MODE_40WIDE|VGA_CGA_MODE_GRAPHICS|VGA_CGA_MODE_VIDEO_ENABLE);
- vga_set_cga_palette_and_background(0,VGA_CGA_PALETTE_CS_ALT_INTENSITY);
- while (getch() != 13);
- }
- else { /* EGA/VGA compatible test */
- /* NTS: We have to redraw it. Some VGA clones (primarily Intel 855/915/945 chipsets) do not properly
- * handle INT 10H mode changes with "preserve video memory" set. Not because they're assholes,
- * but because of the funky way that Intel chipsets interleave the data in actual RAM. */
- while (getch() != 13);
- int10_setmode(6);
- {
- unsigned int x,y;
- VGA_RAM_PTR wr;
-
- for (y=0;y < 80;y++) {
- wr = vga_graphics_ram + ((320/4) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (((320/4)*1)/4);x++) *wr++ = 0;
- for ( ;x < (((320/4)*2)/4);x++) *wr++ = 0x55;
- for ( ;x < (((320/4)*3)/4);x++) *wr++ = 0xAA;
- for ( ;x < (((320/4)*4)/4);x++) *wr++ = 0xFF;
- }
- for (;y < 160;y++) {
- wr = vga_graphics_ram + ((320/4) * (y>>1)) + ((y&1) << 13);
- for (x=0;x < (((320/4)*1)/8);x++) *wr++ = 0;
- for ( ;x < (((320/4)*2)/8);x++) *wr++ = 0x11 << ((y&1)<<1);
- for ( ;x < (((320/4)*3)/8);x++) *wr++ = 0x55;
- for ( ;x < (((320/4)*4)/8);x++) *wr++ = (y&1) ? 0x66 : 0x99;
- for ( ;x < (((320/4)*5)/8);x++) *wr++ = 0xAA;
- for ( ;x < (((320/4)*6)/8);x++) *wr++ = (y&1) ? 0xBB : 0xEE;
- for ( ;x < (((320/4)*8)/8);x++) *wr++ = 0xFF;
- }
- }
- while (getch() != 13);
- }
-
- int10_setmode(3);
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else {
- vga_write("Only CGA or compatible may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == '!') {
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA)) {
- unsigned char mono = (vga_ram_base == 0xB0000) ? 1 : 0;
- unsigned char c;
-
- vga_clear();
- vga_moveto(0,0);
- vga_write_color(7);
- vga_write("I will switch the VGA through all four map modes on each CRTC config.\n\n");
- vga_moveto(0,2);
- vga_write(" CUR MONO COL\n");
- /* row = 2 */
- vga_write("A0000+128KB \n");
- vga_write("A0000+64KB \n");
- vga_write("B0000+32KB \n");
- vga_write("B8000+32KB \n");
- vga_write("\n");
- vga_write_color(0x2F);
-
- for (c=0;c <= 3;c++) {
- vga_set_memory_map(c);
- vga_moveto(12,3+c);
- vga_write("OK");
- }
-
- vga_relocate_crtc(0);
- vga_write_CRTC(0xF,1);
- if (vga_read_CRTC(0xF) == 1) {
- for (c=0;c <= 3;c++) {
- vga_set_memory_map(c);
- vga_moveto(12+5,3+c);
- vga_write("OK");
- }
- }
-
- vga_relocate_crtc(1);
- vga_write_CRTC(0xF,1);
- if (vga_read_CRTC(0xF) == 1) {
- for (c=0;c <= 3;c++) {
- vga_set_memory_map(c);
- vga_moveto(12+(5*2),3+c);
- vga_write("OK");
- }
- }
-
- vga_set_memory_map(mono ? 2 : 3);
- vga_relocate_crtc(mono ? 0 : 1);
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'H') {
-#if TARGET_MSDOS == 16 && defined(__COMPACT__)
-#else
- if (vga_flags & VGA_IS_HGC) {
- vga_turn_on_hgc();
- {
- unsigned char pat;
- unsigned int x,y;
- VGA_RAM_PTR wr;
-
- /* clear */
- wr = vga_graphics_ram;
- for (x=0;x < 0x8000;x++) *wr++ = 0x00;
-
- /* draw hatch pattern */
- for (y=0;y < 348;y++) {
- wr = vga_graphics_ram + ((y>>2) * (720/8)) + ((y&3) << 13);
- pat = 0x55 << (y & 1);
- for (x=0;x < (720/8);x++) *wr++ = pat;
- }
-
- /* and another pattern */
- for (y=0;y <= 120;y++) {
- wr = vga_graphics_ram + ((y>>2) * (720/8)) + ((y&3) << 13) + 14;
- pat = (y % 4) == 0 ? 0xFF : 0x88;
- for (x=0;x < (240/8);x++) *wr++ = pat;
- }
- }
- while (getch() != 13);
-
- vga_turn_off_hgc();
- }
- else {
- vga_write("Only HGC hercules MDA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
-#endif
- }
- else if (c == 'T') {
- int10_setmode(3);
- update_state_from_vga();
- if (vga_flags & VGA_IS_VGA && vga_want_9wide != 0xFF) vga_set_9wide(vga_want_9wide);
- }
- else if (c == 'M') {
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA)) {
- vga_switch_to_mono();
- update_state_from_vga();
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'C') {
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA)) {
- vga_switch_to_color();
- update_state_from_vga();
- }
- else {
- vga_write("Only EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
- }
- else if (c == 'o') {
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA)) {
- unsigned char color;
-
- inp(vga_base_3x0+0xA); /* reset flipflop */
- outp(0x3C0,0x11); /* load overscan color reg */
- color = inp(0x3C1);
- color++;
-
- inp(vga_base_3x0+0xA); /* reset flipflop */
- outp(0x3C0,0x11); /* load overscan color reg */
- outp(0x3C0,color);
- outp(0x3C0,0x20); /* PAS=1 */
- }
- }
- else if (c == 'z') {
-#ifdef TARGET_WINDOWS
-#elif TARGET_MSDOS == 16 && (defined(__COMPACT__) || defined(__SMALL__))
-#else
- write_8254_system_timer(0); /* make sure the timer is in rate generator mode, full counter */
- if (vga_flags & (VGA_IS_VGA|VGA_IS_EGA|VGA_IS_CGA)) {
- unsigned int b_frame,e_retrace,b_vsync,e_frame_active,e_frame;
- unsigned int vlines=0;
- unsigned char b,hex;
- unsigned int j;
- char tmp[128];
-
- while (1) {
- vlines = 0;
-
- vga_clear();
- vga_moveto(0,0);
- vga_write_color(0x7);
- vga_write("Measuring htotal and vtotal...\n");
-
- _cli();
- /* wait for vsync to pass */
- vga_wait_for_vsync();
- vga_wait_for_vsync_end();
- /* NTS: we measure the frame vsync to vsync */
- b_frame = e_frame_active = read_8254(0);
- /* wait for active picture area first (exit retrace) */
- do { b = inp(vga_base_3x0 + 0xA);
- } while (b&1);
- e_retrace = read_8254(0);
- hex = b; vlines++; /* count the start of line */
- do {
- b = inp(vga_base_3x0 + 0xA);
- if ((b&1) != (hex&1)) {
- hex = b;
- if (!(b&1)) vlines++; /* start of a line */
- else e_frame_active = read_8254(0); /* end of line, possibly start of retrace */
- }
- if (b&8) {
- /* we just entered vsync */
- b_vsync = read_8254(0);
- break;
- }
- } while (1);
- /* wait for vsync to end */
- vga_wait_for_vsync_end();
- e_frame = read_8254(0);
- /* compute timing */
- b_vsync = (b_vsync - e_frame) & 0xFFFF;
- e_retrace = (b_frame - e_retrace) & 0xFFFF;
- e_frame_active = (e_frame_active - e_frame) & 0xFFFF;
- b_frame = (b_frame - e_frame) & 0xFFFF; /* remember: timer counts DOWN, 16-bit wide */
-
- sprintf(tmp," vertical lines: %u active\n",vlines);
- vga_write(tmp);
-
- sprintf(tmp," vertical refresh: %.3fms total\n vertical retrace: %.3fms (%.3fms top + %.3fms bottom)\n vertical sync pulse: %.3fms\n",
- ((double)b_frame * 1000) / T8254_REF_CLOCK_HZ,
- ((double)((unsigned long)e_retrace + (unsigned long)e_frame_active) * 1000) / T8254_REF_CLOCK_HZ,
- ((double)e_retrace * 1000) / T8254_REF_CLOCK_HZ,
- ((double)e_frame_active * 1000) / T8254_REF_CLOCK_HZ,
- ((double)b_vsync * 1000) / T8254_REF_CLOCK_HZ);
- vga_write(tmp);
-
- sprintf(tmp," vertical refresh rate: %.3fHz\n",
- 1000.0 / (((double)b_frame * 1000) / T8254_REF_CLOCK_HZ));
- vga_write(tmp);
-
- sprintf(tmp," horizontal refresh rate: %.6fKHz\n",
- 1.0 / (((double)(b_frame - e_frame_active - e_retrace) * 1000) / vlines / T8254_REF_CLOCK_HZ));
- vga_write(tmp);
-
- _sti();
-
- if (kbhit()) {
- if (getch() == 27) break;
- }
-
- for (j=0;j < 9;j++) t8254_wait(0xFFFF); /* 1/18.2 */
- }
- }
- else {
- vga_write("Only CGA/EGA/VGA may do that\n");
- vga_write_sync();
- vga_sync_bios_cursor();
- while (getch() != 13);
- }
-#endif
- }
- }
- vga_sync_bios_cursor();
-
-#if defined(TARGET_WINDOWS)
- DisplayDibDoEnd();
- if (DisplayDibUnloadDLL())
- MessageBox(hwnd,dispDibLastError,"Failed to unload DISPDIB.DLL",MB_OK);
-
-# if TARGET_MSDOS == 32
- FreeWin16EB();
-# endif
-#endif
-
- return 0;
-}
-
+++ /dev/null
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <ctype.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/vga/vgatty.h>
-#include <hw/8254/8254.h>
-#include <hw/dos/doswin.h>
-
-#if defined(TARGET_WINDOWS)
-# error WRONG
-#endif
-
-char tmpline[80];
-
-void bios_cls() {
- VGA_ALPHA_PTR ap;
- VGA_RAM_PTR rp;
- unsigned char m;
-
- m = int10_getmode();
- if ((rp=vga_graphics_ram) != NULL && !(m <= 3 || m == 7)) {
-#if TARGET_MSDOS == 16
- unsigned int i,im;
-
- im = (FP_SEG(vga_graphics_ram_fence) - FP_SEG(vga_graphics_ram));
- if (im > 0xFFE) im = 0xFFE;
- im <<= 4;
- for (i=0;i < im;i++) vga_graphics_ram[i] = 0;
-#else
- while (rp < vga_graphics_ram_fence) *rp++ = 0;
-#endif
- }
- else if ((ap=vga_alpha_ram) != NULL) {
-#if TARGET_MSDOS == 16
- unsigned int i,im;
-
- im = (FP_SEG(vga_alpha_ram_fence) - FP_SEG(vga_alpha_ram));
- if (im > 0x7FE) im = 0x7FE;
- im <<= 4 - 1; /* because ptr is type uint16_t */
- for (i=0;i < im;i++) vga_alpha_ram[i] = 0x0720;
-#else
- while (ap < vga_alpha_ram_fence) *ap++ = 0x0720;
-#endif
- }
- else {
- printf("WARNING: bios cls no ptr\n");
- }
-}
-
-unsigned int common_prompt_number() {
- unsigned int nm;
-
- tmpline[0] = 0;
- fgets(tmpline,sizeof(tmpline),stdin);
- if (isdigit(tmpline[0]))
- nm = (unsigned int)strtoul(tmpline,NULL,0);
- else
- nm = ~0U;
-
- return nm;
-}
-
-void help_main() {
- int c;
-
- bios_cls();
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("VGA library state:\n");
- printf("\n");
- printf(" VGA= (1) VGA detected\n");
- printf(" EGA= (1) EGA detected/compat\n");
- printf(" CGA= (1) CGA detected/compat\n");
- printf(" MDA= (1) MDA detected/compat\n");
- printf(" MCGA= (1) MCGA detected/compat\n");
- printf(" HGC= Hercules detected & what\n");
- printf(" Tandy/PCjr= Tandy or PCjr detected\n");
- printf(" Amstrad= Amstrad detected\n");
- printf(" IO= Base I/O port (3B0/3D0)\n");
- printf(" ALPHA= (1) Alphanumeric mode\n");
- printf(" RAM VGA RAM mapping\n");
- printf(" 9W= (1) VGA lib 9-pixel mode\n");
- printf(" INT10= Active INT10h video mode\n");
- printf("\n");
- printf("ESC to return, ENTER/SPACE for more...\n");
-
- c = getch();
- if (c == 27) return;
-
- bios_cls();
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("VGA CRTC state:\n");
- printf("\n");
- printf(" Clock= Dot clock selection (0-3)\n");
- printf(" div2= (1) Divide dot clock by 2\n");
- printf(" pix/clk= pixels/char clk (8 or 9)\n");
- printf(" Word= (1) Word mode\n");
- printf(" Dword= (1) Doubleword mode\n");
- printf(" Hsync -/+ Hsync polarity\n");
- printf(" Vsync -/+ Vsync polarity\n");
- printf(" mem4= Mem clock divide by 4\n");
- printf(" SLR= Shift/load rate\n");
- printf(" S4= Shift 4 enable\n");
- printf(" memdv2= (1) Div memaddr by 2\n");
- printf(" scandv2= (1) Div scanlineclk by 2\n");
- printf(" awrap= (1) Address wrap select\n");
- printf(" map14= (1) Map MA14 = bit 14\n");
- printf(" map13= (1) Map MA13 = bit 13\n");
- printf(" ref/scanline= Refresh cycles/scanline\n");
- printf(" hrate/vrate= Horz./Vert. refresh rate\n");
- printf(" offset= offset (unit per scanline)\n");
- printf("\n");
- printf("ESC to return, ENTER/SPACE for more...\n");
-
- c = getch();
- if (c == 27) return;
-
- bios_cls();
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("VGA CRTC state (cont):\n");
- printf("\n");
- printf(" V:tot= Vertical total\n");
- printf(" disp= .. active display\n");
- printf(" retr= .. retrace as inequality\n");
- printf(" blnk= .. blanking as inequality\n");
- printf(" H:tot= Horizontal total (chars)\n");
- printf(" disp= .. active display\n");
- printf(" retr= .. retrace as inequality\n");
- printf(" blnk= .. blanking as inequality\n");
- printf(" sdtot= .. start delay after total\n");
- printf(" sdretr= .. start delay aft retrace\n");
- printf(" scan2x= Scan double bit\n");
- printf(" maxscanline= Max scanline per cell or row\n");
- printf("\n");
- printf("ESC to return, ENTER/SPACE for more...\n");
-
- c = getch();
- if (c == 27) return;
-}
-
-static unsigned char rdump[4096];
-
-void dump_to_file() {
- char tmpname[32];
- char nname[17];
- int c,mode,i;
- FILE *fp;
-
- mode = int10_getmode();
- sprintf(nname,"VGADMP%02X",mode);
-
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("Standard VGA registers and RAM will be\n");
- printf("dumped to %s. Hit ENTER to proceed.\n",nname);
- printf("\n");
- printf("\n");
- printf("\n");
-
- for (c=0;c < 40;c++) {
- unsigned short b,cc;
-
- vga_moveto(c,3);
- vga_sync_bios_cursor();
- cc = 0x0930 + (c&0xF);
- b = c;
-
- __asm {
- push ax
- push bx
- push cx
- mov ax,cc
- mov bx,b
- mov cx,1
- int 10h
- pop cx
- pop bx
- pop ax
- }
- }
- vga_moveto(0,5);
- vga_sync_bios_cursor();
-
- c = getch();
- if (c != 13) return;
-
- /* ============= Sequencer ============ */
- for (i=0;i < 256;i++) rdump[i] = vga_read_sequencer(i);
-
- /* ----- write */
- sprintf(tmpname,"%s.SEQ",nname);
- if ((fp=fopen(tmpname,"wb")) != NULL) {
- fwrite(rdump,256,1,fp);
- fclose(fp);
- }
-
- /* ============= GC ============ */
- for (i=0;i < 256;i++) rdump[i] = vga_read_GC(i);
-
- /* ----- write */
- sprintf(tmpname,"%s.GC",nname);
- if ((fp=fopen(tmpname,"wb")) != NULL) {
- fwrite(rdump,256,1,fp);
- fclose(fp);
- }
-
- /* ============= CRTC ============ */
- for (i=0;i < 256;i++) rdump[i] = vga_read_CRTC(i);
-
- /* ----- write */
- sprintf(tmpname,"%s.CRT",nname);
- if ((fp=fopen(tmpname,"wb")) != NULL) {
- fwrite(rdump,256,1,fp);
- fclose(fp);
- }
-
- /* ============= Attribute controller ============ */
- for (i=0;i < 256;i++) rdump[i] = vga_read_AC(i);
-
- /* ----- write */
- sprintf(tmpname,"%s.AC",nname);
- if ((fp=fopen(tmpname,"wb")) != NULL) {
- fwrite(rdump,256,1,fp);
- fclose(fp);
- }
-
- /* ============= VGA palette ============ */
- outp(0x3C8,0);
- outp(0x3C7,0);
- for (i=0;i < (2*3*256);i++) rdump[i] = inp(0x3C9);
-
- /* ----- write */
- sprintf(tmpname,"%s.DAC",nname);
- if ((fp=fopen(tmpname,"wb")) != NULL) {
- fwrite(rdump,2*3*256,1,fp);
- fclose(fp);
- }
-
- /* ============= Reg scan/dump ============ */
- for (i=0;i < 0x30;i++) rdump[i] = inp(0x3B0+i);
-
- /* ----- write */
- sprintf(tmpname,"%s.RED",nname);
- if ((fp=fopen(tmpname,"wb")) != NULL) {
- fwrite(rdump,0x30,1,fp);
- fclose(fp);
- }
-
- /* ============= RAM scan/dump ============ */
- {
- unsigned char seq4,crt17h,crt14h,pl,ogc5,ogc6,seqmask;
-
- ogc6 = vga_read_GC(6);
- ogc5 = vga_read_GC(5);
- seq4 = vga_read_sequencer(4);
- seqmask = vga_read_sequencer(VGA_SC_MAP_MASK);
- crt14h = vga_read_CRTC(0x14);
- crt17h = vga_read_CRTC(0x17);
-
- /* switch into planar mode briefly for planar capture */
- vga_write_sequencer(4,0x06);
- vga_write_sequencer(0,0x01);
- vga_write_sequencer(0,0x03);
- vga_write_sequencer(VGA_SC_MAP_MASK,0xF);
-
- /* for each plane, write to file */
- for (pl=0;pl < 4;pl++) {
- sprintf(tmpname,"%s.PL%u",nname,pl);
- if ((fp=fopen(tmpname,"wb")) != NULL) {
- vga_write_sequencer(4,0x06);
- vga_write_GC(6,(ogc6 & (~0xF)) + (1 << 2) + 1); /* we want video RAM to map to 0xA0000-0xAFFFF AND we want to temporarily disable alphanumeric mode */
- vga_write_GC(5,(ogc5 & (~0x7B))); /* read mode=0 write mode=0 host o/e=0 */
- vga_write_GC(4,pl); /* read map select */
-
- for (i=0;i < (65536/1024);i++) {
- unsigned int j;
-
-#if TARGET_MSDOS == 32
- volatile unsigned char *s = ((volatile unsigned char*)0xA0000) + (unsigned int)(i * 1024);
- volatile unsigned char *d = (volatile unsigned char*)rdump;
- for (j=0;j < 1024;j++) d[j] = s[j];
-#else
- volatile unsigned char FAR *s = (volatile unsigned char FAR*)MK_FP(0xA000,(i * 1024));
- volatile unsigned char FAR *d = (volatile unsigned char FAR*)rdump;
- for (j=0;j < 1024;j++) d[j] = s[j];
-#endif
- fwrite(rdump,1024,1,fp);
- }
- fclose(fp);
- vga_write_GC(6,ogc6); /* restore */
- }
- }
-
- vga_write_sequencer(4,seq4);
- vga_write_sequencer(0,0x01);
- vga_write_sequencer(0,0x03);
- vga_write_sequencer(VGA_SC_MAP_MASK,seqmask);
- vga_write_CRTC(0x14,crt14h);
- vga_write_CRTC(0x17,crt17h);
- vga_write_GC(5,ogc5);
- vga_write_GC(6,ogc6);
- }
-
- /* ======================================= */
- printf("Done\n");
- while (getch() != 13);
-}
-
-/* utility function to flash VGA color palette registers */
-void flash_vga_pal() {
- unsigned char palidx,palold[3],palflash=1,w[3],redraw=1,flashwait=0,vga_mode;
- int c;
-
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- vga_mode = int10_getmode();
-
- printf("Flashing VGA color palette entry.\n");
- printf("ESC to quit, use Left/Right arrow keys\n");
- printf("to select palette entry, Up/Down to\n");
- printf("change values.\n");
- printf("\n");
-
- palidx = 40;
- for (c=0;c < palidx;c++) {
- unsigned short b,cc;
-
- vga_moveto(c,5);
- vga_sync_bios_cursor();
- cc = 0x0930 + (c&0xF);
- b = c;
-
- __asm {
- push ax
- push bx
- push cx
- mov ax,cc
- mov bx,b
- mov cx,1
- int 10h
- pop cx
- pop bx
- pop ax
- }
- }
- printf("\n");
- printf("\n");
-
- /* 320x200x256 mode: draw all 256 colors for ref */
- if (vga_mode == 19 && vga_graphics_ram != NULL) {
- VGA_RAM_PTR draw;
- unsigned int x,y;
-
- for (y=0;y < 8;y++) {
- draw = vga_graphics_ram + (320 * (200 - 1 - y));
- for (x=0;x < 256;x++) *draw++ = x;
- }
- }
-
- palidx = 7; /* start with color 7 (the text we print) */
- vga_read_PAL(palidx,palold,1);
-
- while (1) {
- t8254_wait(0x10000UL); /* 9 / 18.2Hz = 0.5 second (about). no faster. don't give users seizures. */
-
- if (redraw) {
- printf("\x0D" "idx=0x%02x val=0x%02x%02x%02x",
- palidx,palold[0],palold[1],palold[2]);
- fflush(stdout);
- redraw = 0;
- }
-
- if (kbhit()) {
- c = getch();
- if (c == 27)
- break;
- else if (c == 0) {
- c = getch();
- if (c == 0x4B) { /* left */
- vga_write_PAL(palidx,palold,1);
- palidx--;
- vga_read_PAL(palidx,palold,1);
- flashwait = 9 - 1;
- palflash = 1;
- redraw = 1;
- }
- else if (c == 0x4D) { /* right */
- vga_write_PAL(palidx,palold,1);
- palidx++;
- vga_read_PAL(palidx,palold,1);
- flashwait = 9 - 1;
- palflash = 1;
- redraw = 1;
- }
- else if (c == 0x48) { /* up */
- palold[0]++;
- palold[1]++;
- palold[2]++;
- vga_write_PAL(palidx,palold,1);
- vga_read_PAL(palidx,palold,1);
- flashwait = 255 - 20;
- palflash = 0;
- redraw = 1;
- }
- else if (c == 0x50) { /* down */
- palold[0]--;
- palold[1]--;
- palold[2]--;
- vga_write_PAL(palidx,palold,1);
- vga_read_PAL(palidx,palold,1);
- flashwait = 255 - 20;
- palflash = 0;
- redraw = 1;
- }
- }
- }
-
- if (++flashwait == 9) {
- flashwait = 0;
- w[0] = palflash ? (palold[0] + 0x18) : palold[0];
- w[1] = palflash ? (palold[1] + 0x18) : palold[1];
- w[2] = palflash ? (palold[2] + 0x18) : palold[2];
- vga_write_PAL(palidx,w,1);
- palflash = !palflash;
- }
- }
-
- vga_write_PAL(palidx,palold,1);
-}
-
-/* utility function to flash Attribute Controller Palette indexes */
-void flash_acp() {
- unsigned char palidx,palold,palflash=1,w,redraw=1,flashwait=0,vga_mode;
- int c;
-
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- vga_mode = int10_getmode();
-
- printf("Flashing Attribute Controller entry.\n");
- printf("ESC to quit, use Left/Right arrow keys\n");
- printf("to select palette entry, Up/Down to\n");
- printf("change values.\n");
- printf("\n");
-
- palidx = 40;
- for (c=0;c < palidx;c++) {
- unsigned short b,cc;
-
- vga_moveto(c,5);
- vga_sync_bios_cursor();
- cc = 0x0930 + (c&0xF);
- b = c;
-
- __asm {
- push ax
- push bx
- push cx
- mov ax,cc
- mov bx,b
- mov cx,1
- int 10h
- pop cx
- pop bx
- pop ax
- }
- }
- printf("\n");
- printf("\n");
-
- /* 320x200x256 mode: draw all 256 colors for ref */
- if (vga_mode == 19 && vga_graphics_ram != NULL) {
- VGA_RAM_PTR draw;
- unsigned int x,y;
-
- for (y=0;y < 8;y++) {
- draw = vga_graphics_ram + (320 * (200 - 1 - y));
- for (x=0;x < 256;x++) *draw++ = x;
- }
- }
-
- palidx = 7; /* start with color 7 (the text we print) */
- palold = vga_read_AC(palidx);
-
- while (1) {
- t8254_wait(0x10000UL); /* 9 / 18.2Hz = 0.5 second (about). no faster. don't give users seizures. */
-
- if (redraw) {
- printf("\x0D" "idx=0x%02x val=0x%02x RGB(%u,%u,%u)",
- palidx,palold,
- ((palold&4)>>1) | ((palold&32)>>5),
- (palold&2) | ((palold&16)>>4),
- ((palold&1)<<1) | ((palold& 8)>>3));
- fflush(stdout);
- redraw = 0;
- }
-
- if (kbhit()) {
- c = getch();
- if (c == 27)
- break;
- else if (c == 0) {
- c = getch();
- if (c == 0x4B) { /* left */
- vga_write_AC(palidx,palold);
- vga_write_AC(palidx | VGA_AC_ENABLE,palold);
- palidx = (palidx-1)&0xF;
- palold = vga_read_AC(palidx);
- flashwait = 9 - 1;
- palflash = 1;
- redraw = 1;
- }
- else if (c == 0x4D) { /* right */
- vga_write_AC(palidx,palold);
- vga_write_AC(palidx | VGA_AC_ENABLE,palold);
- palidx = (palidx+1)&0xF;
- palold = vga_read_AC(palidx);
- flashwait = 9 - 1;
- palflash = 1;
- redraw = 1;
- }
- else if (c == 0x48) { /* up */
- palold++;
- vga_write_AC(palidx,palold);
- vga_write_AC(palidx | VGA_AC_ENABLE,palold);
- palold = vga_read_AC(palidx);
- flashwait = 255 - 20;
- palflash = 0;
- redraw = 1;
- }
- else if (c == 0x50) { /* down */
- palold--;
- vga_write_AC(palidx,palold);
- vga_write_AC(palidx | VGA_AC_ENABLE,palold);
- palold = vga_read_AC(palidx);
- flashwait = 255 - 20;
- palflash = 0;
- redraw = 1;
- }
- }
- }
-
- if (++flashwait == 9) {
- flashwait = 0;
- w = palflash ? (palold ^ 0x3F) : palold;
- vga_write_AC(palidx,w);
- vga_write_AC(palidx | VGA_AC_ENABLE,w);
- palflash = !palflash;
- }
- }
-
- vga_write_AC(palidx,palold);
- vga_write_AC(palidx | VGA_AC_ENABLE,palold);
-}
-
-int main() {
- unsigned char redraw,vga_mode;
- struct vga_mode_params mp;
- int c;
-
- probe_dos();
- detect_windows();
-
- if (!probe_8254()) {
- printf("8254 not found (I need this for time-sensitive portions of the driver)\n");
- return 1;
- }
-
- if (!probe_vga()) {
- printf("VGA probe failed\n");
- return 1;
- }
-
- if (!(vga_flags & VGA_IS_VGA)) {
- printf("Modesetting + readback of CRTC registers is only supported on VGA\n");
- return 1;
- }
-
- redraw = 1;
- while (1) {
- update_state_from_vga();
-
- if (redraw) {
- unsigned long rate;
- double hrate,vrate;
- unsigned char gfx_misc;
-
- redraw = 0;
- vga_mode = int10_getmode();
- vga_read_crtc_mode(&mp);
-
- rate = vga_clock_rates[mp.clock_select];
- if (mp.clock_div2) rate >>= 1;
- hrate = (double)rate / ((mp.clock9 ? 9 : 8) * mp.horizontal_total);
- vrate = hrate / mp.vertical_total;
-
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- /* also read GC misc */
- gfx_misc = vga_read_GC(6);
-
- printf("VGA=%u EGA=%u CGA=%u MDA=%u MCGA=%u HGC=%u(%u)\n",
- (vga_flags & VGA_IS_VGA) ? 1 : 0,
- (vga_flags & VGA_IS_EGA) ? 1 : 0,
- (vga_flags & VGA_IS_CGA) ? 1 : 0,
- (vga_flags & VGA_IS_MDA) ? 1 : 0,
- (vga_flags & VGA_IS_MCGA) ? 1 : 0,
- (vga_flags & VGA_IS_HGC) ? 1 : 0,vga_hgc_type);
- printf("Tandy/PCjr=%u Amstrad=%u IO=%03xh ALPHA=%u\n",
- (vga_flags & VGA_IS_TANDY) ? 1 : 0,
- (vga_flags & VGA_IS_AMSTRAD) ? 1 : 0,
- vga_base_3x0,
- vga_alpha_mode);
-
- printf("RAM 0x%05lx-0x%05lx 9W=%u INT10=%u(0x%02x)\n",
- (unsigned long)vga_ram_base,
- (unsigned long)vga_ram_base+vga_ram_size-1UL,
- vga_9wide,vga_mode,vga_mode);
-
- printf("Clock=%u div2=%u (%luHZ) pix/clk=%u\n",
- mp.clock_select,
- mp.clock_div2,
- vga_clock_rates[mp.clock_select] >> (mp.clock_div2 ? 1 : 0),
- mp.clock9 ? 9 : 8);
-
- printf("Word=%u DWord=%u Hsync%c Vsync%c mem4=%u\n",
- mp.word_mode,
- mp.dword_mode,
- mp.hsync_neg?'-':'+',
- mp.vsync_neg?'-':'+',
- mp.inc_mem_addr_only_every_4th);
-
- printf("SLR=%u S4=%u memdv2=%u scandv2=%u awrap=%u\n",
- mp.shift_load_rate,
- mp.shift4_enable,
- mp.memaddr_div2,
- mp.scanline_div2,
- mp.address_wrap_select);
-
- printf("map14=%u map13=%u ref/scanline=%u o/e=%u\n",
- mp.map14,
- mp.map13,
- mp.refresh_cycles_per_scanline,
- (gfx_misc&2)?1:0);
-
- printf("hrate=%.3fKHz vrate=%.3fHz\n",
- hrate / 1000,
- vrate);
-
- printf("V:tot=%u disp=%u retr=%u <=x< %u\n",
- mp.vertical_total,
- mp.vertical_display_end,
- mp.vertical_start_retrace,
- mp.vertical_end_retrace);
-
- printf(" blnk=%u <=x< %u alpha=%u\n",
- mp.vertical_blank_start,
- mp.vertical_blank_end,
- ((gfx_misc&1)^1)?1:0); /* the bit is called "alpha disable" */
-
- printf("H:tot=%u disp=%u retr=%u <=x< %u\n",
- mp.horizontal_total,
- mp.horizontal_display_end,
- mp.horizontal_start_retrace,
- mp.horizontal_end_retrace);
-
- printf(" blnk=%u <=x< %u sdtot=%u sdretr=%u\n",
- mp.horizontal_blank_start,
- mp.horizontal_blank_end,
- mp.horizontal_start_delay_after_total,
- mp.horizontal_start_delay_after_retrace);
-
- printf("scan2x=%u maxscanline=%u offset=%u\n",
- mp.scan_double,
- mp.max_scanline,
- mp.offset);
-
- printf("\n");
-
- printf("ESC Exit to DOS ? Explain this\n");
- printf("m Set mode c Change clock\n");
- printf("9 Toggle 8/9 w Word/Dword\n");
- printf("- H/Vsync polarity $ mem4 toggle\n");
- printf("4 toggle shift4 5 toggle SLR\n");
- printf("2 toggle more... M max scanline\n");
- printf("o offset register x Mode-X\n");
- printf("z palette tinkering d Dump regs\n");
- printf("h panning/hpel\n");
- }
-
- c = getch();
- if (c == 27) break;
- else if (c == 13) {
- redraw = 1;
- }
- else if (c == '=') {
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- else if (c == 'h') {
- unsigned int nm;
-
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("\n");
- printf(" o Play with offset register (CRTC)\n");
- printf(" p Play with hpel register (AC)\n");
-
- c = getch();
- if (c == 'o') {
- printf("\n");
- printf("New offset (can be decimal or hexadecimal)? "); fflush(stdout);
- nm = common_prompt_number();
- vga_set_start_location(nm);
- }
- else if (c == 'p') {
- printf("\n");
- printf("New hpel? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm <= 255) vga_write_AC(0x13 | VGA_AC_ENABLE,nm);
- }
-
- redraw = 1;
- }
- else if (c == 'd') {
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("\n");
- printf(" f Dump VGA state to file\n");
-
- c = getch();
- if (c == 'f')
- dump_to_file();
-
- redraw = 1;
- }
- else if (c == 'z') {
- unsigned int nm;
-
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("\n");
- printf(" a Flash attrib control palette\n");
- printf(" p Flash VGA color palette\n");
- printf(" o Change overscan color\n");
-
- c = getch();
- if (c == 'a')
- flash_acp();
- else if (c == 'p')
- flash_vga_pal();
- else if (c == 'o') {
- printf("\n");
- printf("New color code (hex or dec)? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm <= 255) vga_write_AC(0x11 | VGA_AC_ENABLE,nm);
- }
-
- redraw = 1;
- }
- else if (c == 'x') {
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("\n");
- printf(" c CRTC configuration\n");
- printf(" s Sequencer configuration\n");
- printf(" C CRTC anti-configuration\n");
- printf(" S Sequencer anti-configuration\n");
-
- c = getch();
- if (c == 'c') {
- /* CRTC-side configuration of Mode-X */
- mp.word_mode = 0;
- mp.dword_mode = 0;
- mp.address_wrap_select = 1;
- mp.inc_mem_addr_only_every_4th = 0;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == 'C') {
- mp.word_mode = 1;
- mp.dword_mode = 1;
- mp.address_wrap_select = 1;
- mp.inc_mem_addr_only_every_4th = 0;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == 's') {
- /* CRTC-side configuration of Mode-X */
- vga_write_sequencer(0,0x01);
- vga_write_sequencer(4,0x06);
- vga_write_sequencer(0,0x03);
- vga_write_sequencer(VGA_SC_MAP_MASK,0xF);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == 'S') {
- vga_write_sequencer(0,0x01);
- vga_write_sequencer(4,0x0E);
- vga_write_sequencer(0,0x03);
- vga_write_sequencer(VGA_SC_MAP_MASK,0xF);
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
-
- redraw = 1;
- }
- else if (c == 'o') {
- unsigned int nm;
-
- printf("\n");
- printf("New value? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm <= 255) {
- mp.offset = nm;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- redraw = 1;
- }
- else if (c == 'M') {
- unsigned int nm;
-
- printf("\n");
- printf("New value? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm > 0 && nm <= 32) {
- mp.max_scanline = nm;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- redraw = 1;
- }
- else if (c == '2') {
- bios_cls();
- /* position the cursor to home */
- vga_moveto(0,0);
- vga_sync_bios_cursor();
-
- printf("\n");
- printf(" m toggle memaddr div2\n");
- printf(" s toggle scanline div2\n");
- printf(" a toggle address wrap select\n");
- printf(" r toggle refresh cycles/scan\n");
- printf(" 3 toggle map13\n");
- printf(" 4 toggle map14\n");
- printf(" d toggle scan double\n");
- printf(" o toggle odd/even\n");
- printf(" p toggle alpha disable\n");
-
- c = getch();
- if (c == 'd') {
- mp.scan_double = !mp.scan_double;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == 'o') {
- vga_write_GC(6,vga_read_GC(6)^2);
- }
- else if (c == 'p') {
- vga_write_GC(6,vga_read_GC(6)^1);
- }
- else if (c == 'm') {
- mp.memaddr_div2 = !mp.memaddr_div2;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == 's') {
- mp.scanline_div2 = !mp.scanline_div2;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == 'a') {
- mp.address_wrap_select = !mp.address_wrap_select;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == 'r') {
- mp.refresh_cycles_per_scanline = !mp.refresh_cycles_per_scanline;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == '3') {
- mp.map13 = !mp.map13;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
- else if (c == '4') {
- mp.map14 = !mp.map14;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- }
-
- redraw = 1;
- }
- else if (c == '4') {
- mp.shift4_enable = !mp.shift4_enable;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- else if (c == '5') {
- mp.shift_load_rate = !mp.shift_load_rate;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- else if (c == '?') {
- redraw = 1;
- help_main();
- }
- else if (c == '$') {
- mp.inc_mem_addr_only_every_4th = !mp.inc_mem_addr_only_every_4th;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- else if (c == '-') {
- unsigned int nm;
-
- printf("\n");
- printf(" 0: h + v +\n");
- printf(" 1: h - v +\n");
- printf(" 2: h + v -\n");
- printf(" 3: h - v -\n");
- printf("Mode? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm != ~0 && nm < 4) {
- mp.hsync_neg = (nm&1);
- mp.vsync_neg = (nm&2)?1:0;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == '9') {
- mp.clock9 = !mp.clock9;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- else if (c == 'm') {
- unsigned int nm;
-
- printf("\n");
- printf("Mode? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm != (~0U)) {
- if (nm < 0x100) {
- int10_setmode(nm);
- }
- else {
- uint16_t a;
-
- a = nm;
- /* VESA BIOS extensions or no, try to set a mode */
- __asm {
- push ax
- push bx
- mov ax,0x4F02
- mov bx,a
- int 0x10
- pop bx
- pop ax
- }
- }
- }
- redraw = 1;
- }
- else if (c == 'c') {
- unsigned int nm;
-
- printf("\n");
- for (nm=0;nm < 4;nm++) printf(" [%u] = %-8luHz [%u] = %luHz\n",
- nm,vga_clock_rates[nm],
- nm+4,vga_clock_rates[nm]>>1);
- printf("Clock? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm != ~0 && nm < 8) {
- mp.clock_select = nm&3;
- mp.clock_div2 = (nm&4)?1:0;
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- else if (c == 'w') {
- unsigned int nm;
-
- printf("\n");
- printf(" 0: byte (w=0 d=0)\n");
- printf(" 1: word (w=1 d=0)\n");
- printf(" 2: dword (w=1 d=1)\n");
- printf(" 3: dword !word (w=0 d=1)\n");
- printf("Mode? "); fflush(stdout);
- nm = common_prompt_number();
- if (nm != ~0 && nm < 4) {
- mp.dword_mode = (nm&2)?1:0;
- mp.word_mode = (nm&1)^mp.dword_mode; /* 0 1 2 3 > 00 01 11 10 */
- vga_write_crtc_mode(&mp,VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC);
- redraw = 1;
- }
- }
- }
-
- return 0;
-}
-
+++ /dev/null
--fr=nul -fo=dos386f/.obj -i=.. -i../.. -e=2 -zq -mf -d0 -bt=dos -oilrtfm -wx -fp3 -3r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=386 -DMMODE=f -q vgagui.c
+++ /dev/null
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <i86.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/dos/doswin.h>
-
-#ifdef TARGET_WINDOWS
-# include <hw/dos/winfcon.h>
-# include <windows/apihelp.h>
-# include <windows/dispdib/dispdib.h>
-# include <windows/win16eb/win16eb.h>
-#endif
-
-VGA_RAM_PTR vga_graphics_ram = NULL;
-VGA_RAM_PTR vga_graphics_ram_fence = NULL;
-VGA_ALPHA_PTR vga_alpha_ram = NULL;
-VGA_ALPHA_PTR vga_alpha_ram_fence = NULL;
-
-unsigned char vga_pos_x = 0,vga_pos_y = 0,vga_color = 0x7;
-unsigned char vga_width = 80,vga_height = 25;
-unsigned char vga_alpha_mode = 0;
-unsigned char vga_hgc_type = 0;
-unsigned int vga_base_3x0 = 0;
-unsigned long vga_ram_base = 0;
-unsigned long vga_ram_size = 0;
-unsigned char vga_stride = 80;
-unsigned short vga_flags = 0;
-unsigned char vga_9wide = 0;
-
-/* HGC values for HGC graphics */
-static unsigned char hgc_graphics_crtc[12] = {
- 0x35,0x2D,0x2E,0x07,
- 0x5B,0x02,0x57,0x57,
- 0x02,0x03,0x00,0x00
-};
-
-static unsigned char hgc_text_crtc[12] = {
- 0x61,0x50,0x52,0x0F,
- 0x19,0x06,0x19,0x19,
- 0x02,0x0D,0x0D,0x0C
-};
-
-uint32_t vga_clock_rates[4] = {
- 25175000UL,
- (25175000UL*9UL)/8UL, /* ~28MHz */
-/* if you know your SVGA chipset's correct values you may overwrite entries 2 and 3 */
- 0,
- 0
-};
-
-int check_vga_3C0() {
- unsigned char mor;
-
- /* Misc. output register test. This register is supposed to be readable at 0x3CC, writeable at 0x3C2,
- * and contain 7 documented bits that we can freely change */
- _cli();
- mor = inp(0x3CC);
- outp(0x3C2,0); /* turn it all off */
- if ((inp(0x3CC)&0xEF) != 0) { /* NTS: do not assume bit 4 is changeable */
- /* well if I couldn't change it properly it isn't the Misc. output register now is it? */
- outp(0x3C2,mor); /* restore it */
- return 0;
- }
- outp(0x3C2,0xEF); /* turn it all on (NTS: bit 4 is undocumented) */
- if ((inp(0x3CC)&0xEF) != 0xEF) { /* NTS: do not assume bit 4 is changeable */
- /* well if I couldn't change it properly it isn't the Misc. output register now is it? */
- outp(0x3C2,mor); /* restore it */
- return 0;
- }
- outp(0x3C2,mor);
- _sti();
-
- return 1;
-}
-
-void vga_sync_hw_cursor() {
- unsigned int i;
- i = vga_read_CRTC(0xF); /* cursor low */
- i |= vga_read_CRTC(0xE) << 8; /* cursor high */
- vga_pos_x = i % vga_stride;
- vga_pos_y = i / vga_stride;
-}
-
-void vga_sync_bios_cursor() {
-#ifndef TARGET_WINDOWS
-# if TARGET_MSDOS == 32
- *((unsigned char*)0x450) = vga_pos_x;
- *((unsigned char*)0x451) = vga_pos_y;
-# else
- *((unsigned char far*)MK_FP(0x40,0x50)) = vga_pos_x;
- *((unsigned char far*)MK_FP(0x40,0x51)) = vga_pos_y;
-# endif
-#endif
-}
-
-void update_state_vga_memory_map_select(unsigned char c) {
- switch (c) {
- case 0: vga_ram_base = 0xA0000; vga_ram_size = 0x20000; break;
- case 1: vga_ram_base = 0xA0000; vga_ram_size = 0x10000; break;
- case 2: vga_ram_base = 0xB0000; vga_ram_size = 0x08000; break;
- case 3: vga_ram_base = 0xB8000; vga_ram_size = 0x08000; break;
- }
-
-#if defined(TARGET_WINDOWS)
- if (vga_ram_base == 0xA0000)
- vga_graphics_ram = (unsigned char FAR*)DisplayDibGetScreenPointerA000();
- else if (vga_ram_base == 0xB0000)
- vga_graphics_ram = (unsigned char FAR*)DisplayDibGetScreenPointerB000();
- else if (vga_ram_base == 0xB8000)
- vga_graphics_ram = (unsigned char FAR*)DisplayDibGetScreenPointerB800();
- else
- vga_graphics_ram = (unsigned char FAR*)DisplayDibGetScreenPointerA000();
-
- vga_graphics_ram_fence = vga_graphics_ram + vga_ram_size;
- vga_alpha_ram = (uint16_t FAR*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t FAR*)vga_graphics_ram_fence;
-#else
-# if TARGET_MSDOS == 32
- /* NTS: According to many sources, 32-bit DOS extenders tend to map the lower 1MB 1:1, so this is safe */
- /* NTS: If I remember correctly Windows 95 also did this for Win32 applications, for whatever reason! */
- vga_graphics_ram = (unsigned char*)vga_ram_base;
- vga_graphics_ram_fence = vga_graphics_ram + vga_ram_size;
- vga_alpha_ram = (uint16_t*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t*)vga_graphics_ram_fence;
-# else
- vga_graphics_ram = MK_FP(vga_ram_base>>4,vga_ram_base&0xF); /* A0000 -> A000:0000 */
- vga_graphics_ram_fence = MK_FP((vga_ram_base+vga_ram_size)>>4,(vga_ram_base+vga_ram_size)&0xF);
- vga_alpha_ram = (uint16_t far*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t far*)vga_graphics_ram_fence;
-# endif
-#endif
-}
-
-/* EGA/VGA only */
-void vga_set_memory_map(unsigned char c) {
- unsigned char b;
-
- if (vga_flags & VGA_IS_VGA) {
- b = vga_read_GC(6);
- vga_write_GC(6,(b & 0xF3) | (c << 2));
- update_state_vga_memory_map_select(c);
- }
- else if (vga_flags & VGA_IS_EGA) {
- /* guessing code because you can't readback regs on EGA */
- b = int10_getmode();
- /* INT 10H text modes: set odd/even, else, set alpha disable */
- vga_write_GC(6,0x02 | (c << 2));
- update_state_vga_memory_map_select(c);
- }
-}
-
-void update_state_from_vga() {
- unsigned char c;
-
- vga_pos_x = vga_pos_y = 0;
- vga_stride = 80;
- vga_height = 25;
- vga_width = 80;
- vga_9wide = 0;
-
- if (vga_flags & VGA_IS_VGA) { /* VGA only. EGA cards DO have the misc. output reg but it's write-only */
- /* update state from H/W which I/O port */
- c = inp(0x3CC);
- if (c & 1) {
- vga_base_3x0 = 0x3D0;
- }
- else {
- vga_base_3x0 = 0x3B0;
- }
-
- /* now ask the graphics controller where/how VGA memory is mapped */
- c = vga_read_GC(6);
- /* bit 0 = alpha disable (if set, graphics) */
- vga_alpha_mode = ((c & 1) == 0);
- /* bits 2-3 memory map select */
- update_state_vga_memory_map_select((c>>2)&3);
-
- /* read the sequencer: are we in 8 or 9 dot mode? */
- c = vga_read_sequencer(0x1);
- vga_9wide = (c & 1) == 0;
-
- /* read from the CRTC controller the stride, width, and height */
- vga_stride = vga_read_CRTC(0x13) * 2; /* "offset" register */
- if (vga_alpha_mode) {
- vga_width = vga_stride;
- vga_sync_hw_cursor();
- /* TODO: read vertical blank values and calculate active area, then divide by scan line height, to get alpha height */
- /* TODO: read horizontal blank values to calculate active area, then visible width */
- }
- else {
- /* TODO: similar semantics for graphics mode */
- }
- }
- else if (vga_flags & VGA_IS_EGA) {
- /* Well the EGA has similar registers BUT they aren't readable. So we have to
- * guess based on other information handed to us */
-
- /* reading the misc. output register doesn't work, use BIOS data area */
-#if defined(TARGET_WINDOWS)
- c = 0xD0;/*TODO*/
-#else
-# if TARGET_MSDOS == 32
- c = *((unsigned char*)0x463);
-# else
- c = *((unsigned char far*)MK_FP(0x40,0x63));
-# endif
-#endif
- if ((c&0xF0) == 0xD0)
- vga_base_3x0 = 0x3D0;
- else if ((c&0xF0) == 0xB0)
- vga_base_3x0 = 0x3B0;
- else {
- vga_base_3x0 = 0x3D0;
- }
-
- /* reading from the graphics controller (0x3CE) doesn't work, deduce from BIOS mode */
- c = int10_getmode();
- switch (c) {
- case 0: case 1: case 2: case 3: case 7:
- vga_alpha_mode = 1;
-
- /* the best we can do is assume B0000 if CRTC is at 3Bx or B8000 if at 3Dx even though it's possible to map at B8000 and 3Bx */
- if (vga_base_3x0 == 0x3B0)
- update_state_vga_memory_map_select(2);
- else
- update_state_vga_memory_map_select(3);
- break;
- case 4: case 5: case 6:
- vga_alpha_mode = 0;
- update_state_vga_memory_map_select(3);
- break;
- case 13: case 14: case 15: case 16: case 17: case 18: default:
- vga_alpha_mode = 0;
- update_state_vga_memory_map_select(1);
- break;
- }
-
- /* read from the CRTC controller the stride, width, and height */
- vga_stride = vga_read_CRTC(0x13) * 2; /* "offset" register */
- if (vga_alpha_mode) {
- vga_width = vga_stride;
- vga_sync_hw_cursor();
- /* TODO: read vertical blank values and calculate active area, then divide by scan line height, to get alpha height */
- /* TODO: read horizontal blank values to calculate active area, then visible width */
- }
- else {
- /* TODO: similar semantics for graphics mode */
- }
-
-#if defined(TARGET_WINDOWS)
- /* TODO */
-#else
-# if TARGET_MSDOS == 32
- /* NTS: According to many sources, 32-bit DOS extenders tend to map the lower 1MB 1:1, so this is safe */
- /* NTS: If I remember correctly Windows 95 also did this for Win32 applications, for whatever reason! */
- vga_graphics_ram = (unsigned char*)vga_ram_base;
- vga_graphics_ram_fence = vga_graphics_ram + vga_ram_size;
- vga_alpha_ram = (uint16_t*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t*)vga_graphics_ram_fence;
-# else
- vga_graphics_ram = MK_FP(vga_ram_base>>4,vga_ram_base&0xF); /* A0000 -> A000:0000 */
- vga_graphics_ram_fence = MK_FP((vga_ram_base+vga_ram_size)>>4,vga_ram_base+vga_ram_size);
- vga_alpha_ram = (uint16_t far*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t far*)vga_graphics_ram_fence;
-# endif
-#endif
- }
- else if (vga_flags & VGA_IS_CGA) {
- vga_base_3x0 = 0x3D0; /* always at 0x3Dx */
-
- /* TODO: If Tandy, detect state */
-
- /* read the status register to determine the state of the CGA... oh wait... we can't.
- * fine. deduce it from the BIOS video mode. */
- c = int10_getmode();
- switch (c) {
- case 0: case 1: case 2: case 3: case 7:
- vga_alpha_mode = 1;
- break;
- default:
- vga_alpha_mode = 0;
- break;
- }
-
- if (c <= 1) {
- vga_stride = 40;
- vga_width = 40;
- }
-
- vga_ram_base = 0xB8000;
- vga_ram_size = 0x08000;
-
-#if defined(TARGET_WINDOWS)
- /* TODO */
-#else
-# if TARGET_MSDOS == 32
- /* NTS: According to many sources, 32-bit DOS extenders tend to map the lower 1MB 1:1, so this is safe */
- /* NTS: If I remember correctly Windows 95 also did this for Win32 applications, for whatever reason! */
- vga_graphics_ram = (unsigned char*)vga_ram_base;
- vga_graphics_ram_fence = vga_graphics_ram + vga_ram_size;
- vga_alpha_ram = (uint16_t*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t*)vga_graphics_ram_fence;
-# else
- vga_graphics_ram = MK_FP(vga_ram_base>>4,vga_ram_base&0xF); /* A0000 -> A000:0000 */
- vga_graphics_ram_fence = MK_FP((vga_ram_base+vga_ram_size)>>4,vga_ram_base+vga_ram_size);
- vga_alpha_ram = (uint16_t far*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t far*)vga_graphics_ram_fence;
-# endif
-#endif
- }
- else if (vga_flags & VGA_IS_MDA) {
- vga_base_3x0 = 0x3B0; /* always at 0x3Bx */
- vga_alpha_mode = 1; /* stock MDA doesn't have graphics */
- vga_ram_base = 0xB0000;
- vga_ram_size = 0x08000;
-
- /* Hercules MDA: It would be nice to be able to read bit 2 of the display control,
- * except that the port is write-only. Thanks >:( */
-
-#if defined(TARGET_WINDOWS)
- /* TODO */
-#else
-# if TARGET_MSDOS == 32
- /* NTS: According to many sources, 32-bit DOS extenders tend to map the lower 1MB 1:1, so this is safe */
- /* NTS: If I remember correctly Windows 95 also did this for Win32 applications, for whatever reason! */
- vga_graphics_ram = (unsigned char*)vga_ram_base;
- vga_graphics_ram_fence = vga_graphics_ram + vga_ram_size;
- vga_alpha_ram = (uint16_t*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t*)vga_graphics_ram_fence;
-# else
- vga_graphics_ram = MK_FP(vga_ram_base>>4,vga_ram_base&0xF); /* A0000 -> A000:0000 */
- vga_graphics_ram_fence = MK_FP((vga_ram_base+vga_ram_size)>>4,vga_ram_base+vga_ram_size);
- vga_alpha_ram = (uint16_t far*)vga_graphics_ram;
- vga_alpha_ram_fence = (uint16_t far*)vga_graphics_ram_fence;
-# endif
-#endif
- }
-}
-
-int probe_vga() {
-#if defined(TARGET_WINDOWS)
- /* TODO: More comprehensive tests! */
- vga_flags |= VGA_IS_VGA | VGA_IS_EGA | VGA_IS_CGA;
- update_state_from_vga();
- return 1;
-#else
- union REGS regs = {0};
- unsigned char c,c2;
-
- vga_flags = 0;
- vga_base_3x0 = 0;
-
- /* apparently the best way is to ask the VGA BIOS */
- /* according to sources I have this function only works on VGA BIOSes and nothing prior to that */
- {
- regs.w.ax = 0x1A00;
-#if TARGET_MSDOS == 32
- int386(0x10,®s,®s);
-#else
- int86(0x10,®s,®s);
-#endif
- if (regs.h.al == 0x1A) {
- if (regs.h.bl == 1) {
- vga_flags |= VGA_IS_MDA;
- }
- else if (regs.h.bl == 2) {
- vga_flags |= VGA_IS_CGA;
- }
- else if (regs.h.bl == 4 || regs.h.bl == 5) {
- /* it's an EGA */
- vga_flags |= VGA_IS_EGA | VGA_IS_CGA;
- }
- else if (regs.h.bl == 7 || regs.h.bl == 8) {
- /* VGA, officially */
- vga_flags |= VGA_IS_VGA | VGA_IS_EGA | VGA_IS_CGA;
- }
- else if (regs.h.bl == 10 || regs.h.bl == 11 || regs.h.bl == 12) {
- vga_flags |= VGA_IS_MCGA | VGA_IS_CGA;
- }
- }
- }
-
- /* if that didn't work, then assume it's not VGA, and probe around a bit */
- /* are you an EGA? Determine by BIOS */
- if (vga_flags == 0) {
- regs.w.ax = 0x1200;
- regs.w.bx = 0xFF10;
-#if TARGET_MSDOS == 32
- int386(0x10,®s,®s);
-#else
- int86(0x10,®s,®s);
-#endif
- if (regs.h.bh != 0xFF) { /* so, if BH changes the EGA BIOS or higher is present? */
- vga_flags |= VGA_IS_CGA | VGA_IS_EGA;
- /* and BH == 0 if color */
- }
- }
-
- /* hm, okay. how about testing for a CGA? */
- /* NTS: The CGA is always at port 0x3Dx */
- if (vga_flags == 0) {
- unsigned int patience = 1000;
- outp(0x3D4,0xF);
- c = inp(0x3D5);
- outp(0x3D5,0xAA);
- while (--patience != 0 && (c2=inp(0x3D5)) != 0xAA);
- outp(0x3D5,c);
- if (c2 == 0xAA) {
- vga_flags |= VGA_IS_CGA;
-
- /* If it looks like a CGA it might be a Tandy/PCjr */
- /* unfortunately I can't find ANYTHING on
- * how to go about detecting Tandy graphics. The best I can
- * find are obscure INT 1Ah calls that detect the Tandy's
- * sound chip (and conflict the PCMCIA services---YIKES!) */
- {
- union REGS regs = {0};
- regs.w.ax = 0x8100;
-#if TARGET_MSDOS == 32
- int386(0x1A,®s,®s);
-#else
- int86(0x1A,®s,®s);
-#endif
- if (regs.h.al & 0x80) {
- if ((regs.w.cflag & 1) == 0) { /* and sound chip is free? CF=0 */
- vga_flags |= VGA_IS_TANDY;
- }
- }
- }
-
- /* what about Amstrad? */
- {
- union REGS regs = {0};
- regs.w.ax = 0x0600;
- regs.w.bx = 0;
- regs.w.cflag = 0;
-#if TARGET_MSDOS == 32
- int386(0x15,®s,®s);
-#else
- int86(0x15,®s,®s);
-#endif
- if (regs.w.bx != 0 && !(regs.w.cflag & 1)) {
- vga_flags |= VGA_IS_AMSTRAD;
- /* TODO: If I read the Amstrad tech manual correctly, their video hardware also emulates Hercules modes, right? */
- /* TODO: I get the impression Amstrad graphics do not include Tandy modes, is that correct? */
- //vga_flags &= ~VGA_IS_TANDY; /* <- if so, uncomment this line */
- }
- }
- }
- }
-
- /* hm, okay. how about testing for a MDA? */
- /* NTS: The MDA is always at port 0x3Bx */
- if (vga_flags == 0) {
- unsigned int patience = 1000;
- outp(0x3B4,0xF);
- c = inp(0x3B5);
- outp(0x3B5,0xAA);
- while (--patience != 0 && (c2=inp(0x3B5)) != 0xAA);
- outp(0x3B5,c);
- if (c2 == 0xAA) {
- vga_flags |= VGA_IS_MDA;
- }
- }
-
- /* If it looks like an MDA, then it might be helpful to tell whether it's a
- * Hercules graphics card */
- if (vga_flags & VGA_IS_MDA) {
- unsigned char cm,c;
- unsigned int hsyncs = 0; /* in case we're on a slow machine use hsync count to know when to stop */
- unsigned int patience = 0xFFFF; /* NTS: 0xFFFF on actual hardware of that era might turn into a considerable and unnecessary pause */
- cm = inp(0x3BA);
- while (--patience != 0 && ((c=inp(0x3BA)) & 0x80) == (cm & 0x80)) {
- if ((c^cm) & 1) { /* HSYNC change? */
- cm ^= 1;
- if (c & 1) { /* did HSYNC start? */
- if (++hsyncs >= 600) break; /* if we've gone 600 hsyncs without seeing VSYNC change then give up */
- }
- }
- inp(0x80);
- }
- if (patience > 0 && (c^cm) & 0x80) { /* if it changed, then HGC */
- vga_flags |= VGA_IS_HGC;
- vga_hgc_type = (c >> 4) & 7;
- switch ((c>>4)&7) {
- case 5: case 1: vga_hgc_type = (c>>4)&7; break;
- default: vga_hgc_type = 0; break;
- }
- }
- }
-
- update_state_from_vga();
- return 1;
-#endif
-}
-
-/* WARNING: [At least in DOSBox 0.74] do not call this for any CGA or EGA graphics modes.
- * It seems to trigger a false mode change and alphanumeric mode */
-void vga_relocate_crtc(unsigned char color) {
- unsigned char moc = 0;
-
- /* this code assumes color == 0 or color == 1 */
- color = (color != 0)?1:0;
-
- /* VGA: Easy, read the register, write it back */
- if (vga_flags & VGA_IS_VGA) {
- moc = inp(0x3CC);
- moc &= 0xFE; /* clear bit 0, respond to 0x3Bx */
- outp(0x3C2,moc | color);
- }
- else if (vga_flags & VGA_IS_EGA) {
- /* EGA: We can't read it, but we can write it from our best guess */
- outp(0x3C2,0x02 | (color?1:0));
- }
-
- vga_base_3x0 = color ? 0x3D0 : 0x3B0;
-}
-
-void vga_switch_to_mono() {
- unsigned char moc = 0;
-
- /* VGA: Easy, read the register, write it back */
- if (vga_flags & VGA_IS_VGA) {
- moc = inp(0x3CC);
- moc &= 0xFE; /* clear bit 0, respond to 0x3Bx */
- outp(0x3C2,moc);
-
- /* and then hack the graphics controller to remap the VRAM */
- moc = vga_read_GC(6);
- moc &= 0xF3; /* clear bits 2-3 */
- moc |= 0x08; /* bits 2-3 = 10 = B0000 */
- vga_write_GC(6,moc);
- }
- else if (vga_flags & VGA_IS_EGA) {
- /* EGA: We can't read it, but we can write it from our best guess */
- moc = 0x02; /* VSYNC/HSYNC pos, low page odd/even, 25MHz clock, RAM enable */
- outp(0x3C2,moc);
- vga_write_GC(6,0x08|0x02); /* B0000 with odd/even */
- }
- else {
- /* whuh? */
- return;
- }
-
- /* next, tell the BIOS of the change */
-#ifndef TARGET_WINDOWS
-# if TARGET_MSDOS == 32
- *((unsigned char*)0x449) = 0x07; /* mode 7 */
- *((unsigned char*)0x463) = 0xB4;
- *((unsigned char*)0x410) |= 0x30; /* -> change to 80x25 mono */
- *((unsigned char*)0x465) &= ~0x04; /* monochrome operation */
-# else
- *((unsigned char far*)MK_FP(0x40,0x49)) = 0x07; /* mode 7 */
- *((unsigned char far*)MK_FP(0x40,0x63)) = 0xB4;
- *((unsigned char far*)MK_FP(0x40,0x10)) |= 0x30; /* -> change to 80x25 mono */
- *((unsigned char far*)MK_FP(0x40,0x65)) &= ~0x04; /* monochrome operation */
-# endif
-#endif
-}
-
-void vga_switch_to_color() {
- unsigned char moc = 0;
-
- /* VGA: Easy, read the register, write it back */
- if (vga_flags & VGA_IS_VGA) {
- moc = inp(0x3CC);
- moc |= 0x01; /* set bit 0, respond to 0x3Dx */
- outp(0x3C2,moc);
-
- /* and then hack the graphics controller to remap the VRAM */
- moc = vga_read_GC(6);
- moc &= 0xF3; /* clear bits 2-3 */
- moc |= 0x0C; /* bits 2-3 = 11 = B8000 */
- vga_write_GC(6,moc);
- }
- else if (vga_flags & VGA_IS_EGA) {
- /* EGA: We can't read it, but we can write it from our best guess */
- moc = 0x02|1; /* VSYNC/HSYNC pos, low page odd/even, 25MHz clock, RAM enable */
- outp(0x3C2,moc);
- vga_write_GC(6,0x0C|0x02); /* B8000 with odd/even */
- }
- else {
- /* whuh? */
- return;
- }
-
- /* next, tell the BIOS of the change */
-#ifndef TARGET_WINDOWS
-# if TARGET_MSDOS == 32
- *((unsigned char*)0x449) = 0x03; /* mode 3 */
- *((unsigned char*)0x463) = 0xD4;
- *((unsigned char*)0x410) &= 0x30; /* INT 11 initial video mode */
- *((unsigned char*)0x410) |= 0x20; /* -> change to 80x25 color */
- *((unsigned char*)0x465) |= 0x04; /* color operation */
-# else
- *((unsigned char far*)MK_FP(0x40,0x49)) = 0x03; /* mode 3 */
- *((unsigned char far*)MK_FP(0x40,0x63)) = 0xD4;
- *((unsigned char far*)MK_FP(0x40,0x10)) &= 0x30; /* INT 11 initial video mode */
- *((unsigned char far*)MK_FP(0x40,0x10)) |= 0x20; /* -> change to 80x25 color */
- *((unsigned char far*)MK_FP(0x40,0x65)) |= 0x04; /* color operation */
-# endif
-#endif
-}
-
-void vga_moveto(unsigned char x,unsigned char y) {
- vga_pos_x = x;
- vga_pos_y = y;
-}
-
-void vga_turn_on_hgc() {
- unsigned char c;
-
- outp(0x3B8,0x00); /* turn off video */
- outp(0x3BF,0x01); /* enable setting graphics mode */
- outp(0x3B8,0x02); /* turn on graphics */
- for (c=0;c < 12;c++) {
- outp(0x3B4,c);
- outp(0x3B5,hgc_graphics_crtc[c]);
- }
- outp(0x3B8,0x0A); /* turn on graphics+video */
-}
-
-void vga_turn_off_hgc() {
- unsigned char c;
-
- outp(0x3B8,0x00); /* turn off video */
- outp(0x3BF,0x00); /* disable setting graphics mode */
- for (c=0;c < 12;c++) {
- outp(0x3B4,c);
- outp(0x3B5,hgc_text_crtc[c]);
- }
- outp(0x3B8,0x28); /* turn on video and text */
-}
-
-void vga_set_cga_palette_and_background(unsigned char pal,unsigned char color) {
- outp(0x3D9,(pal << 5) | color);
-}
-
-void vga_set_cga_mode(unsigned char b) {
- outp(0x3D8,b);
-}
-
-void vga_tandy_setpalette(unsigned char i,unsigned char c) {
- inp(0x3DA);
- outp(0x3DA,0x10 + i);
- outp(0x3DE,c); /* NTS: This works properly on Tandy [at least DOSBox] */
- outp(0x3DA,c); /* NTS: Writing 0x00 like some sames do works on Tandy but PCjr takes THIS byte as palette data */
-}
-
-void vga_enable_256color_modex() {
- vga_write_sequencer(4,0x06);
- vga_write_sequencer(0,0x01);
- vga_write_CRTC(0x17,0xE3);
- vga_write_CRTC(0x14,0x00);
- vga_write_sequencer(0,0x03);
- vga_write_sequencer(VGA_SC_MAP_MASK,0xF);
-}
-
-void vga_set_stride(unsigned int stride) {
- /* TODO: Knowing the current "byte/word/dword" memory size, compute properly */
- stride >>= (2+1); /* divide by DWORD * 2 */
- vga_write_CRTC(0x13,stride);
-}
-
-void vga_set_start_location(unsigned int offset) {
- vga_write_CRTC(0x0C,offset>>8);
- vga_write_CRTC(0x0D,offset);
-}
-
-void vga_set_ypan_sub(unsigned char c) {
- vga_write_CRTC(0x08,c);
-}
-
-void vga_set_xpan(unsigned char c) {
- vga_write_AC(0x13|0x20,c);
-}
-
-void vga_splitscreen(unsigned int v) {
- unsigned char c;
-
- /* FIXME: Either DOSBox 0.74 got EGA emulation wrong, or we really do have to divide the line count by 2. */
- /* Until then leave the value as-is */
- /* TODO: Didn't Mike Abrash or other programming gurus mention a bug or off-by-1 error with the EGA linecount? */
-
- vga_write_CRTC(0x18,v);
- if (vga_flags & VGA_IS_VGA) {
- c = vga_read_CRTC(0x07);
- vga_write_CRTC(0x07,(c & (~0x10)) | (((v>>8)&1) << 4));
- c = vga_read_CRTC(0x09);
- vga_write_CRTC(0x09,(c & (~0x40)) | (((v>>9)&1) << 6));
- }
- else {
- c = 0x1F; /* since most modes have > 256 lines this is as good a guess as any */
- vga_write_CRTC(0x07,(c & (~0x10)) | (((v>>8)&1) << 4));
- }
-}
-
-void vga_alpha_switch_to_font_plane() {
- vga_write_GC(0x4,0x02); /* NTS: Read Map Select: This is very important if the caller wants to read from the font plane without reading back gibberish */
- vga_write_GC(0x5,0x00);
- vga_write_GC(0x6,0x0C);
- vga_write_sequencer(0x2,0x04);
- vga_write_sequencer(0x4,0x06);
-}
-
-void vga_alpha_switch_from_font_plane() {
- vga_write_GC(0x4,0x00);
- vga_write_GC(0x5,0x10);
- vga_write_GC(0x6,0x0E);
- vga_write_sequencer(0x2,0x03);
- vga_write_sequencer(0x4,0x02);
-}
-
-/* NTS: this also completes the change by setting the clock select bits in Misc. out register
- * on the assumption that you are changing 8/9 bits in 80x25 alphanumeric mode. The
- * clock change is necessary to retain the proper hsync/vsync rates on the VGA monitor. */
-void vga_set_9wide(unsigned char en) {
- unsigned char c;
-
- if (en == vga_9wide)
- return;
-
- c = vga_read_sequencer(1);
- c &= 0xFE;
- c |= en ^ 1;
- vga_write_sequencer(1,c);
- vga_9wide = en;
-
- c = inp(0x3CC);
- c &= 0xF3;
- c |= (en ? 1 : 0) << 2; /* 0=25MHz 1=28MHz */
- outp(0x3C2,c);
-}
-
-void vga_select_charset_a_b(unsigned short a,unsigned short b) {
- unsigned char c;
-
- c = a >> 14;
- c |= (b >> 14) << 2;
- c |= ((a >> 13) & 1) << 4;
- c |= ((b >> 13) & 1) << 5;
-
- vga_write_sequencer(3,c);
-}
-
-/* VGA hardware registers impose several restraints on valid values,
- * mostly related to how retrace and blanking start/end values are encoded */
-void vga_correct_crtc_mode(struct vga_mode_params *p) {
- /* TODO */
-}
-
-/* WARNING: This code is deliberately designed to NOT fullfill your request if you have
- * anything but VGA. EGA and CGA monitors are fixed-frequency and this kind of
- * experimentation is not good for them. You can of course fry a VGA monitor
- * that way too, but at least we can read back the "safe" values the BIOS
- * programmed into the hardware */
-void vga_write_crtc_mode(struct vga_mode_params *p,unsigned int flags) {
- unsigned char c,c2;
-
- if (!(vga_flags & VGA_IS_VGA))
- return;
-
- /* sync disable unless told not to */
- if (!(flags & VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC)) {
- c = vga_read_CRTC(0x17);
- vga_write_CRTC(0x17,c&0x7F);
- }
-
- c = inp(0x3CC); /* misc out reg */
- c &= ~((3 << 2) | (1 << 6) | (1 << 7));
- c |= (p->clock_select&3) << 2;
- c |= p->hsync_neg << 6;
- c |= p->vsync_neg << 7;
- outp(0x3C2,c);
-
- vga_write_sequencer(1,
- (p->shift_load_rate << 2) |
- (p->shift4_enable << 4) |
- ((p->clock9 ^ 1) << 0) |
- (p->clock_div2 << 3));
-
- c = 0; /* use 'c' as overflow register */
- c2 = vga_read_CRTC(0x09); /* read max scan line */
- c2 &= ~(1 << 5); /* mask out start vertical blank bit 9 */
- vga_write_CRTC(0x11, /* NTS: we leave bit 7 (protect) == 0 so we can program regs 0-7 in this routine */
- (((p->refresh_cycles_per_scanline == 5) ? 1 : 0) << 6) |
- (p->vertical_end_retrace & 0xF));
- vga_write_CRTC(0x06,(p->vertical_total - 2));
- c |= (((p->vertical_total - 2) >> 8) & 1) << 0;
- c |= (((p->vertical_total - 2) >> 9) & 1) << 5;
- vga_write_CRTC(0x10,p->vertical_start_retrace);
- c |= ((p->vertical_start_retrace >> 8) & 1) << 2;
- c |= ((p->vertical_start_retrace >> 9) & 1) << 7;
- vga_write_CRTC(0x12,p->vertical_display_end - 1);
- c |= (((p->vertical_display_end - 1) >> 8) & 1) << 1;
- c |= (((p->vertical_display_end - 1) >> 9) & 1) << 6;
- vga_write_CRTC(0x15,p->vertical_blank_start - 1);
- c |= (((p->vertical_blank_start - 1) >> 8) & 1) << 3;
- c2|= (((p->vertical_blank_start - 1) >> 9) & 1) << 5;
-
- /* NTS: this field is 7 bits wide but "Some SVGA chipsets use all 8" as VGADOC says. */
- /* writing it in this way resolves the partial/full screen blanking problems with Intel 855/915/945 chipsets */
- vga_write_CRTC(0x16,p->vertical_blank_end - 1);
-
- vga_write_CRTC(0x14, /* NTS we write "underline location == 0" */
- (p->dword_mode << 6) |
- (p->inc_mem_addr_only_every_4th << 5));
- vga_write_CRTC(0x07,c); /* overflow reg */
-
- c2 &= ~(0x9F); /* mask out SD + Max scanline */
- c2 |= (p->scan_double << 7);
- c2 |= (p->max_scanline - 1) & 0x1F;
- vga_write_CRTC(0x09,c2);
- vga_write_CRTC(0x13,p->offset);
- vga_write_CRTC(0,(p->horizontal_total - 5));
- vga_write_CRTC(1,(p->horizontal_display_end - 1));
- vga_write_CRTC(2,p->horizontal_blank_start - 1);
- vga_write_CRTC(3,((p->horizontal_blank_end - 1) & 0x1F) | (p->horizontal_start_delay_after_total << 5) | 0x80);
- vga_write_CRTC(4,p->horizontal_start_retrace);
- vga_write_CRTC(5,((((p->horizontal_blank_end - 1) >> 5) & 1) << 7) | (p->horizontal_start_delay_after_retrace << 5) |
- (p->horizontal_end_retrace & 0x1F));
-
- /* finish by writing reg 0x17 which also enables sync */
- vga_write_CRTC(0x17,
- (p->sync_enable << 7) |
- (vga_read_CRTC(0x17) & 0x10) | /* NTS: one undocumented bit, perhaps best not to change it */
- ((p->word_mode^1) << 6) |
- (p->address_wrap_select << 5) |
- (p->memaddr_div2 << 3) |
- (p->scanline_div2 << 2) |
- ((p->map14 ^ 1) << 1) |
- ((p->map13 ^ 1) << 0));
-
- /* reinforce write protect */
- c = vga_read_CRTC(0x11);
- vga_write_CRTC(0x11,c|0x80);
-}
-
-void vga_read_crtc_mode(struct vga_mode_params *p) {
- unsigned char c,c2;
-
- if (!(vga_flags & VGA_IS_VGA))
- return;
-
- c = inp(0x3CC); /* misc out reg */
- p->clock_select = (c >> 2) & 3;
- p->hsync_neg = (c >> 6) & 1;
- p->vsync_neg = (c >> 7) & 1;
-
- c = vga_read_sequencer(1);
- p->clock9 = (c & 1) ^ 1;
- p->clock_div2 = (c >> 3) & 1;
- p->shift4_enable = (c >> 4) & 1;
- p->shift_load_rate = (c >> 2) & 1;
-
- p->sync_enable = (vga_read_CRTC(0x17) >> 7) & 1;
- p->word_mode = ((vga_read_CRTC(0x17) >> 6) & 1) ^ 1;
- p->address_wrap_select = (vga_read_CRTC(0x17) >> 5) & 1;
- p->memaddr_div2 = (vga_read_CRTC(0x17) >> 3) & 1;
- p->scanline_div2 = (vga_read_CRTC(0x17) >> 2) & 1;
- p->map14 = ((vga_read_CRTC(0x17) >> 1) & 1) ^ 1;
- p->map13 = ((vga_read_CRTC(0x17) >> 0) & 1) ^ 1;
-
- p->dword_mode = (vga_read_CRTC(0x14) >> 6) & 1;
- p->horizontal_total = vga_read_CRTC(0) + 5;
- p->horizontal_display_end = vga_read_CRTC(1) + 1;
- p->horizontal_blank_start = vga_read_CRTC(2) + 1;
- p->horizontal_blank_end = ((vga_read_CRTC(3) & 0x1F) | ((vga_read_CRTC(5) >> 7) << 5) |
- ((p->horizontal_blank_start - 1) & (~0x3F))) + 1;
- if (p->horizontal_blank_start >= p->horizontal_blank_end)
- p->horizontal_blank_end += 0x40;
- p->horizontal_start_retrace = vga_read_CRTC(4);
- p->horizontal_end_retrace = (vga_read_CRTC(5) & 0x1F) |
- (p->horizontal_start_retrace & (~0x1F));
- if ((p->horizontal_start_retrace&0x1F) >= (p->horizontal_end_retrace&0x1F))
- p->horizontal_end_retrace += 0x20;
- p->horizontal_start_delay_after_total = (vga_read_CRTC(3) >> 5) & 3;
- p->horizontal_start_delay_after_retrace = (vga_read_CRTC(5) >> 5) & 3;
-
- c = vga_read_CRTC(7); /* c = overflow reg */
- c2 = vga_read_CRTC(9);
-
- p->scan_double = (c2 >> 7) & 1;
- p->max_scanline = (c2 & 0x1F) + 1;
- p->offset = vga_read_CRTC(0x13);
- p->vertical_total = (vga_read_CRTC(6) | ((c & 1) << 8) | (((c >> 5) & 1) << 9)) + 2;
- p->vertical_start_retrace = (vga_read_CRTC(0x10) | (((c >> 2) & 1) << 8) | (((c >> 7) & 1) << 9));
- p->vertical_end_retrace = (vga_read_CRTC(0x11) & 0xF) |
- (p->vertical_start_retrace & (~0xF));
- if ((p->vertical_start_retrace&0xF) >= (p->vertical_end_retrace&0xF))
- p->vertical_end_retrace += 0x10;
- p->refresh_cycles_per_scanline = ((vga_read_CRTC(0x11) >> 6) & 1) ? 5 : 3;
- p->inc_mem_addr_only_every_4th = (vga_read_CRTC(0x14) >> 5) & 1;
- p->vertical_display_end = ((vga_read_CRTC(0x12) | (((c >> 1) & 1) << 8) | (((c >> 6) & 1) << 9))) + 1;
- p->vertical_blank_start = ((vga_read_CRTC(0x15) | (((c >> 3) & 1) << 8) | (((c2 >> 5) & 1) << 9))) + 1;
- p->vertical_blank_end = ((vga_read_CRTC(0x16) & 0x7F) | ((p->vertical_blank_start - 1) & (~0x7F))) + 1;
- if (p->vertical_blank_start >= p->vertical_blank_end)
- p->vertical_blank_end += 0x80;
-}
-
-void vga_bios_set_80x50_text() { /* switch to VGA 80x50 8-line high text */
-#if defined(TARGET_WINDOWS)
-#else
- union REGS regs = {0};
- regs.w.ax = 0x1112;
- regs.w.bx = 0;
-# if TARGET_MSDOS == 32
- int386(0x10,®s,®s);
-# else
- int86(0x10,®s,®s);
-# endif
- vga_height = 50;
-#endif
-}
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-unsigned char int10_getmode() {
- unsigned char *base,*p,ret;
- DWORD code;
-
- if ((base=p=LockWin16EBbuffer()) == NULL)
- return 3;
-
- /* force creation of the code alias */
- code = GetCodeAliasWin16EBbuffer();
- if (code == 0) {
- UnlockWin16EBbuffer();
- return 3;
- }
-
- /* MOV AX,0F00 */
- *p++ = 0xB8; *((WORD FAR*)p) = 0x0F00; p+=2;
- /* INT 10h */
- *p++ = 0xCD; *p++ = 0x10;
-
- /* RETF */
- *p++ = 0xCB;
-
- /* run it! */
- ret = (unsigned char)ExecuteWin16EBbuffer(code);
- UnlockWin16EBbuffer();
- return ret;
-}
-
-void int10_setmode(unsigned char mode) {
- unsigned char *base,*p;
- DWORD code;
-
- if ((base=p=LockWin16EBbuffer()) == NULL)
- return;
-
- /* force creation of the code alias */
- code = GetCodeAliasWin16EBbuffer();
- if (code == 0) {
- UnlockWin16EBbuffer();
- return;
- }
-
- /* MOV AX,<x> */
- *p++ = 0xB8; *((WORD FAR*)p) = mode; p+=2;
- /* INT 10h */
- *p++ = 0xCD; *p++ = 0x10;
- /* RETF */
- *p++ = 0xCB;
-
- /* run it! */
- ExecuteWin16EBbuffer(code);
- UnlockWin16EBbuffer();
-}
-#endif
-
+++ /dev/null
-
-#ifndef __DOSLIB_HW_VGA_VGA_H
-#define __DOSLIB_HW_VGA_VGA_H
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#if TARGET_MSDOS == 32
-typedef unsigned char *VGA_RAM_PTR;
-typedef uint16_t *VGA_ALPHA_PTR;
-#else
-typedef unsigned char far *VGA_RAM_PTR;
-typedef uint16_t far *VGA_ALPHA_PTR;
-#endif
-
-/* vga_flags */
-#define VGA_IS_TANDY 0x02 /* Tandy/PCjr */
-#define VGA_IS_HGC 0x04
-#define VGA_IS_MCGA 0x08
-#define VGA_IS_VGA 0x10
-#define VGA_IS_EGA 0x20
-#define VGA_IS_CGA 0x40
-#define VGA_IS_MDA 0x80
-#define VGA_IS_AMSTRAD 0x100
-
-/* sequencer index */
-#define VGA_AC_ENABLE 0x20
-
-/* graphics controller regs */
-#define VGA_GC_DATA_ROTATE_OP_NONE (0 << 3)
-#define VGA_GC_DATA_ROTATE_OP_AND (1 << 3)
-#define VGA_GC_DATA_ROTATE_OP_OR (2 << 3)
-#define VGA_GC_DATA_ROTATE_OP_XOR (3 << 3)
-
-/* font manipulation vars */
-#define VGA_EGA_BYTES_PER_CHAR_BITMAP 32
-#define VGA_EGA_BYTES_PER_CHAR_BITMAP_SHIFT 5
-
-/* EGA/VGA memory map bits */
-enum {
- VGA_MEMMAP_A0000_128K=0,
- VGA_MEMMAP_A0000_64K,
- VGA_MEMMAP_B0000_32K,
- VGA_MEMMAP_B8000_32K
-};
-
-enum {
- VGA_CGA_MODE_40WIDE=0,
- VGA_CGA_MODE_80WIDE=0x01,
- VGA_CGA_MODE_GRAPHICS=0x02,
- VGA_CGA_MODE_BW=0x04,
- VGA_CGA_MODE_VIDEO_ENABLE=0x08,
- VGA_CGA_MODE_VIDEO_640=0x10,
- VGA_CGA_MODE_NO_BLINKING=0x20
-};
-
-/* sequencer registers */
-enum {
- VGA_SC_MAP_MASK=2
-};
-
-/* graphics controller registers */
-enum {
- VGA_GC_ENABLE_SET_RESET=0,
- VGA_GC_SET_RESET=1,
- VGA_GC_DATA_ROTATE=3,
- VGA_GC_MODE=5,
- VGA_GC_BIT_MASK=8
-};
-
-enum { /* CGA palette selection (320x200x4) */
- VGA_CGA_PALETTE_GR_BR_RD=0,
- VGA_CGA_PALETTE_CY_MA_WH=1
-};
-
-enum { /* color select (text=border color 320x200=background 640x200=foreground */
- VGA_CGA_PALETTE_CS_BLUE=(1U << 0U),
- VGA_CGA_PALETTE_CS_GREEN=(1U << 1U),
- VGA_CGA_PALETTE_CS_RED=(1U << 2U),
- VGA_CGA_PALETTE_CS_INTENSITY=(1U << 3U),
- VGA_CGA_PALETTE_CS_ALT_INTENSITY=(1U << 4U)
-};
-
-extern VGA_RAM_PTR vga_graphics_ram;
-extern VGA_RAM_PTR vga_graphics_ram_fence;
-extern VGA_ALPHA_PTR vga_alpha_ram;
-extern VGA_ALPHA_PTR vga_alpha_ram_fence;
-
-extern uint32_t vga_clock_rates[4];
-extern unsigned char vga_pos_x,vga_pos_y,vga_color;
-extern unsigned char vga_width,vga_height;
-extern unsigned char vga_alpha_mode;
-extern unsigned char vga_hgc_type;
-extern unsigned int vga_base_3x0;
-extern unsigned long vga_ram_base;
-extern unsigned long vga_ram_size;
-extern unsigned char vga_stride;
-extern unsigned short vga_flags;
-extern unsigned char vga_9wide;
-
-unsigned char int10_getmode();
-void vga_write(const char *msg);
-void int10_setmode(unsigned char mode);
-void update_state_vga_memory_map_select(unsigned char c);
-unsigned char vga_force_read(const VGA_RAM_PTR p);
-void vga_force_write(VGA_RAM_PTR p,const unsigned char c);
-void vga_force_write_w(VGA_ALPHA_PTR p,const unsigned short c);
-int check_vga_3C0();
-void vga_sync_hw_cursor();
-void vga_sync_bios_cursor();
-void update_state_vga_memory_map_select(unsigned char c);
-void vga_set_memory_map(unsigned char c);
-void vga_bios_set_80x50_text();
-void update_state_from_vga();
-int probe_vga();
-void vga_write_state_DEBUG(FILE *f);
-void vga_relocate_crtc(unsigned char color);
-void vga_switch_to_mono();
-void vga_switch_to_color();
-void vga_turn_on_hgc();
-void vga_turn_off_hgc();
-void vga_set_cga_palette_and_background(unsigned char pal,unsigned char color);
-void vga_set_cga_mode(unsigned char b);
-void vga_tandy_setpalette(unsigned char i,unsigned char c);
-void vga_enable_256color_modex();
-void vga_set_stride(unsigned int stride);
-void vga_set_start_location(unsigned int offset);
-void vga_set_ypan_sub(unsigned char c);
-void vga_set_xpan(unsigned char c);
-void vga_splitscreen(unsigned int v);
-void vga_alpha_switch_to_font_plane();
-void vga_alpha_switch_from_font_plane();
-void vga_set_9wide(unsigned char en);
-void vga_select_charset_a_b(unsigned short a,unsigned short b);
-void vga_write_crtc_mode(struct vga_mode_params *p,unsigned int flags);
-void vga_correct_crtc_mode(struct vga_mode_params *p);
-void vga_read_crtc_mode(struct vga_mode_params *p);
-
-#define VGA_WRITE_CRTC_MODE_NO_CLEAR_SYNC 0x0001
-
-static inline unsigned char vga_read_CRTC(unsigned char i) {
- outp(vga_base_3x0+4,i);
- return inp(vga_base_3x0+5);
-}
-
-static inline unsigned char vga_read_GC(unsigned char i) {
- outp(0x3CE,i);
- return inp(0x3CF);
-}
-
-static inline unsigned char vga_read_sequencer(unsigned char i) {
- outp(0x3C4,i);
- return inp(0x3C5);
-}
-
-static inline void vga_write_sequencer(unsigned char i,unsigned char c) {
- outp(0x3C4,i);
- outp(0x3C5,c);
-}
-
-static inline void vga_write_GC(unsigned char i,unsigned char c) {
- outp(0x3CE,i);
- outp(0x3CF,c);
-}
-
-static inline void vga_write_CRTC(unsigned char i,unsigned char c) {
- outp(vga_base_3x0+4,i);
- outp(vga_base_3x0+5,c);
-}
-
-static inline void vga_write_color(unsigned char c) {
- vga_color = c;
-}
-
-static inline void vga_read_PAL(unsigned char i,unsigned char *p,unsigned int count) {
- count *= 3;
- outp(0x3C7,i);
- while (count-- > 0) *p++ = inp(0x3C9);
-}
-
-static inline void vga_write_PAL(unsigned char i,unsigned char *p,unsigned int count) {
- count *= 3;
- outp(0x3C8,i);
- while (count-- > 0) outp(0x3C9,*p++);
-}
-
-/* NTS: VGA hardware treats bit 5 of the index as a "screen enable".
- * When the caller is done reprogramming it is expected to or the index by VGA_AC_ENABLE */
-static inline void vga_write_AC(unsigned char i,unsigned char c) {
- inp(vga_base_3x0+0xA); /* reset flipflop */
- outp(0x3C0,i);
- outp(0x3C0,c);
- inp(vga_base_3x0+0xA);
-}
-
-static inline unsigned char vga_read_AC(unsigned char i) {
- unsigned char c;
-
- /* NTS: Reading the palette registers must occur this way because
- * an old S3 Virge DX card I have will misread the values
- * when PAS=1 otherwise. */
-
- inp(vga_base_3x0+0xA); /* reset latch */
- outp(0x3C0,i&(~0x20)); /* index with PAS=0 */
- c = inp(0x3C1);
- inp(vga_base_3x0+0xA); /* reset latch */
- outp(0x3C0,i|0x20); /* index with PAS=1 */
- inp(vga_base_3x0+0xA); /* reset latch */
-
- return c;
-}
-
-static inline void vga_AC_reenable_screen() {
- inp(vga_base_3x0+0xA); /* reset flipflop */
- outp(0x3C0,0x20);
- inp(vga_base_3x0+0xA);
-}
-
-static inline void vga_palette_lseek(unsigned int i) {
- outp(0x3C8,i);
-}
-
-static inline void vga_palette_write(unsigned char r,unsigned char g,unsigned char b) {
- outp(0x3C9,r);
- outp(0x3C9,g);
- outp(0x3C9,b);
-}
-
-static inline unsigned char vga_in_vsync() {
- unsigned int p = vga_base_3x0 + 0xA;
- return (inp(p) & 0x8);
-}
-
-static inline void vga_wait_for_hsync() {
- unsigned int p = vga_base_3x0 + 0xA;
- while ((inp(p) & 0x1) == 0);
-}
-
-static inline void vga_wait_for_hsync_end() {
- unsigned int p = vga_base_3x0 + 0xA;
- while ((inp(p) & 0x1) != 0);
-}
-
-static inline void vga_wait_for_vsync() {
- unsigned int p = vga_base_3x0 + 0xA;
- while ((inp(p) & 0x8) == 0);
-}
-
-static inline void vga_wait_for_vsync_end() {
- unsigned int p = vga_base_3x0 + 0xA;
- while ((inp(p) & 0x8) != 0);
-}
-
-static inline unsigned char vga_AC_RGB_to_code(unsigned char r,unsigned char g,unsigned char b) {
- return (((b>>1)&1)<<0)|(((g>>1)&1)<<1)|(((r>>1)&1)<<2)|
- (((b>>0)&1)<<3)|(((g>>0)&1)<<4)|(((r>>0)&1)<<5);
-}
-
-#if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32
-/* we have to call the Win16 executable buffer */
-#else
-# pragma aux int10_getmode = \
- "mov ax,0x0F00" \
- "int 0x10" \
- value [al] \
- modify [ax bx];
-
-# pragma aux int10_setmode = \
- "xor ah,ah" \
- "int 0x10" \
- parm [al] \
- modify [ax bx];
-#endif
-
-/* Watcom loves to reorder memory I/O on us. So to avoid problems we just have to
- * suck it up and write the VGA memory functions in assembly language where it can't
- * reorder access. Keeping the I/O in order is very important if we're to make
- * proper use of the VGA hardware latch */
-#if TARGET_MSDOS == 32
-#pragma aux vga_force_read = \
- "mov al,[ebx]" \
- modify [al] \
- value [al] \
- parm [ebx];
-#pragma aux vga_force_write = \
- "mov [ebx],al" \
- parm [ebx] [al];
-#else
-#pragma aux vga_force_read = \
- "mov al,es:[di]" \
- modify [al] \
- value [al] \
- parm [es di];
-#pragma aux vga_force_write = \
- "mov es:[di],al" \
- parm [es di] [al];
-#pragma aux vga_force_write_w = \
- "mov es:[di],ax" \
- parm [es di] [ax];
-#endif
-
-/* all video timing and mode related values.
- * notice that other params like graphics controller settings aren't included here,
- * since you can always set those up yourself without disturbing the video timing */
-/* NTS: VGA standard hardware seems to be designed so that generally clock_div2=1
- * means you divide the master clock by 2. But it also seems that this bit is
- * ignored in 256-color modes and the VGA acts like it's always clear (NOT SET),
- * timings are programmed as if 640x400, and pixels are doubled horizontally
- * regardless of the bit. Despite all that, the general mode timing calculations
- * work out correctly anyway. This is important to know, because it may affect
- * your ability to correctly use this API for major mode changes between
- * 256-color modes & other modes. */
-struct vga_mode_params {
- unsigned char clock_select:2; /* 0x3C2 Misc out reg bits 2-3 */
- unsigned char hsync_neg:1; /* 0x3C2 bit 6 */
- unsigned char vsync_neg:1; /* 0x3C2 bit 7 */
- unsigned char clock9:1; /* sequencer[1] bit 0 */
- unsigned char clock_div2:1; /* sequencer[1] bit 3 [divide master clock by 2] */
- unsigned char word_mode:1; /* CRTC[0x17] bit 6 = WORD MODE */
- unsigned char dword_mode:1; /* CRTC[0x14] bit 6 = DWORD MODE */
- unsigned short horizontal_total; /* CRTC[0] -5 */
- unsigned short horizontal_display_end; /* CRTC[1] -1 */
- unsigned short horizontal_blank_start; /* CRTC[2] */
- unsigned short horizontal_blank_end; /* CRTC[3] bit 0-4 & CRTC[5] bit 7 */
- unsigned short horizontal_start_retrace;/* CRTC[4] */
- unsigned short horizontal_end_retrace; /* CRTC[5] bit 0-4 */
- unsigned char horizontal_start_delay_after_total; /* CRTC[3] bit 5-6 */
- unsigned char horizontal_start_delay_after_retrace; /* CRTC[5] bit 5-6 */
- unsigned short vertical_total; /* CRTC[6] and CRTC[7] bit 0 and CRTC[7] bit 5 -2 */
- unsigned short vertical_start_retrace; /* CRTC[0x10] and CRTC[7] bit 2 and CRTC[7] bit 7 */
- unsigned short vertical_end_retrace; /* CRTC[0x11] bit 0-3 */
- unsigned char refresh_cycles_per_scanline; /* CRTC[0x11] bit 6 */
- unsigned char inc_mem_addr_only_every_4th; /* CRTC[0x14] bit 5 */
- unsigned short vertical_display_end; /* CRTC[0x12] and CRTC[7] bit 1 and CRTC[7] bit 6 */
- unsigned short vertical_blank_start; /* CRTC[0x15] and CRTC[7] bit 3 */
- unsigned short vertical_blank_end; /* CRTC[0x16] bit 0-7 */
- unsigned char shift_load_rate:1; /* sequencer[1] bit 2 */
- unsigned char shift4_enable:1; /* sequencer[1] bit 4 */
- unsigned char address_wrap_select:1; /* CRTC[0x17] bit 5 */
- unsigned char memaddr_div2:1; /* CRTC[0x17] bit 3 */
- unsigned char scanline_div2:1; /* CRTC[0x17] bit 2 */
- unsigned char map14:1; /* CRTC[0x17] bit 1 */
- unsigned char map13:1; /* CRTC[0x17] bit 0 */
- unsigned char scan_double:1; /* CRTC[0x09] bit 7 */
- unsigned char max_scanline; /* CRTC[0x09] bit 4-0 */
- unsigned char offset; /* CRTC[0x13] */
- unsigned char sync_enable:1; /* CRTC[0x17] bit 7 */
-};
-
-#endif /* __DOSLIB_HW_VGA_VGA_H */
-
+++ /dev/null
-
-/* TODO: Add two options
- *
- * 1) runtime enable/disable intercept (if you don't want to force to 480 anymore)
- *
- * 2) disable overscan options
- *
- * I'm noticing that the PEXHDCAP card is mis-detecting the 8-pixel overscan
- * as part of the active picture, so what I get is a capture that's missing
- * 8 pixels from the right side and capturing 8 pixels of black on the left
- * (or depending on the DOS game/demo, whatever color was programmed to be
- * the overscan color).
- *
- * So what would be useful is if the user could have us disable the overscan
- * border entirely, or disable overscan on the sides only, or top/bottom only,
- * or just leave it alone--whatever the user wants.
- *
- * I'm guessing modern VGA capture cards like the PEXHDCAP are made for Windows
- * desktops only where overscan color is never used, and that's why DOS overscan
- * colors confuse it a bit like that.
- *
- * On the S3 Virge PCI card I have, even for parts of the picture that are
- * pure black, the card seems to bias the R,G,B output a bit including overscan
- * and you can clearly see on the output a dark gray where active picture area
- * and overscan are rendered, which might have something to do with the shifted
- * image on capture as well.
- *
- * TODO: Reduce memory footprint. 32KB is a bit much, and it crowds out some of the
- * stuff you want to capture. */
-
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <ctype.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <math.h>
-#include <dos.h>
-
-#include <hw/dos/dos.h>
-
-unsigned char force89 = 0; /* 0=dont force 8=force 8 9=force 9 */
-unsigned char blanking_fix = 1;
-int blanking_align = 0;
-void (__interrupt __far *old_int10)();
-
-void __interrupt __far new_int10(union INTPACK ip) {
- if (ip.w.ax == 0xDFA0 && ip.w.bx == 0x1AC0) {
- switch (ip.h.cl) {
- case 0: /* install check */
- ip.w.ax = 0xDFAA;
- ip.w.bx = 0xCACA;
- break;
- case 1: /* change force89 option */
- ip.w.ax = 0xDFAA;
- ip.w.bx = 0xCACA;
- force89 = ip.h.ch;
- break;
- case 2: /* change blanking fix option */
- ip.w.ax = 0xDFAA;
- ip.w.bx = 0xCACA;
- blanking_fix = ip.h.ch;
- break;
- case 3: /* change blanking align option */
- ip.w.ax = 0xDFAA;
- ip.w.bx = 0xCACA;
- if (ip.h.ch & 0x80)
- blanking_align = -1;
- else
- blanking_align = ip.h.ch;
- break;
- default:
- ip.w.ax = 0xDFFF;
- ip.w.bx = 0xCACA;
- break;
- };
-
- return;
- }
- else if (ip.h.ah == 0x00) {
- unsigned int vtotal = 0x20B; /* NTS: two less than actual scanlines */
- unsigned int vretrace_s = 0x1EA;
- unsigned int vretrace_e = 0x1EC;
- unsigned int vdisplay_e = 0x1E0; /* NTS: this value is the display end, actual register value is - 1 */
- unsigned int vblank_s = 0x1E8;
- unsigned int vblank_e = 0x204;
- unsigned int mode = ip.h.al;
- unsigned char t,ov=0;
- unsigned int port;
-
- __asm {
- push ds
- mov ax,seg old_int10
- mov ds,ax
- mov ax,mode
- pushf
- callf dword ptr [old_int10]
- pop ds
- }
-
- /* mono or color? */
- port = (inp(0x3CC)&1)?0x3D4:0x3B4;
-
- if (ip.h.al <= 3 || ip.h.al == 7) {
- /* force 8-pixel */
- if (force89 == 8) {
- outp(0x3C4,0x01); /* seq, clocking mode reg */
- t = inp(0x3C5);
- outp(0x3C5,t|0x01); /* select 8 dots/char */
-
- t = inp(0x3CC); /* then select 25MHz clock */
- outp(0x3C2,t&(~0xC));
- }
- /* force 9-pixel */
- else if (force89 == 9) {
- outp(0x3C4,0x01); /* seq, clocking mode reg */
- t = inp(0x3C5);
- outp(0x3C5,t&0xFE); /* select 9 dots/char */
-
- t = inp(0x3CC); /* then select 28MHz clock */
- outp(0x3C2,(t&(~0xC)) | (1 << 2));
- }
- }
-
- if (blanking_fix) {
- unsigned int lines;
- unsigned int extra;
-
- /* read from the card how many active display lines there are */
- outp(port,0x12); /* display end */
- lines = inp(port+1); /* bits 0-7 */
- outp(port,0x07); /* overflow */
- t = inp(port+1);
- lines += (t&0x02)?0x100:0x000;
- lines += (t&0x40)?0x200:0x000;
- lines++; /* display reg is value - 1 */
-
- /* how many extra lines will there be? */
- if (lines < vdisplay_e)
- extra = vdisplay_e - lines;
- else
- extra = 0;
-
- /* now use that count to reprogram the blanking area and display params.
- * use the extra line count to adjust vertical retrace downward so the
- * shortened image is centered. if we do not do this, then the image is
- * "stuck" to the bottom of the screen with black at the top. */
- vdisplay_e = lines;
- vblank_s = lines + 8;
- if (blanking_align < 0) {
- /* align image to top */
- vretrace_s = lines + 10 + extra;
- vretrace_e = lines + 12 + extra;
- }
- else if (blanking_align == 0) {
- /* align to center */
- vretrace_s = lines + 10 + (extra/2);
- vretrace_e = lines + 12 + (extra/2);
- }
- else {
- /* align to bottom */
- vretrace_s = lines + 10;
- vretrace_e = lines + 12;
- }
- }
-
- /* vertical display end is actually value - 1 */
- vdisplay_e--;
-
- /* reprogram the CRTC back to a 480 line mode */
- outp(port,0x11); /* retrace end (also clear protect bit, and preserve whatever the "bandwidth" bit contains) */
- t = inp(port+1);
- outp(port+1,(t&0x70)+(vretrace_e&0xF));
-
- outp(port,0x17);
- t = inp(port+1);
- outp(port+1,t&0x7F);
-
- /* need to make sure line compare is beyond the end of picture */
- ov |= 0x10; /* bit 8 of line compare */
-
- outp(port,0x06); /* vertical total */
- outp(port+1,vtotal);
- ov |= (vtotal & 0x100) >> 8;
- ov |= ((vtotal & 0x200) >> ((8+1) - 5));
-
- outp(port,0x10); /* retrace start */
- outp(port+1,vretrace_s);
- ov |= ((vretrace_s & 0x100) >> (8 - 2));
- ov |= ((vretrace_s & 0x200) >> ((8+1) - 7));
-
- outp(port,0x12); /* display end */
- outp(port+1,vdisplay_e);
- ov |= ((vdisplay_e & 0x100) >> (8 - 1));
- ov |= ((vdisplay_e & 0x200) >> ((8+1) - 6));
-
- outp(port,0x15); /* blank start */
- outp(port+1,vblank_s);
- ov |= ((vblank_s & 0x100) >> (8 - 3));
- outp(port,0x09);
- t = inp(port+1);
- outp(port+1,(t&0x9F)+(vblank_s&0x200?0x20:0x00)+0x40/*make sure bit 9 of line compare is set*/);
-
- outp(port,0x16); /* blank end */
- outp(port+1,vblank_e);
-
- outp(port,0x07); /* overflow */
- outp(port+1,ov);
-
- outp(port,0x17);
- t = inp(port+1);
- outp(port+1,t|0x80);
-
- outp(port,0x11); /* retrace end (also clear protect bit, and preserve whatever the "bandwidth" bit contains) */
- t = inp(port+1);
- outp(port+1,t|0x80);
-
- return;
- }
-
- _chain_intr(old_int10);
-}
-
-static void help() {
- printf("VGA240 [options]\n");
- printf("\n");
- printf("Intercept VGA BIOS calls to force video modes with at least 480 scan lines,\n");
- printf("to improve scan converter output and allow capture/viewing with flat panel or\n");
- printf("VGA capture cards that do not support 350/400-line DOS modes.\n");
- printf("\n");
- printf("If the program is resident, you can run this program with other options to\n");
- printf("change configuration at runtime along with /SET\n");
- printf("\n");
- printf("(C) 2014 Jonathan Campbell\n");
- printf("\n");
- printf(" /INSTALL Make the program resident in memory.\n");
- printf(" /SET If the program is resident, update settings.\n");
- printf(" /BLANKFIX Active display is maintained from original mode,\n");
- printf(" blanking interval is extended to make 480 lines.\n");
- printf(" /NOBLANKFIX Active display is extended to 480 lines\n");
- printf(" /BA=N Adjust vertical retrace to center display area, where\n");
- printf(" N is -1 (top), 0 (center), 1 (bottom)\n");
- printf(" /8 Force alphanumeric modes to 8 pixels/char. Use this\n");
- printf(" option if your VGA scan/capture misdetects the output\n");
- printf(" as 640x480 instead of 720x480\n");
- printf(" /N8 Don't force to 8 pixels/char\n");
-}
-
-int resident() {
- unsigned int a=0,b=0;
-
- __asm {
- push ax
- push bx
- mov ax,0xDFA0
- mov bx,0x1AC0
- int 10h
- mov a,ax
- mov b,bx
- pop bx
- pop ax
- }
-
- return (a == 0xDFAA && b == 0xCACA);
-}
-
-int res_set_opt8(unsigned char func,unsigned char opt) {
- unsigned int a=0,b=0;
-
- __asm {
- push ax
- push bx
- push cx
- mov ax,0xDFA0
- mov bx,0x1AC0
- mov cl,func
- mov ch,opt
- int 10h
- mov a,ax
- mov b,bx
- pop cx
- pop bx
- pop ax
- }
-
- return (a == 0xDFAA && b == 0xCACA);
-}
-
-int main(int argc,char **argv) {
- unsigned char force89_set=0;
- unsigned char blanking_fix_set=0;
- unsigned char blanking_align_set=0;
- char *a,*command=NULL;
- int i;
-
-#if TARGET_MSDOS != 16
-# error you are not supposed to compile this for protected mode!
-#endif
-
- for (i=1;i < argc;) {
- a = argv[i++];
- if (*a == '/' || *a == '-') {
- do { a++; } while (*a == '/' || *a == '-');
-
- if (!strcasecmp(a,"i") || !strcasecmp(a,"install")) {
- command = a;
- }
- else if (!strcasecmp(a,"s") || !strcasecmp(a,"set")) {
- command = a;
- }
- else if (!strcasecmp(a,"BLANKFIX")) {
- blanking_fix_set=1;
- blanking_fix = 1;
- }
- else if (!strcasecmp(a,"NOBLANKFIX")) {
- blanking_fix_set=1;
- blanking_fix = 0;
- }
- else if (!strncasecmp(a,"BA=",3)) {
- a += 3;
- blanking_align = atoi(a);
- blanking_align_set = 1;
- }
- else if (!strcmp(a,"8")) {
- force89_set = 1;
- force89 = 8;
- }
- else if (!strcmp(a,"9")) {
- force89_set = 1;
- force89 = 9;
- }
- else if (!strcmp(a,"N8") || !strcmp(a,"N9")) {
- force89_set = 1;
- force89 = 0;
- }
- else {
- fprintf(stderr,"Unknown switch %s\n",a);
- command = NULL;
- break;
- }
- }
- else {
- fprintf(stderr,"Unknown switch %s\n",a);
- command = NULL;
- break;
- }
- }
-
- if (command == NULL) {
- help();
- return 1;
- }
-
- if (tolower(*command) == 'i') {
- if (resident()) {
- printf("This program is already resident\n");
- return 1;
- }
-
- _cli();
- old_int10 = _dos_getvect(0x10);
- _dos_setvect(0x10,new_int10);
- _sti();
- __asm {
- push ax
- mov ax,3
- int 10h
- pop ax
- }
- printf("INT 10h hooked\n"); fflush(stdout);
- _dos_keep(0,(18000+256)>>4); /* FIXME! How can an Open Watcom C program autodetect it's true resident size? */
- /* Examples given by Open Watcom are for .COM programs! */
- }
- else if (tolower(*command) == 's') {
- if (!resident()) {
- printf("This program is not yet installed\n");
- return 1;
- }
-
- if (force89_set) {
- if (!res_set_opt8(1,force89)) {
- printf("Failed to set force89\n");
- return 1;
- }
- }
- if (blanking_fix_set) {
- if (!res_set_opt8(2,blanking_fix)) {
- printf("Failed to set blank fix\n");
- return 1;
- }
- }
- if (blanking_align_set) {
- if (blanking_align < 0) blanking_align = 0xFF;
- if (!res_set_opt8(3,(unsigned char)blanking_align)) {
- printf("Failed to set blank align\n");
- return 1;
- }
-
- }
-
- __asm {
- push ax
- mov ax,3
- int 10h
- pop ax
- }
- }
-
- return 0;
-}
-
+++ /dev/null
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <i86.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/vga/vgatty.h>
-#include <hw/vga/vgagui.h>
-
-#ifdef TARGET_WINDOWS
-# include <hw/dos/winfcon.h>
-# include <windows/apihelp.h>
-# include <windows/dispdib/dispdib.h>
-# include <windows/win16eb/win16eb.h>
-#endif
-
-struct vga_menu_bar_state vga_menu_bar = {NULL,-1,0};
-void (*vga_menu_idle)() = NULL;
-
-int vga_menu_item_nonselectable(const struct vga_menu_item *m) {
- if (m->text == (char*)1) return 1;
- return 0;
-}
-
-void vga_menu_bar_draw() {
- VGA_ALPHA_PTR vga = vga_alpha_ram + (80*vga_menu_bar.row);
- const struct vga_menu_bar_item *m = vga_menu_bar.bar;
- unsigned int x,i,color,colorh,ti;
- unsigned char hi;
- const char *msg;
-
- /* start */
- x = 0;
- i = 0;
- if (m != NULL) {
- while (x < 80 && m->name != NULL) {
- ti = 1;
- msg = m->name;
- hi = (i == vga_menu_bar.sel);
- color = hi ? 0x1F00 : 0x7000;
- colorh = hi ? 0x1E00 : 0x7100;
- if (m->x >= 80) break;
- while (x < m->x) vga[x++] = color | 0x20;
- while (x < (m->x+m->w) && *msg != 0) {
- if (ti && *msg == m->shortcut_key) {
- vga[x++] = colorh | (*msg++);
- ti = 0;
- }
- else {
- vga[x++] = color | (*msg++);
- }
- }
- while (x < (m->x+m->w)) vga[x++] = color | 0x20;
- m++;
- i++;
- }
- }
-
- /* finish the bar */
- while (x < 80) vga[x++] = 0x7020;
-}
-
-void vga_menu_draw_item(VGA_ALPHA_PTR screen,const struct vga_menu_item **scan,unsigned int i,unsigned int w,unsigned int color,unsigned int tcolor) {
- const struct vga_menu_item *sci = scan[i];
- const char *txt = sci->text;
- unsigned int x,ti=1;
-
- screen += (i * vga_width) + 1;
- if (txt == (char*)1) {
- screen[-1] = 204 | color;
- for (x=0;x < w;x++) screen[x] = 205 | color;
- screen[w] = 185 | color;
- }
- else {
- for (x=0;x < w && txt[x] != 0;x++) {
- if (ti && tolower(txt[x]) == tolower(sci->shortcut_key)) {
- screen[x] = txt[x] | tcolor;
- ti = 0;
- }
- else {
- screen[x] = txt[x] | color;
- }
- }
- for (;x < w;x++) screen[x] = 0x20 | color;
- }
-}
-
-const struct vga_menu_item *vga_menu_bar_menuitem(const struct vga_menu_bar_item *menu,unsigned char row,unsigned int *spec) {
- const struct vga_menu_item *ret = NULL,**scan,*sci;
- unsigned int w,h,i,l,x,y,o,ks,nks,items,sel,c,altup=0;
- static const unsigned int hicolor = 0x7000;
- static const unsigned int hitcolor = 0x7100;
- static const unsigned int color = 0x1700;
- static const unsigned int tcolor = 0x1E00;
- VGA_ALPHA_PTR screen,buf;
- unsigned char loop = 1;
-
- /* FIX: If re-inited because of arrow keys, then one more alt-up should trigger release */
- if (*spec == 0x4B00 || *spec == 0x4D00)
- altup++;
-
- *spec = 0;
- if (menu != NULL) {
- sel = 0;
- w = h = 1;
- ks = (read_bios_keystate() & BIOS_KS_ALT);
- scan = menu->items;
- for (i=0;(sci=scan[i]) != NULL;i++) {
- if (sci->text == (char*)1) l = 1;
- else l = (unsigned int)strlen(sci->text);
- if (l > 78) l = 78;
- if (w < (l+2)) w = (l+2);
- if (h < (i+2) && (h+2+row) <= 25) h = i+2;
- }
- items = i;
-
-#if TARGET_MSDOS == 32
- buf = malloc(w * h * 2);
-#else
- buf = _fmalloc(w * h * 2);
-#endif
- screen = vga_alpha_ram + (row * vga_width) + menu->x;
- if (buf != NULL) {
- /* copy off the screen contents */
- for (y=0;y < h;y++) {
- o = w * y;
- i = vga_width * y;
- for (x=0;x < w;x++,o++,i++) buf[o] = screen[i];
- }
-
- /* draw the box */
- for (y=0;y < (h-1);y++) {
- o = vga_width * y;
- screen[o+0] = 186 | color;
- screen[o+w-1] = 186 | color;
- }
- o = vga_width * (h-1);
- screen[o+0] = 200 | color;
- for (x=1;x < (w-1);x++) screen[o+x] = 205 | color;
- screen[o+w-1] = 188 | color;
-
- /* draw the items */
- for (i=0;i < items;i++)
- vga_menu_draw_item(screen,scan,i,w-2,i == sel ? hicolor : color,i == sel ? hitcolor : tcolor);
-
- while (loop) {
- nks = (read_bios_keystate() & BIOS_KS_ALT);
- vga_menu_idle();
-
- if (ks && !nks) {
- if (++altup >= 2) break;
- }
- ks = nks;
-
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 27)
- break;
- else if (c == 13) {
- ret = scan[sel];
- break;
- }
- else if (c == 0x4800) {
- vga_menu_draw_item(screen,scan,sel,w-2,color,tcolor);
- do {
- if (sel == 0) sel = items-1;
- else sel--;
- } while (vga_menu_item_nonselectable(scan[sel]));
- vga_menu_draw_item(screen,scan,sel,w-2,hicolor,hitcolor);
- }
- else if (c == 0x5000) {
- vga_menu_draw_item(screen,scan,sel,w-2,color,tcolor);
- do {
- if (++sel >= items) sel = 0;
- } while (vga_menu_item_nonselectable(scan[sel]));
- vga_menu_draw_item(screen,scan,sel,w-2,hicolor,hitcolor);
- }
- else if (c == 0x4B00 || c == 0x4D00) {
- *spec = c;
- ret = NULL;
- break;
- }
- else if (c > 32 && c < 127) {
- int patience = items;
-
- vga_menu_draw_item(screen,scan,sel,w-2,color,tcolor);
- /* look for the first menu item with that shortcut key */
- if (++sel >= items) sel = 0;
- while (tolower(scan[sel]->shortcut_key) != tolower(c)) {
- if (--patience == 0) {
- sel = 0;
- break;
- }
-
- if (++sel >= items) sel = 0;
- }
- vga_menu_draw_item(screen,scan,sel,w-2,hicolor,hitcolor);
- if (patience > 0) {
- ret = scan[sel];
- break;
- }
- }
- }
- }
-
- /* copy screen contents back */
- for (y=0;y < h;y++) {
- i = w * y;
- o = vga_width * y;
- for (x=0;x < w;x++,o++,i++) screen[o] = buf[i];
- }
-
-#if TARGET_MSDOS == 32
- free(buf);
-#else
- _ffree(buf);
-#endif
- }
- }
-
- return ret;
-}
-
-const struct vga_menu_item *vga_menu_bar_keymon() {
- const struct vga_menu_bar_item *m = NULL;
- const struct vga_menu_item *ret = NULL;
- unsigned int spec=0;
- int c,i;
-
- if (vga_menu_bar.bar == NULL)
- return ret;
-
- if (read_bios_keystate() & BIOS_KS_ALT) {
- vga_menu_bar.sel = 0;
- vga_menu_bar_draw();
-
-again:
- do {
- vga_menu_idle();
- if (kbhit()) {
- c = getch();
- if (c == 0) {
- i = 0;
- c = getch();
- if (c == 0x9B) { /* ALT-left */
- if (--vga_menu_bar.sel < 0) {
- vga_menu_bar.sel = 0;
- while (vga_menu_bar.bar[vga_menu_bar.sel].name != NULL) vga_menu_bar.sel++;
- vga_menu_bar.sel--;
- }
- m = &vga_menu_bar.bar[vga_menu_bar.sel];
- vga_menu_bar_draw();
- }
- else if (c == 0x9D) { /* ALT-right */
- if (vga_menu_bar.bar[++vga_menu_bar.sel].name == NULL) vga_menu_bar.sel = 0;
- m = &vga_menu_bar.bar[vga_menu_bar.sel];
- vga_menu_bar_draw();
- }
- else {
- int oi = vga_menu_bar.sel;
-
- for (m=vga_menu_bar.bar;m->name != NULL;m++,i++) {
- if (c == m->shortcut_scan)
- break;
- }
- if (m->name == NULL) {
- m = NULL;
- vga_menu_bar.sel = -1;
- }
- else {
- vga_menu_bar.sel = i;
- }
-
- if (oi != vga_menu_bar.sel)
- vga_menu_bar_draw();
-
- if (m != NULL)
- break;
- }
- }
- }
- } while (read_bios_keystate() & BIOS_KS_ALT);
-
- if (!(read_bios_keystate() & BIOS_KS_ALT)) {
- while (kbhit()) getch();
- }
-
- if (m != NULL) {
- ret = vga_menu_bar_menuitem(m,vga_menu_bar.row+1,&spec);
- if (ret == NULL) {
- if (spec == 0x4B00) {
- if (--vga_menu_bar.sel < 0) {
- vga_menu_bar.sel = 0;
- while (vga_menu_bar.bar[vga_menu_bar.sel].name != NULL) vga_menu_bar.sel++;
- vga_menu_bar.sel--;
- }
- m = &vga_menu_bar.bar[vga_menu_bar.sel];
- vga_menu_bar_draw();
- goto again;
- }
- else if (spec == 0x4D00) {
- if (vga_menu_bar.bar[++vga_menu_bar.sel].name == NULL) vga_menu_bar.sel = 0;
- m = &vga_menu_bar.bar[vga_menu_bar.sel];
- vga_menu_bar_draw();
- goto again;
- }
- }
- }
-
- while (read_bios_keystate() & BIOS_KS_ALT);
- vga_menu_bar.sel = -1;
- vga_menu_bar_draw();
- }
-
- return ret;
-}
-
-int vga_msg_box_create(struct vga_msg_box *b,const char *msg,unsigned int extra_y,unsigned int min_x) {
- unsigned int w=min_x,h=max(1,extra_y),x=0,y,px,py,i,o;
- static const unsigned int color = 0x1E00;
- const char *scan;
-
- scan = msg;
- while (*scan != 0) {
- if (*scan == '\n') {
- x=0;
- h++;
- }
- else if ((unsigned char)(*scan) >= 32) {
- x++;
- if (w < x) w = x;
- }
- scan++;
- }
- w += 4; if (w > 80) w = 80;
- h += 2; if (h > 25) h = 25;
- px = (vga_width - w) / 2;
- py = (vga_height - h) / 2;
- b->screen = vga_alpha_ram + (py * vga_width) + px;
- b->x = px;
- b->y = py;
- b->w = w;
- b->h = h;
-
-#if TARGET_MSDOS == 32
- b->buf = malloc(w * h * 2);
-#else
- b->buf = _fmalloc(w * h * 2);
-#endif
- if (b->buf != NULL) {
- /* copy the screen to buffer */
- for (y=0;y < h;y++) {
- i = y * vga_width;
- o = y * w;
- for (x=0;x < w;x++,i++,o++) b->buf[o] = b->screen[i];
- }
- }
-
- /* draw border */
- for (y=1;y < (h-1);y++) {
- o = y * vga_width;
- b->screen[o+0] = 186 | color;
- b->screen[o+1] = 32 | color;
- b->screen[o+w-2] = 32 | color;
- b->screen[o+w-1] = 186 | color;
- }
- o = (h-1)*vga_width;
- for (x=1;x < (w-1);x++) {
- b->screen[x] = 205 | color;
- b->screen[x+o] = 205 | color;
- }
- b->screen[0] = 201 | color;
- b->screen[w-1] = 187 | color;
- b->screen[o] = 200 | color;
- b->screen[o+w-1] = 188 | color;
-
- x = 0;
- y = 0;
- o = vga_width + 2;
- scan = msg;
- while (*scan != 0) {
- if (*scan == '\n') {
- while (x < (w-4)) {
- b->screen[o+x] = 32 | color;
- x++;
- }
- if (++y >= (h-2)) break;
- x = 0;
- o += vga_width;
- }
- else if ((unsigned char)(*scan) >= 32) {
- if (x < (w-4)) b->screen[o+x] = *scan | color;
- x++;
- }
- scan++;
- }
- while (y < (h-2)) {
- while (x < (w-4)) {
- b->screen[o+x] = 32 | color;
- x++;
- }
- ++y;
- x = 0;
- o += vga_width;
- }
-
- b->w = w;
- b->h = h;
- return 1;
-}
-
-void vga_msg_box_destroy(struct vga_msg_box *b) {
- unsigned int x,y,i,o;
-
- if (b) {
- if (b->buf) {
- /* copy screen back */
- for (y=0;y < b->h;y++) {
- i = y * b->w;
- o = y * vga_width;
- for (x=0;x < b->w;x++,i++,o++) b->screen[o] = b->buf[i];
- }
-
-#if TARGET_MSDOS == 32
- free(b->buf);
-#else
- _ffree(b->buf);
-#endif
- b->buf = NULL;
- }
- b->screen = NULL;
- }
-}
-
-int confirm_yes_no_dialog(const char *message) {
- struct vga_msg_box box = {NULL,NULL,0,0};
- unsigned int x,bw;
- int ret = 1,c;
-
- bw = 8;
- if (vga_msg_box_create(&box,message,2,(bw*2)+2)) {
- x = ((box.w+2-(bw*2))/2)+box.x;
- vga_write_color(0x70);
- vga_moveto(x,box.y+box.h-2);
- vga_write(" ");
- vga_write_color(0x71);
- vga_write("Y");
- vga_write_color(0x70);
- vga_write("es ");
- vga_moveto(x+bw,box.y+box.h-2);
- vga_write(" ");
- vga_write_color(0x71);
- vga_write("N");
- vga_write_color(0x70);
- vga_write("o ");
-
- while (1) {
- vga_menu_idle();
- if (kbhit()) {
- c = getch();
- if (c == 0) c = getch() << 8;
-
- if (c == 'Y' || c == 'y') {
- ret = 1;
- break;
- }
- else if (c == 'N' || c == 'n') {
- ret = 0;
- break;
- }
- else if (c == 27) {
- ret = 0;
- break;
- }
- }
- }
-
- vga_msg_box_destroy(&box);
- }
-
- return ret;
-}
-
+++ /dev/null
-
-#ifndef __DOSLIB_HW_VGA_VGAGUI_H
-#define __DOSLIB_HW_VGA_VGAGUI_H
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-#define MAX_MENU_BAR 16
-
-struct vga_menu_item {
- char* text;
- unsigned char shortcut_key;
- unsigned char disabled:1;
- unsigned char reserved:7;
-};
-
-struct vga_menu_bar_item {
- char* name;
- unsigned char shortcut_key,shortcut_scan;
- unsigned char x,w;
- const struct vga_menu_item** items;
-};
-
-struct vga_menu_bar_state {
- const struct vga_menu_bar_item* bar;
- int sel;
- unsigned char row;
-};
-
-struct vga_msg_box {
- VGA_ALPHA_PTR screen,buf;
- unsigned int w,h,x,y;
-};
-
-extern struct vga_menu_bar_state vga_menu_bar;
-
-extern void (*vga_menu_idle)();
-
-void vga_menu_draw_item(VGA_ALPHA_PTR screen,const struct vga_menu_item **scan,unsigned int i,unsigned int w,unsigned int color,unsigned int tcolor);
-const struct vga_menu_item *vga_menu_bar_menuitem(const struct vga_menu_bar_item *menu,unsigned char row,unsigned int *spec);
-int vga_msg_box_create(struct vga_msg_box *b,const char *msg,unsigned int extra_y,unsigned int min_x);
-int vga_menu_item_nonselectable(const struct vga_menu_item *m);
-void vga_msg_box_destroy(struct vga_msg_box *b);
-int confirm_yes_no_dialog(const char *message);
-const struct vga_menu_item *vga_menu_bar_keymon();
-void vga_menu_bar_draw();
-
-#endif /* __DOSLIB_HW_VGA_VGAGUI_H */
-
+++ /dev/null
-#include <stdio.h>
-#include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#include <malloc.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <i86.h>
-#include <dos.h>
-
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/vga/vga.h>
-#include <hw/vga/vgatty.h>
-#include <hw/vga/vgagui.h>
-
-#ifdef TARGET_WINDOWS
-# include <hw/dos/winfcon.h>
-# include <windows/apihelp.h>
-# include <windows/dispdib/dispdib.h>
-# include <windows/win16eb/win16eb.h>
-#endif
-
-void vga_scroll_up(unsigned char lines) {
- VGA_ALPHA_PTR rd,wr;
- unsigned char row,c;
-
- if (lines == 0)
- return;
- else if (lines > vga_height)
- lines = vga_height;
-
- if (lines < vga_height) {
- unsigned char lcopy = vga_height - lines;
- wr = vga_alpha_ram;
- rd = vga_alpha_ram + (lines * vga_stride);
- for (row=0;row < lcopy;row++) {
- for (c=0;c < vga_stride;c++) {
- *wr++ = *rd++;
- }
- }
- }
-
- wr = vga_alpha_ram + ((vga_height - lines) * vga_stride);
- for (row=0;row < lines;row++) {
- for (c=0;c < vga_stride;c++)
- *wr++ = (vga_color << 8) | 0x20;
- }
-}
-
-void vga_cursor_down() {
- if (++vga_pos_y >= vga_height) {
- vga_pos_y = vga_height - 1;
- vga_scroll_up(1);
- }
-}
-
-void vga_writec(char c) {
- if (c == '\n') {
- vga_pos_x = 0;
- vga_cursor_down();
- }
- else if (c == '\t') {
- vga_pos_x = (vga_pos_x | 7) + 1;
- if (vga_pos_x >= vga_width) {
- vga_pos_x = 0;
- vga_cursor_down();
- }
- }
- else {
- if (vga_pos_x >= vga_width) {
- vga_pos_x = 0;
- vga_cursor_down();
- }
-
- vga_alpha_ram[(vga_pos_y * vga_stride) + vga_pos_x] = c | (vga_color << 8);
- vga_pos_x++;
- }
-}
-
-void vga_write(const char *msg) {
- while (*msg != 0) vga_writec(*msg++);
-}
-
-void vga_write_sync() { /* sync writing pos with BIOS cursor and hardware */
- if (vga_alpha_mode) {
- unsigned int ofs = (vga_pos_y * vga_stride) + vga_pos_x;
- vga_write_CRTC(0xE,ofs >> 8);
- vga_write_CRTC(0xF,ofs);
- }
-}
-
-void vga_clear() {
- VGA_ALPHA_PTR wr;
- unsigned char r,c;
-
- wr = vga_alpha_ram;
- for (r=0;r < vga_height;r++) {
- for (c=0;c < vga_stride;c++) {
- *wr++ = 0x0720;
- }
- }
-}
-
+++ /dev/null
-
-#include <hw/cpu/cpu.h>
-#include <stdint.h>
-
-char *vga_gets(unsigned int maxlen);
-void vga_moveto(unsigned char x,unsigned char y);
-void vga_scroll_up(unsigned char lines);
-void vga_cursor_down();
-void vga_writec(char c);
-void vga_write(const char *msg);
-void vga_write_sync();
-void vga_clear();
-
+++ /dev/null
-
-!ifeq HPS /
-MAKECMD=env "parent_build_list=$(TO_BUILD)" ./make.sh
-COPY=cp
-RM=rm
-!else
-MAKECMD=make.bat
-COPY=copy
-RM=del
-!endif
-
-# we need to know where "HERE" is
-HERE = $+$(%cwd)$-
-
-# HW\VGA-----------------------------------------------------------------------------------
-HW_VGA_LIB_DIR=$(REL)$(HPS)hw$(HPS)vga
-HW_VGA_LIB=$(HW_VGA_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)vga.lib
-!ifdef TARGET_WINDOWS
-HW_VGA_LIB_DEPENDENCIES=$(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(WINDOWS_DISPDIB_LIB) $(WINDOWS_DISPDIB_LIB_DEPENDENCIES)
-HW_VGA_LIB_WLINK_LIBRARIES=library $(HW_VGA_LIB) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(WINDOWS_DISPDIB_LIB_WLINK_LIBRARIES)
-!else
-HW_VGA_LIB_DEPENDENCIES=$(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES)
-HW_VGA_LIB_WLINK_LIBRARIES=library $(HW_VGA_LIB) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES)
-!endif
-
-# HW\VGA-----------------------------------------------------------------------------------
-HW_VGATTY_LIB_DIR=$(REL)$(HPS)hw$(HPS)vga
-HW_VGATTY_LIB=$(HW_VGATTY_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)vgatty.lib
-!ifdef TARGET_WINDOWS
-HW_VGATTY_LIB_DEPENDENCIES=$(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(WINDOWS_DISPDIB_LIB) $(WINDOWS_DISPDIB_LIB_DEPENDENCIES)
-HW_VGATTY_LIB_WLINK_LIBRARIES=library $(HW_VGATTY_LIB) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(WINDOWS_DISPDIB_LIB_WLINK_LIBRARIES)
-!else
-HW_VGATTY_LIB_DEPENDENCIES=$(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES)
-HW_VGATTY_LIB_WLINK_LIBRARIES=library $(HW_VGATTY_LIB) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES)
-!endif
-
-# HW\VGA-----------------------------------------------------------------------------------
-HW_VGAGUI_LIB_DIR=$(REL)$(HPS)hw$(HPS)vga
-HW_VGAGUI_LIB=$(HW_VGAGUI_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)vgagui.lib
-!ifdef TARGET_WINDOWS
-HW_VGAGUI_LIB_DEPENDENCIES=$(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES) $(WINDOWS_DISPDIB_LIB) $(WINDOWS_DISPDIB_LIB_DEPENDENCIES)
-HW_VGAGUI_LIB_WLINK_LIBRARIES=library $(HW_VGAGUI_LIB) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES) $(WINDOWS_DISPDIB_LIB_WLINK_LIBRARIES)
-!else
-HW_VGAGUI_LIB_DEPENDENCIES=$(HW_VGA_LIB) $(HW_VGA_LIB_DEPENDENCIES) $(HW_DOS_LIB) $(HW_DOS_LIB_DEPENDENCIES) $(HW_CPU_LIB) $(HW_CPU_LIB_DEPENDENCIES)
-HW_VGAGUI_LIB_WLINK_LIBRARIES=library $(HW_VGAGUI_LIB) $(HW_VGA_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES) $(HW_CPU_LIB_WLINK_LIBRARIES)
-!endif
-
-# HW\CPU------------------------------------------------------------------------------------
-HW_CPU_LIB=$(HW_CPU_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)cpu.lib
-HW_CPU_LIB_DIR=$(REL)$(HPS)hw$(HPS)cpu
-HW_CPU_LIB_DEPENDENCIES=$(WINDOWS_NTVDMLIB_LIB) $(HW_DOS_LIB)
-HW_CPU_LIB_WLINK_LIBRARIES=$(WINDOWS_NTVDMLIB_LIB_WLINK_LIBRARIES) library $(HW_DOS_LIB) library $(HW_CPU_LIB)
-
-# HW\DOS------------------------------------------------------------------------------------
-HW_DOS_LIB=$(HW_DOS_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)dos.lib
-HW_DOS_LIB_DIR=$(REL)$(HPS)hw$(HPS)dos
-HW_DOS_LIB_DEPENDENCIES=$(WINDOWS_NTVDMLIB_LIB) $(HW_CPU_LIB)
-HW_DOS_LIB_WLINK_LIBRARIES=$(WINDOWS_NTVDMLIB_LIB_WLINK_LIBRARIES) library $(HW_DOS_LIB) library $(HW_CPU_LIB)
-
-# HW\LLMEM----------------------------------------------------------------------------------
-HW_LLMEM_LIB_DIR=$(REL)$(HPS)hw$(HPS)llmem
-HW_LLMEM_LIB=$(HW_LLMEM_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)llmem.lib
-HW_LLMEM_LIB_DEPENDENCIES=$(HW_DOS_LIB) $(HW_CPU_LIB) $(WINDOWS_NTVDMLIB_LIB)
-HW_LLMEM_LIB_WLINK_LIBRARIES=library $(HW_DOS_LIB) library $(HW_CPU_LIB) $(WINDOWS_NTVDMLIB_LIB_WLINK_LIBRARIES) library $(HW_LLMEM_LIB)
-
-# HW\8042-----------------------------------------------------------------------------------
-HW_8042_LIB_DIR=$(REL)$(HPS)hw$(HPS)8042
-HW_8042_LIB=$(HW_8042_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)8042.lib
-HW_8042_LIB_DEPENDENCIES=
-HW_8042_LIB_WLINK_LIBRARIES=library $(HW_8042_LIB)
-
-# HW\ACPI-----------------------------------------------------------------------------------
-HW_ACPI_LIB_DIR=$(REL)$(HPS)hw$(HPS)acpi
-HW_ACPI_LIB=$(HW_ACPI_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)acpi.lib
-HW_ACPI_LIB_DEPENDENCIES=
-HW_ACPI_LIB_WLINK_LIBRARIES=library $(HW_ACPI_LIB)
-
-# HW\8237-----------------------------------------------------------------------------------
-HW_8237_LIB_DIR=$(REL)$(HPS)hw$(HPS)8237
-HW_8237_LIB=$(HW_8237_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)8237.lib
-HW_8237_LIB_DEPENDENCIES=
-HW_8237_LIB_WLINK_LIBRARIES=library $(HW_8237_LIB)
-
-# HW\8250-----------------------------------------------------------------------------------
-HW_8250_LIB_DIR=$(REL)$(HPS)hw$(HPS)8250
-HW_8250_LIB=$(HW_8250_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)8250.lib
-HW_8250_LIB_DEPENDENCIES=
-HW_8250_LIB_WLINK_LIBRARIES=library $(HW_8250_LIB)
-
-HW_8250PNP_LIB_DIR=$(REL)$(HPS)hw$(HPS)8250
-HW_8250PNP_LIB=$(HW_8250PNP_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)8250pnp.lib
-HW_8250PNP_LIB_DEPENDENCIES=$(HW_8250_LIB)
-HW_8250PNP_LIB_WLINK_LIBRARIES=library $(HW_8250PNP_LIB) library $(HW_8250_LIB)
-
-# HW\8254-----------------------------------------------------------------------------------
-HW_8254_LIB_DIR=$(REL)$(HPS)hw$(HPS)8254
-HW_8254_LIB=$(HW_8254_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)8254.lib
-HW_8254_LIB_DEPENDENCIES=
-HW_8254_LIB_WLINK_LIBRARIES=library $(HW_8254_LIB)
-
-# HW\8259-----------------------------------------------------------------------------------
-HW_8259_LIB_DIR=$(REL)$(HPS)hw$(HPS)8259
-HW_8259_LIB=$(HW_8259_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)8259.lib
-HW_8259_LIB_DEPENDENCIES=
-HW_8259_LIB_WLINK_LIBRARIES=library $(HW_8259_LIB)
-
-# HW\ACPI-----------------------------------------------------------------------------------
-HW_ACPI_LIB_DIR=$(REL)$(HPS)hw$(HPS)acpi
-HW_ACPI_LIB=$(HW_ACPI_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)acpi.lib
-HW_ACPI_LIB_DEPENDENCIES=
-HW_ACPI_LIB_WLINK_LIBRARIES=library $(HW_ACPI_LIB)
-
-# HW\APM------------------------------------------------------------------------------------
-HW_APM_LIB_DIR=$(REL)$(HPS)hw$(HPS)apm
-HW_APM_LIB=$(HW_APM_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)apm.lib
-HW_APM_LIB_DEPENDENCIES=
-HW_APM_LIB_WLINK_LIBRARIES=library $(HW_APM_LIB)
-
-# HW\IDE------------------------------------------------------------------------------------
-HW_IDE_LIB_DIR=$(REL)$(HPS)hw$(HPS)ide
-HW_IDE_LIB=$(HW_IDE_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)idelib.lib
-HW_IDE_LIB_DEPENDENCIES=
-HW_IDE_LIB_WLINK_LIBRARIES=library $(HW_IDE_LIB)
-
-# HW\FLOPPY---------------------------------------------------------------------------------
-HW_FLOPPY_LIB_DIR=$(REL)$(HPS)hw$(HPS)floppy
-HW_FLOPPY_LIB=$(HW_FLOPPY_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)floppy.lib
-HW_FLOPPY_LIB_DEPENDENCIES=
-HW_FLOPPY_LIB_WLINK_LIBRARIES=library $(HW_FLOPPY_LIB)
-
-# HW\ADLIB----------------------------------------------------------------------------------
-HW_ADLIB_LIB_DIR=$(REL)$(HPS)hw$(HPS)adlib
-HW_ADLIB_LIB=$(HW_ADLIB_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)adlib.lib
-HW_ADLIB_LIB_DEPENDENCIES=
-HW_ADLIB_LIB_WLINK_LIBRARIES=library $(HW_ADLIB_LIB)
-
-# HW\ISAPNP---------------------------------------------------------------------------------
-HW_ISAPNP_LIB_DIR=$(REL)$(HPS)hw$(HPS)isapnp
-HW_ISAPNP_LIB=$(HW_ISAPNP_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)isapnp.lib
-HW_ISAPNP_LIB_DEPENDENCIES=
-HW_ISAPNP_LIB_WLINK_LIBRARIES=library $(HW_ISAPNP_LIB)
-
-# HW\SMBIOS---------------------------------------------------------------------------------
-HW_SMBIOS_LIB_DIR=$(REL)$(HPS)hw$(HPS)smbios
-HW_SMBIOS_LIB=$(HW_SMBIOS_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)smbios.lib
-HW_SMBIOS_LIB_DEPENDENCIES=
-HW_SMBIOS_LIB_WLINK_LIBRARIES=library $(HW_SMBIOS_LIB)
-
-# HW\PARPORT--------------------------------------------------------------------------------
-HW_PARPORT_LIB_DIR=$(REL)$(HPS)hw$(HPS)parport
-HW_PARPORT_LIB=$(HW_PARPORT_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)parport.lib
-HW_PARPORT_LIB_DEPENDENCIES=
-HW_PARPORT_LIB_WLINK_LIBRARIES=library $(HW_PARPORT_LIB)
-
-HW_PARPNP_LIB_DIR=$(HW_PARPORT_LIB_DIR)
-HW_PARPNP_LIB=$(HW_PARPNP_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)parpnp.lib
-HW_PARPNP_LIB_DEPENDENCIES=
-HW_PARPNP_LIB_WLINK_LIBRARIES=library $(HW_PARPNP_LIB)
-
-# HW\FLATREAL-------------------------------------------------------------------------------
-HW_FLATREAL_LIB_DIR=$(REL)$(HPS)hw$(HPS)flatreal
-HW_FLATREAL_LIB=$(HW_FLATREAL_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)flatreal.lib
-HW_FLATREAL_LIB_DEPENDENCIES=
-HW_FLATREAL_LIB_WLINK_LIBRARIES=library $(HW_FLATREAL_LIB)
-
-# HW\BIOSDISK-------------------------------------------------------------------------------
-HW_BIOSDISK_LIB_DIR=$(REL)$(HPS)hw$(HPS)biosdisk
-HW_BIOSDISK_LIB=$(HW_BIOSDISK_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)biosdisk.lib
-HW_BIOSDISK_LIB_DEPENDENCIES=
-HW_BIOSDISK_LIB_WLINK_LIBRARIES=library $(HW_BIOSDISK_LIB)
-
-# HW\PCI------------------------------------------------------------------------------------
-HW_PCI_LIB_DIR=$(REL)$(HPS)hw$(HPS)pci
-HW_PCI_LIB=$(HW_PCI_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)pci.lib
-HW_PCI_LIB_DEPENDENCIES=
-HW_PCI_LIB_WLINK_LIBRARIES=library $(HW_PCI_LIB)
-
-# HW\PCIE-----------------------------------------------------------------------------------
-HW_PCIE_LIB_DIR=$(REL)$(HPS)hw$(HPS)pcie
-HW_PCIE_LIB=$(HW_PCIE_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)pcie.lib
-HW_PCIE_LIB_DEPENDENCIES=$(HW_ACPI_LIB) $(HW_FLATREAL_LIB) $(HW_LLMEM_LIB)
-HW_PCIE_LIB_WLINK_LIBRARIES=library $(HW_PCIE_LIB) $(HW_ACPI_LIB_WLINK_LIBRARIES) $(HW_FLATREAL_LIB_WLINK_LIBRARIES) $(HW_LLMEM_LIB_WLINK_LIBRARIES)
-
-# HW\RTC------------------------------------------------------------------------------------
-HW_RTC_LIB_DIR=$(REL)$(HPS)hw$(HPS)rtc
-HW_RTC_LIB=$(HW_RTC_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)rtc.lib
-HW_RTC_LIB_DEPENDENCIES=
-HW_RTC_LIB_WLINK_LIBRARIES=library $(HW_RTC_LIB)
-
-# HW\VESA-----------------------------------------------------------------------------------
-HW_VESA_LIB_DIR=$(REL)$(HPS)hw$(HPS)vesa
-HW_VESA_LIB=$(HW_VESA_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)vesa.lib
-HW_VESA_LIB_DEPENDENCIES=
-HW_VESA_LIB_WLINK_LIBRARIES=library $(HW_VESA_LIB)
-
-# HW\SNDSB----------------------------------------------------------------------------------
-HW_SNDSB_LIB_DIR=$(REL)$(HPS)hw$(HPS)sndsb
-HW_SNDSB_LIB=$(HW_SNDSB_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)sndsb.lib
-HW_SNDSB_LIB_DEPENDENCIES=
-HW_SNDSB_LIB_WLINK_LIBRARIES=library $(HW_SNDSB_LIB)
-
-HW_SNDSBPNP_LIB_DIR=$(HW_SNDSB_LIB_DIR)
-HW_SNDSBPNP_LIB=$(HW_SNDSBPNP_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)sndsbpnp.lib
-HW_SNDSBPNP_LIB_DEPENDENCIES=
-HW_SNDSBPNP_LIB_WLINK_LIBRARIES=library $(HW_SNDSBPNP_LIB)
-
-# HW\ULTRASND-------------------------------------------------------------------------------
-HW_ULTRASND_LIB_DIR=$(REL)$(HPS)hw$(HPS)ultrasnd
-HW_ULTRASND_LIB=$(HW_ULTRASND_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)ultrasnd.lib
-HW_ULTRASND_LIB_DEPENDENCIES=
-HW_ULTRASND_LIB_WLINK_LIBRARIES=library $(HW_ULTRASND_LIB)
-
-# HW\MB\INTEL\PIIX3-------------------------------------------------------------------------
-HW_MB_INTEL_PIIX3_LIB=$(REL)$(HPS)hw$(HPS)mb$(HPS)intel$(HPS)piix3
-HW_MB_INTEL_PIIX3=$(HW_MB_INTEL_PIIX3_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)piix3.lib
-HW_MB_INTEL_PIIX3_DEPENDENCIES=
-HW_MB_INTEL_PIIX3_WLINK_LIBRARIES=library $(HW_MB_INTEL_PIIX3_LIB)
-
-# WINDOWS\NTVDM-----------------------------------------------------------------------------
-!ifndef TARGET_OS2
-WINDOWS_NTVDMLIB_LIB_DIR=$(REL)$(HPS)windows$(HPS)ntvdm
-WINDOWS_NTVDMLIB_LIB=$(WINDOWS_NTVDMLIB_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)ntvdmlib.lib
-WINDOWS_NTVDMLIB_LIB_DEPENDENCIES=$(HW_DOS_LIB) $(HW_CPU_LIB)
-WINDOWS_NTVDMLIB_LIB_WLINK_LIBRARIES=library $(HW_DOS_LIB) library $(HW_CPU_LIB) library $(WINDOWS_NTVDMLIB_LIB)
-! ifdef TARGET_WINDOWS
-! ifeq TARGET_MSDOS 32
-! ifeq TARGET_WINDOWS 40
-WINDOWS_NTVDMVDD_LIB_DIR=$(REL)$(HPS)windows$(HPS)ntvdm
-WINDOWS_NTVDMVDD_LIB=$(WINDOWS_NTVDMVDD_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)ntvdmvdd.lib
-WINDOWS_NTVDMVDD_LIB_DEPENDENCIES=$(HW_DOS_LIB) $(HW_CPU_LIB) $(WINDOWS_NTVDMLIB_LIB)
-WINDOWS_NTVDMVDD_LIB_WLINK_LIBRARIES=library $(HW_DOS_LIB) library $(HW_CPU_LIB) library $(WINDOWS_NTVDMLIB_LIB) library $(WINDOWS_NTVDMVDD_LIB)
-! endif
-! endif
-! endif
-!endif
-
-# WINDOWS\W9XVMM----------------------------------------------------------------------------
-WINDOWS_W9XVMM_LIB_DIR=$(REL)$(HPS)windows$(HPS)w9xvmm
-WINDOWS_W9XVMM_LIB=$(WINDOWS_W9XVMM_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)w9xvmm.lib
-WINDOWS_W9XVMM_LIB_DEPENDENCIES=$(HW_DOS_LIB) $(HW_CPU_LIB) $(WINDOWS_NTVDMLIB_LIB)
-WINDOWS_W9XVMM_LIB_WLINK_LIBRARIES=library $(HW_DOS_LIB) library $(HW_CPU_LIB) library $(WINDOWS_NTVDMLIB_LIB) library $(WINDOWS_W9XVMM_LIB)
-
-# EXT\FAAD----------------------------------------------------------------------------------
-# libfaad does not compile properly in 16-bit real mode
-!ifeq TARGET_MSDOS 16
-EXT_FAAD_LIB_NO_LIB = 1
-EXT_FAAD_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_FAAD_LIB_NO_LIB
-EXT_FAAD_LIB_DIR=$(REL)$(HPS)ext$(HPS)faad
-EXT_FAAD_LIB=$(EXT_FAAD_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)faad.lib
-EXT_FAAD_LIB_DEPENDENCIES=
-EXT_FAAD_LIB_WLINK_LIBRARIES=library $(EXT_FAAD_LIB)
-!endif
-
-# EXT\LIBOGG--------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_LIBOGG_LIB_NO_LIB = 1
-EXT_LIBOGG_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_LIBOGG_LIB_NO_LIB
-EXT_LIBOGG_LIB_DIR=$(REL)$(HPS)ext$(HPS)libogg
-EXT_LIBOGG_LIB=$(EXT_LIBOGG_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)libogg.lib
-EXT_LIBOGG_LIB_DEPENDENCIES=
-EXT_LIBOGG_LIB_WLINK_LIBRARIES=library $(EXT_LIBOGG_LIB)
-!endif
-
-# EXT\FLAC----------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_FLAC_LIB_NO_LIB = 1
-EXT_FLAC_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_FLAC_LIB_NO_LIB
-EXT_FLAC_LIB_DIR=$(REL)$(HPS)ext$(HPS)flac
-EXT_FLAC_LIB=$(EXT_FLAC_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)flac.lib
-EXT_FLAC_LIB_DEPENDENCIES=
-EXT_FLAC_LIB_WLINK_LIBRARIES=library $(EXT_FLAC_LIB)
-!endif
-!ifndef EXT_FLAC_LIB_NO_EXE
-EXT_FLAC_EXE = $(SUBDIR)$(HPS)flac.exe
-!endif
-
-# EXT\JPEG----------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_JPEG_LIB_NO_LIB = 1
-EXT_JPEG_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_JPEG_LIB_NO_LIB
-EXT_JPEG_LIB_DIR=$(REL)$(HPS)ext$(HPS)jpeg
-EXT_JPEG_LIB=$(EXT_JPEG_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)jpeg.lib
-EXT_JPEG_LIB_DEPENDENCIES=
-EXT_JPEG_LIB_WLINK_LIBRARIES=library $(EXT_JPEG_LIB)
-!endif
-!ifndef EXT_JPEG_LIB_NO_EXE
-EXT_JPEG_CJPEG_EXE = $(SUBDIR)$(HPS)cjpeg.exe
-EXT_JPEG_DJPEG_EXE = $(SUBDIR)$(HPS)djpeg.exe
-!endif
-
-# EXT\LAME----------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_LAME_LIB_NO_LIB = 1
-EXT_LAME_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_LAME_LIB_NO_LIB
-EXT_LAME_LIB_DIR=$(REL)$(HPS)ext$(HPS)lame
-EXT_LAME_LIB=$(EXT_LAME_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)lame.lib
-EXT_LAME_LIB_DEPENDENCIES=
-EXT_LAME_LIB_WLINK_LIBRARIES=library $(EXT_LAME_LIB)
-!endif
-!ifndef EXT_LAME_LIB_NO_EXE
-EXT_LAME_LAME_EXE = $(SUBDIR)$(HPS)lame.exe
-!endif
-
-# EXT\LIBMAD--------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_LIBMAD_LIB_NO_LIB = 1
-EXT_LIBMAD_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_LIBMAD_LIB_NO_LIB
-EXT_LIBMAD_LIB_DIR=$(REL)$(HPS)ext$(HPS)libmad
-EXT_LIBMAD_LIB=$(EXT_LIBMAD_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)libmad.lib
-EXT_LIBMAD_LIB_DEPENDENCIES=
-EXT_LIBMAD_LIB_WLINK_LIBRARIES=library $(EXT_LIBMAD_LIB)
-!endif
-
-# EXT\SPEEX---------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_SPEEX_LIB_NO_LIB = 1
-EXT_SPEEX_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_SPEEX_LIB_NO_LIB
-EXT_SPEEX_LIB_DIR=$(REL)$(HPS)ext$(HPS)speex
-EXT_SPEEX_LIB=$(EXT_SPEEX_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)speex.lib
-EXT_SPEEX_LIB_DEPENDENCIES=
-EXT_SPEEX_LIB_WLINK_LIBRARIES=library $(EXT_SPEEX_LIB)
-!endif
-!ifndef EXT_SPEEX_LIB_NO_EXE
-EXT_SPEEX_SPEEXDEC_EXE = $(SUBDIR)$(HPS)speexdec.exe
-EXT_SPEEX_SPEEXENC_EXE = $(SUBDIR)$(HPS)speexenc.exe
-!endif
-
-# EXT\VORBIS--------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_VORBIS_LIB_NO_LIB = 1
-EXT_VORBIS_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_VORBIS_LIB_NO_LIB
-EXT_VORBIS_LIB_DIR=$(REL)$(HPS)ext$(HPS)vorbis
-EXT_VORBIS_LIB=$(EXT_VORBIS_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)vorbis.lib
-EXT_VORBIS_LIB_DEPENDENCIES=
-EXT_VORBIS_LIB_WLINK_LIBRARIES=library $(EXT_VORBIS_LIB)
-!endif
-
-# EXT\ZLIB----------------------------------------------------------------------------------
-!ifndef EXT_ZLIB_LIB_NO_LIB
-EXT_ZLIB_LIB_DIR=$(REL)$(HPS)ext$(HPS)zlib
-EXT_ZLIB_LIB=$(EXT_ZLIB_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)zlib.lib
-EXT_ZLIB_LIB_DEPENDENCIES=
-EXT_ZLIB_LIB_WLINK_LIBRARIES=library $(EXT_ZLIB_LIB)
-!endif
-!ifndef EXT_ZLIB_LIB_NO_EXE
-EXT_ZLIB_MINIGZIP_EXE = $(SUBDIR)$(HPS)minigzip.exe
-EXT_ZLIB_EXAMPLE_EXE = $(SUBDIR)$(HPS)example.exe
-!endif
-
-# EXT\BZIP2---------------------------------------------------------------------------------
-!ifeq TARGET_MSDOS 16
-EXT_BZIP2_LIB_NO_LIB = 1
-EXT_BZIP2_LIB_NO_EXE = 1
-!endif
-!ifndef EXT_BZIP2_LIB_NO_LIB
-EXT_BZIP2_LIB_DIR=$(REL)$(HPS)ext$(HPS)bzip2
-EXT_BZIP2_LIB=$(EXT_BZIP2_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)bzip2.lib
-EXT_BZIP2_LIB_DEPENDENCIES=
-EXT_BZIP2_LIB_WLINK_LIBRARIES=library $(EXT_BZIP2_LIB)
-!endif
-!ifndef EXT_BZIP2_LIB_NO_EXE
-EXT_BZIP2_LIB_BZIP2_EXE = $(SUBDIR)$(HPS)bzip2.exe
-EXT_BZIP2_LIB_BZIP2REC_EXE = $(SUBDIR)$(HPS)bzip2rec.exe
-!endif
-
-# WINDOWS\WIN16EB--------------------------------------------------------------------------
-WINDOWS_WIN16EB_LIB_DIR=$(REL)$(HPS)windows$(HPS)win16eb
-WINDOWS_WIN16EB_LIB=$(WINDOWS_WIN16EB_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)win16eb.lib
-WINDOWS_WIN16EB_LIB_DEPENDENCIES=$(HW_DOS_LIB) $(HW_CPU_LIB)
-WINDOWS_WIN16EB_LIB_WLINK_LIBRARIES=library $(WINDOWS_WIN16EB_LIB) $(HW_CPU_LIB_WLINK_LIBRARIES) $(HW_DOS_LIB_WLINK_LIBRARIES)
-
-# WINDOWS\DISPDIB--------------------------------------------------------------------------
-WINDOWS_DISPDIB_LIB_DIR=$(REL)$(HPS)windows$(HPS)dispdib
-WINDOWS_DISPDIB_LIB=$(WINDOWS_DISPDIB_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)dispdib.lib
-WINDOWS_DISPDIB_LIB_DEPENDENCIES=$(WINDOWS_WIN16EB_LIB) $(WINDOWS_WIN16EB_LIB_DEPENDENCIES)
-WINDOWS_DISPDIB_LIB_WLINK_LIBRARIES=library $(WINDOWS_DISPDIB_LIB) $(WINDOWS_WIN16EB_LIB_WLINK_LIBRARIES)
-
-# HW\USB\OHCI------------------------------------------------------------------------------
-HW_USB_OHCI_LIB_DIR=$(REL)$(HPS)hw$(HPS)usb$(HPS)ohci
-HW_USB_OHCI_LIB=$(HW_USB_OHCI_LIB_DIR)$(HPS)$(SUBDIR)$(HPS)ohci.lib
-HW_USB_OHCI_LIB_DEPENDENCIES=
-HW_USB_OHCI_LIB_WLINK_LIBRARIES=library $(HW_USB_OHCI_LIB)
-
+++ /dev/null
-@echo off\r
-\r
-set WHAT=make\r
-if "%1" == "clean" set WHAT=clean\r
-\r
-echo All done\r
+++ /dev/null
-@echo off\r
-if exist *.map del *.map\r
-if exist *.obj del *.obj\r
-if exist *.sym del *.sym\r
-if exist *.exe del *.exe\r
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 2
-CPULEV2 = 2
-TARGET86 = 286
-!include "$(REL)$(HPS)mak$(HPS)comdos86.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 3
-!endif
-!ifndef CPULEV2
-CPULEV2 = 3
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 386
-!endif
-
-# Watcom does not have -fp4 because there's really nothing new to the 486 FPU to code home about
-!ifndef CPULEV3F
-CPULEV3F=$(CPULEV3)
-!ifeq CPULEV3F 4
-CPULEV3F=3
-!endif
-!endif
-
-!ifndef CPULEV4F
-CPULEV4F=$(CPULEV4)
-!ifeq CPULEV4F 4
-CPULEV4F=3
-!endif
-!endif
-
-TARGET_MSDOS = 32
-SUBDIR = dos$(TARGET86)$(MMODE)$(DSUFFIX)
-CC = wcc386
-LINKER = wcl386
-LDFLAGS = # -ldos32a
-WLINK_SYSTEM = dos4g
-WLINK_CON_SYSTEM = dos4g
-CFLAGS = -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-CFLAGS386= -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586= -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686= -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-AFLAGS = -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-NASMFLAGS= -DTARGET_MSDOS=32 -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-# NTS: MS-DOS is console based, no difference
-CFLAGS_CON = $(CFLAGS)
-CFLAGS386_CON = $(CFLAGS386)
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = $(CFLAGS386_TO_586)
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = $(CFLAGS386_TO_686)
-AFLAGS_CON = $(AFLAGS)
-NASMFLAGS_CON = $(NASMFLAGS)
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 4
-CPULEV2 = 4
-CPULEV3 = 4
-CPULEV4 = 4
-TARGET86 = 486
-!include "$(REL)$(HPS)mak$(HPS)comdo386.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 5
-CPULEV2 = 5
-CPULEV3 = 5
-CPULEV4 = 5
-CPULEV5 = 5
-TARGET86 = 586
-!include "$(REL)$(HPS)mak$(HPS)comdo386.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 6
-CPULEV2 = 6
-CPULEV3 = 6
-CPULEV4 = 6
-CPULEV5 = 6
-CPULEV6 = 6
-TARGET86 = 686
-!include "$(REL)$(HPS)mak$(HPS)comdo386.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 0
-!endif
-!ifndef CPULEV2
-CPULEV2 = 2
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 86
-!endif
-
-# large and compact model builds must not assume DS != SS.
-# some interrupt handlers call subroutines in this code. if not notified that DS != SS
-# the subroutines will mis-address parameters and screw things up.
-!ifeq MMODE l
-ZU_FLAG=-zu
-!endif
-!ifeq MMODE c
-ZU_FLAG=-zu
-!endif
-
-TARGET_MSDOS = 16
-SUBDIR = dos$(TARGET86)$(MMODE)$(DSUFFIX)
-CC = wcc
-LINKER = wcl
-WLINK_SYSTEM = dos
-WLINK_CON_SYSTEM = dos
-CFLAGS = -e=2 $(ZU_FLAG) -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-CFLAGS386= -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-CFLAGS386_TO_586= -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-CFLAGS386_TO_686= -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-AFLAGS = -e=2 -zq -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=dos -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q
-NASMFLAGS= -DTARGET_MSDOS=16 -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-# NTS: MS-DOS is console based, no difference
-CFLAGS_CON = $(CFLAGS)
-CFLAGS386_CON = $(CFLAGS386)
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = $(CFLAGS386_TO_586)
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = $(CFLAGS386_TO_686)
-AFLAGS_CON = $(AFLAGS)
-NASMFLAGS_CON = $(NASMFLAGS)
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 0
-!endif
-!ifndef CPULEV2
-CPULEV2 = 2
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 86
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# Include the 1.x headers. I looked at their os2 headers and they seem optimized for 32-bit
-OS2_INCLUDE=-i="$(%WATCOM)/h/os21x"
-
-# NOTE TO SELF: If you compile using naive flags, your code will work under Windows 3.1, but will crash horribly under Windows 3.0.
-# Wanna know why? Because apparently Windows 3.0 doesn't maintain SS == DS, which Watcom assumes. So you always need
-# to specify the -zu and -zw switches. Even for Windows 3.1.
-
-TARGET_MSDOS = 16
-TARGET_OS2 = 10
-SUBDIR = os2w$(TARGET86_1DIGIT)$(MMODE)$(DSUFFIX)
-RC = wrc
-CC = wcc
-LINKER = wcl
-WLINK_SYSTEM = os2_pm
-WLINK_CON_SYSTEM = os2
-WLINK_DLL_SYSTEM = os2_dll
-
-# GUI versions
-RCFLAGS = -q -r -31 -bt=os2_pm $(OS2_INCLUDE)
-CFLAGS = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2_pm -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-CFLAGS386= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2_pm -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-CFLAGS386_TO_586= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2_pm -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-CFLAGS386_TO_686= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2_pm -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-AFLAGS = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2_pm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-NASMFLAGS= -DTARGET_MSDOS=16 -DTARGET_OS2=$(TARGET_OS2) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-WLINK_FLAGS = op start=_cstart_
-
-# console versions
-RCFLAGS_CON = -q -r -31 -bt=os2 $(OS2_INCLUDE)
-CFLAGS_CON = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-CFLAGS386_CON= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-CFLAGS386_TO_586_CON= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-CFLAGS386_TO_686_CON= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-AFLAGS_CON = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bg
-NASMFLAGS_CON= -DTARGET_MSDOS=16 -DTARGET_OS2=$(TARGET_OS2) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-WLINK_CON_FLAGS = op start=_cstart_
-
-RCFLAGS_DLL = -q -r -31 -bt=os2_dll $(OS2_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bd
-CFLAGS386_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bd
-CFLAGS386_TO_586_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bd
-CFLAGS386_TO_686_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bd
-AFLAGS_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2 -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_16_ -bd
-NASMFLAGS_DLL = -DTARGET_MSDOS=16 -DTARGET_OS2=$(TARGET_OS2) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 3
-!endif
-!ifndef CPULEV2
-CPULEV2 = 3
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 86
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# Include the 2.x headers
-OS2_INCLUDE=-i="$(%WATCOM)/h/os2"
-
-TARGET_MSDOS = 32
-TARGET_OS2 = 20
-SUBDIR = os2d$(TARGET86_1DIGIT)$(MMODE)$(DSUFFIX)
-RC = wrc
-CC = wcc386
-LINKER = wcl386
-WLINK_SYSTEM = os2v2_pm
-WLINK_CON_SYSTEM = os2v2
-WLINK_DLL_SYSTEM = os2v2_dll
-
-# GUI versions
-RCFLAGS = -q -r -31 -bt=os2v2_pm $(OS2_INCLUDE)
-CFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2_pm -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-CFLAGS386= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2_pm -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-CFLAGS386_TO_586= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2_pm -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-CFLAGS386_TO_686= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2_pm -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-AFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2_pm -wx -$(CPULEV0) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-NASMFLAGS= -DTARGET_MSDOS=32 -DTARGET_OS2=$(TARGET_OS2) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-WLINK_FLAGS = op start=_cstart_
-
-# console versions
-RCFLAGS_CON = -q -r -31 -bt=os2v2 $(OS2_INCLUDE)
-CFLAGS_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-CFLAGS386_CON= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-CFLAGS386_TO_586_CON= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-CFLAGS386_TO_686_CON= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-AFLAGS_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -wx -$(CPULEV0) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bg
-NASMFLAGS_CON= -DTARGET_MSDOS=32 -DTARGET_OS2=$(TARGET_OS2) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-WLINK_CON_FLAGS = op start=_cstart_
-
-RCFLAGS_DLL = -q -r -31 -bt=os2v2_dll $(OS2_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bd
-CFLAGS386_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bd
-CFLAGS386_TO_586_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bd
-CFLAGS386_TO_686_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bd
-AFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=os2v2 -wx -$(CPULEV0) -dTARGET_MSDOS=32 -dTARGET_OS2=$(TARGET_OS2) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(OS2_INCLUDE) -D_OS2_32_ -bd
-NASMFLAGS_DLL = -DTARGET_MSDOS=32 -DTARGET_OS2=$(TARGET_OS2) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 0
-!endif
-!ifndef CPULEV2
-CPULEV2 = 2
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 86
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# why is this even necessary? why does dumbshit Watcom insist on including the WINNT headers for Windows 3.1 builds?
-WIN_INCLUDE=-i="$(%WATCOM)/h/win"
-
-# NOTE TO SELF: If you compile using naive flags, your code will work under Windows 3.1, but will crash horribly under Windows 3.0.
-# Wanna know why? Because apparently Windows 3.0 doesn't maintain SS == DS, which Watcom assumes. So you always need
-# to specify the -zu and -zw switches. Even for Windows 3.1
-
-TARGET_MSDOS = 16
-TARGET_WINDOWS = 30
-SUBDIR = win30$(TARGET86_1DIGIT)$(MMODE)$(DSUFFIX)
-RC = wrc
-CC = wcc
-LINKER = wcl
-WLINK_SYSTEM = windows
-WLINK_CON_SYSTEM = windows
-WLINK_DLL_SYSTEM = windows_dll
-RCFLAGS = -q -r -30 -bt=windows $(WIN_INCLUDE)
-CFLAGS = -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-CFLAGS386= -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-CFLAGS386_TO_586= -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-CFLAGS386_TO_686= -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-AFLAGS = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-NASMFLAGS= -DTARGET_MSDOS=16 -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-# NTS: Win16 apps do not have a console mode
-RCFLAGS_CON = $(RCFLAGS)
-CFLAGS_CON = $(CFLAGS)
-CFLAGS386_CON = $(CFLAGS386)
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = $(CFLAGS386_TO_586)
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = $(CFLAGS386_TO_686)
-AFLAGS_CON = $(AFLAGS)
-NASMFLAGS_CON = $(NASMFLAGS)
-
-RCFLAGS_DLL = -q -r -30 -bt=windows $(WIN_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-CFLAGS386_DLL = -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-CFLAGS386_TO_586_DLL = -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-CFLAGS386_TO_686_DLL = -e=2 -zq -zu -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-AFLAGS_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-NASMFLAGS_DLL = -DTARGET_MSDOS=16 -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-# macro to patch the EXE to the proper version
-WIN_NE_SETVER_BUILD = ../../tool/chgnever.pl 3.0
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 0
-!endif
-!ifndef CPULEV2
-CPULEV2 = 2
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 86
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# why is this even necessary? why does dumbshit Watcom insist on including the WINNT headers for Windows 3.1 builds?
-WIN_INCLUDE=-i="$(%WATCOM)/h/win"
-
-# NOTE TO SELF: If you compile using naive flags, your code will work under Windows 3.1, but will crash horribly under Windows 3.0.
-# Wanna know why? Because apparently Windows 3.0 doesn't maintain SS == DS, which Watcom assumes. So you always need
-# to specify the -zu and -zw switches. Even for Windows 3.1.
-
-TARGET_MSDOS = 16
-TARGET_WINDOWS = 31
-SUBDIR = win31$(TARGET86_1DIGIT)$(MMODE)$(DSUFFIX)
-RC = wrc
-CC = wcc
-LINKER = wcl
-WLINK_SYSTEM = windows
-WLINK_CON_SYSTEM = windows
-WLINK_DLL_SYSTEM = windows_dll
-RCFLAGS = -q -r -31 -bt=windows $(WIN_INCLUDE)
-CFLAGS = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-CFLAGS386= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-CFLAGS386_TO_586= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-CFLAGS386_TO_686= -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-AFLAGS = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bg
-NASMFLAGS= -DTARGET_MSDOS=16 -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-# NTS: Win16 apps do not have a console mode
-RCFLAGS_CON = $(RCFLAGS)
-CFLAGS_CON = $(CFLAGS)
-CFLAGS386_CON = $(CFLAGS386)
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = $(CFLAGS386_TO_586)
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = $(CFLAGS386_TO_686)
-AFLAGS_CON = $(AFLAGS)
-NASMFLAGS_CON = $(NASMFLAGS)
-
-RCFLAGS_DLL = -q -r -31 -bt=windows_dll $(WIN_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-CFLAGS386_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -$(CPULEV3) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-CFLAGS386_TO_586_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-CFLAGS386_TO_686_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-AFLAGS_DLL = -e=2 -zq -zw -zu -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -$(CPULEV0) -dTARGET_MSDOS=16 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -D_WINDOWS_16_ -bd
-NASMFLAGS_DLL = -DTARGET_MSDOS=16 -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMSDOS=1 -DTARGET86=$(TARGET86) -DMMODE=$(MMODE)
-
-# macro to patch the EXE to the proper version
-WIN_NE_SETVER_BUILD = ../../tool/chgnever.pl 3.1
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 0
-TARGET86 = 86
-!include "$(REL)$(HPS)mak$(HPS)comw3086.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 2
-CPULEV2 = 2
-TARGET86 = 286
-!include "$(REL)$(HPS)mak$(HPS)comw3086.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 3
-CPULEV2 = 3
-CPULEV3 = 3
-TARGET86 = 386
-!include "$(REL)$(HPS)mak$(HPS)comw3086.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 2
-CPULEV2 = 2
-TARGET86 = 286
-!include "$(REL)$(HPS)mak$(HPS)comw3186.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-CPULEV0 = 3
-CPULEV2 = 3
-CPULEV3 = 3
-TARGET86 = 386
-!include "$(REL)$(HPS)mak$(HPS)comw3186.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 3
-!endif
-!ifndef CPULEV2
-CPULEV2 = 3
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 386
-!endif
-
-# Watcom does not have -fp4 because there's really nothing new to the 486 FPU to code home about
-!ifndef CPULEV3F
-CPULEV3F=$(CPULEV3)
-!ifeq CPULEV3F 4
-CPULEV3F=3
-!endif
-!endif
-
-!ifndef CPULEV4F
-CPULEV4F=$(CPULEV4)
-!ifeq CPULEV4F 4
-CPULEV4F=3
-!endif
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# why is this even necessary? why does dumbshit Watcom insist on including the WINNT headers for Windows 3.1 builds?
-WIN_INCLUDE=-i="$(%WATCOM)/h/win"
-
-TARGET_MSDOS = 32
-TARGET_WINDOWS = 31
-WIN386 = 1
-SUBDIR = win38631
-CC = wcc386
-RC = wrc
-LINKER = wcl386
-LDFLAGS = # -ldos32a
-WLINK_SYSTEM = win386
-WLINK_CON_SYSTEM = win386
-WLINK_DLL_SYSTEM = win386
-RCFLAGS = -q -r -31 -bt=windows $(WIN_INCLUDE)
-CFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-CFLAGS386= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-AFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dMSDOS=1 -dWIN386=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-NASMFLAGS= -DTARGET_MSDOS=32 -DMSDOS=1 -DWIN386=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE) -dWIN386=1
-
-# NTS: Win16 apps do not have a console mode
-RCFLAGS_CON = $(RCFLAGS)
-CFLAGS_CON = $(CFLAGS)
-CFLAGS386_CON = $(CFLAGS386)
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = $(CFLAGS386_TO_586)
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = $(CFLAGS386_TO_686)
-AFLAGS_CON = $(AFLAGS)
-NASMFLAGS_CON = $(NASMFLAGS)
-
-RCFLAGS_DLL = -q -r -31 -bt=windows $(WIN_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-CFLAGS386_DLL= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_DLL= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_DLL= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-AFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dMSDOS=1 -dWIN386=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-NASMFLAGS_DLL = -DTARGET_MSDOS=32 -DMSDOS=1 -DWIN386=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE) -dWIN386=1
-
-# macro to patch the EXE to the proper version
-WIN_NE_SETVER_BUILD = ../../tool/chgnever.pl 3.1
-
-# needed to rename ,exe back to .rex if the "EXE" was actually a .rex file
-WIN386_EXE_TO_REX_IF_REX = ../../tool/win386-exe-to-rex-if-rex.pl
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 3
-!endif
-!ifndef CPULEV2
-CPULEV2 = 3
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 386
-!endif
-
-# Watcom does not have -fp4 because there's really nothing new to the 486 FPU to code home about
-!ifndef CPULEV3F
-CPULEV3F=$(CPULEV3)
-!ifeq CPULEV3F 4
-CPULEV3F=3
-!endif
-!endif
-
-!ifndef CPULEV4F
-CPULEV4F=$(CPULEV4)
-!ifeq CPULEV4F 4
-CPULEV4F=3
-!endif
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# why is this even necessary? why does dumbshit Watcom insist on including the WINNT headers for Windows 3.1 builds?
-WIN_INCLUDE=-i="$(%WATCOM)/h/nt"
-
-TARGET_MSDOS = 32
-TARGET_WINDOWS = 40
-SUBDIR = win32
-CC = wcc386
-RC = wrc
-LINKER = wcl386
-LDFLAGS = # -ldos32a
-WLINK_SYSTEM = nt_win
-WLINK_DLL_SYSTEM = nt_dll
-WLINK_CON_SYSTEM = nt
-
-RCFLAGS = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-CFLAGS386= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-AFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-NASMFLAGS= -DTARGET_MSDOS=32 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-RCFLAGS_CON = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-CFLAGS386_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-AFLAGS_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-NASMFLAGS_CON = -DTARGET_MSDOS=32 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-RCFLAGS_DLL = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-CFLAGS386_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-AFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-NASMFLAGS_DLL = -DTARGET_MSDOS=32 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 3
-!endif
-!ifndef CPULEV2
-CPULEV2 = 3
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 386
-!endif
-
-# Watcom does not have -fp4 because there's really nothing new to the 486 FPU to code home about
-!ifndef CPULEV3F
-CPULEV3F=$(CPULEV3)
-!ifeq CPULEV3F 4
-CPULEV3F=3
-!endif
-!endif
-
-!ifndef CPULEV4F
-CPULEV4F=$(CPULEV4)
-!ifeq CPULEV4F 4
-CPULEV4F=3
-!endif
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# why is this even necessary? why does dumbshit Watcom insist on including the WINNT headers for Windows 3.1 builds?
-WIN_INCLUDE=-i="$(%WATCOM)/h/nt"
-
-TARGET_MSDOS = 32
-TARGET_WINDOWS = 31
-SUBDIR = win32s$(TARGET86_1DIGIT)$(DSUFFIX)
-CC = wcc386
-RC = wrc
-LINKER = wcl386
-LDFLAGS = # -ldos32a
-WLINK_SYSTEM = win32s
-WLINK_CON_SYSTEM = win32s
-WLINK_DLL_SYSTEM = win32s
-RCFLAGS = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-CFLAGS386= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-AFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE)
-NASMFLAGS= -DTARGET_MSDOS=32 -DMSDOS=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-# NTS: In the Windows 3.1 Win32s world there is no such thing as a console application
-RCFLAGS_CON = $(RCFLAGS)
-CFLAGS_CON = $(CFLAGS)
-CFLAGS386_CON = $(CFLAGS386)
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = $(CFLAGS386_TO_586)
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = $(CFLAGS386_TO_686)
-AFLAGS_CON = $(AFLAGS)
-NASMFLAGS_CON = $(NASMFLAGS)
-
-RCFLAGS_DLL = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-CFLAGS386_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-AFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dMSDOS=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-NASMFLAGS_DLL = -DTARGET_MSDOS=32 -DMSDOS=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 3
-!endif
-!ifndef CPULEV2
-CPULEV2 = 3
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 386
-!endif
-
-# Watcom does not have -fp4 because there's really nothing new to the 486 FPU to code home about
-!ifndef CPULEV3F
-CPULEV3F=$(CPULEV3)
-!ifeq CPULEV3F 4
-CPULEV3F=3
-!endif
-!endif
-
-!ifndef CPULEV4F
-CPULEV4F=$(CPULEV4)
-!ifeq CPULEV4F 4
-CPULEV4F=3
-!endif
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# why is this even necessary? why does dumbshit Watcom insist on including the WINNT headers for Windows 3.1 builds?
-WIN_INCLUDE=-i="$(%WATCOM)/h/win"
-
-TARGET_MSDOS = 32
-TARGET_WINDOWS = 30
-WIN386 = 1
-SUBDIR = win386
-CC = wcc386
-RC = wrc
-LINKER = wcl386
-LDFLAGS = # -ldos32a
-WLINK_SYSTEM = win386
-WLINK_CON_SYSTEM = win386
-WLINK_DLL_SYSTEM = win386
-RCFLAGS = -q -r -30 -bt=windows $(WIN_INCLUDE)
-CFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-CFLAGS386= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-AFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dMSDOS=1 -dWIN386=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-NASMFLAGS= -DTARGET_MSDOS=32 -DMSDOS=1 -DWIN386=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE) -dWIN386=1
-
-# NTS: Win16 apps do not have a console mode
-RCFLAGS_CON = $(RCFLAGS)
-CFLAGS_CON = $(CFLAGS)
-CFLAGS386_CON = $(CFLAGS386)
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = $(CFLAGS386_TO_586)
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = $(CFLAGS386_TO_686)
-AFLAGS_CON = $(AFLAGS)
-NASMFLAGS_CON = $(NASMFLAGS)
-
-RCFLAGS_DLL = -q -r -30 -bt=windows $(WIN_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-CFLAGS386_DLL= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_DLL= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_DLL= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -bt=windows -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dMSDOS=1 -dWIN386=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-AFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -bt=windows -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dMSDOS=1 -dWIN386=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -dWIN386=1
-NASMFLAGS_DLL = -DTARGET_MSDOS=32 -DMSDOS=1 -DWIN386=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE) -dWIN386=1
-
-# macro to patch the EXE to the proper version
-WIN_NE_SETVER_BUILD = ../../tool/chgnever.pl 3.0
-
-# needed to rename ,exe back to .rex if the "EXE" was actually a .rex file
-WIN386_EXE_TO_REX_IF_REX = ../../tool/win386-exe-to-rex-if-rex.pl
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-# do not run directly, use make.sh
-
-CFLAGS_1 =
-!ifndef DEBUG
-DEBUG = -d0
-DSUFFIX =
-!else
-DSUFFIX = d
-!endif
-
-!ifndef CPULEV0
-CPULEV0 = 3
-!endif
-!ifndef CPULEV2
-CPULEV2 = 3
-!endif
-!ifndef CPULEV3
-CPULEV3 = 3
-!endif
-!ifndef CPULEV4
-CPULEV4 = 4
-!endif
-!ifndef CPULEV5
-CPULEV5 = 5
-!endif
-!ifndef CPULEV6
-CPULEV6 = 6
-!endif
-!ifndef TARGET86
-TARGET86 = 386
-!endif
-
-# Watcom does not have -fp4 because there's really nothing new to the 486 FPU to code home about
-!ifndef CPULEV3F
-CPULEV3F=$(CPULEV3)
-!ifeq CPULEV3F 4
-CPULEV3F=3
-!endif
-!endif
-
-!ifndef CPULEV4F
-CPULEV4F=$(CPULEV4)
-!ifeq CPULEV4F 4
-CPULEV4F=3
-!endif
-!endif
-
-!ifeq TARGET86 86
-TARGET86_1DIGIT=0
-!endif
-!ifeq TARGET86 186
-TARGET86_1DIGIT=1
-!endif
-!ifeq TARGET86 286
-TARGET86_1DIGIT=2
-!endif
-!ifeq TARGET86 386
-TARGET86_1DIGIT=3
-!endif
-!ifeq TARGET86 486
-TARGET86_1DIGIT=4
-!endif
-!ifeq TARGET86 586
-TARGET86_1DIGIT=5
-!endif
-!ifeq TARGET86 686
-TARGET86_1DIGIT=6
-!endif
-
-# why is this even necessary? why does dumbshit Watcom insist on including the WINNT headers for Windows 3.1 builds?
-WIN_INCLUDE=-i="$(%WATCOM)/h/nt"
-
-TARGET_MSDOS = 32
-TARGET_WINDOWS = 40
-SUBDIR = winnt
-CC = wcc386
-RC = wrc
-LINKER = wcl386
-LDFLAGS = # -ldos32a
-WLINK_SYSTEM = nt_win
-WLINK_DLL_SYSTEM = nt_dll
-WLINK_CON_SYSTEM = nt
-
-RCFLAGS = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-CFLAGS386= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686= -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-AFLAGS = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dWINNT=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bg
-NASMFLAGS= -DTARGET_MSDOS=32 -DWINNT=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-RCFLAGS_CON = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-CFLAGS386_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-AFLAGS_CON = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dWINNT=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bc
-NASMFLAGS_CON = -DTARGET_MSDOS=32 -DWINNT=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-RCFLAGS_DLL = -q -r -bt=nt $(WIN_INCLUDE)
-CFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-CFLAGS386_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV3F) -$(CPULEV3)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-# a 586 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_586_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV5) -$(CPULEV5)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-# a 686 version of the build flags, so some OBJ files can target Pentium or higher instructions
-CFLAGS386_TO_686_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -oilrtfm -wx -fp$(CPULEV6) -$(CPULEV6)r -dTARGET_MSDOS=32 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dWINNT=1 -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-AFLAGS_DLL = -e=2 -zq -zw -m$(MMODE) $(DEBUG) $(CFLAGS_1) -wx -fp$(CPULEV3F) -$(CPULEV3) -dTARGET_MSDOS=32 -dWINNT=1 -dTARGET_WINDOWS=$(TARGET_WINDOWS) -dTARGET86=$(TARGET86) -DMMODE=$(MMODE) -q $(WIN_INCLUDE) -bd
-NASMFLAGS_DLL = -DTARGET_MSDOS=32 -DWINNT=1 -DTARGET86=$(TARGET86) -DTARGET_WINDOWS=$(TARGET_WINDOWS) -DMMODE=$(MMODE)
-
-!include "$(REL)$(HPS)mak$(HPS)bcommon.mak"
-!include "common.mak"
-!include "$(REL)$(HPS)mak$(HPS)dcommon.mak"
-
+++ /dev/null
-
-# HW\VGA------------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_VGA_LIB
-$(HW_VGA_LIB):
- @cd $(HW_VGA_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-
-$(HW_VGATTY_LIB):
- @cd $(HW_VGATTY_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-
-$(HW_VGAGUI_LIB):
- @cd $(HW_VGAGUI_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\CPU------------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_CPU_LIB
-$(HW_CPU_LIB):
- @cd $(HW_CPU_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\DOS------------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_DOS_LIB
-$(HW_DOS_LIB):
- @cd $(HW_DOS_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\SNDSB----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_SNDSB_LIB
-$(HW_SNDSB_LIB):
- @cd $(HW_SNDSB_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\LLMEM----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_LLMEM_LIB
-$(HW_LLMEM_LIB):
- @cd $(HW_LLMEM_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\8042-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_8042_LIB
-$(HW_8042_LIB):
- @cd $(HW_8042_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\8237-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_8237_LIB
-$(HW_8237_LIB):
- @cd $(HW_8237_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\8250-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_8250_LIB
-$(HW_8250_LIB):
- @cd $(HW_8250_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\8254-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_8254_LIB
-$(HW_8254_LIB):
- @cd $(HW_8254_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\8259-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_8259_LIB
-$(HW_8259_LIB):
- @cd $(HW_8259_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\ACPI-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_ACPI_LIB
-$(HW_ACPI_LIB):
- @cd $(HW_ACPI_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\PCI------------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_PCI_LIB
-$(HW_PCI_LIB):
- @cd $(HW_PCI_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\PCIE-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_PCIE_LIB
-$(HW_PCIE_LIB):
- @cd $(HW_PCIE_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\MB\INTEL\PIIX3-------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_MB_INTEL_PIIX3_LIB
-$(HW_MB_INTEL_PIIX3_LIB):
- @cd $(HW_MB_INTEL_PIIX3_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\ADLIB----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_ADLIB_LIB
-$(HW_ADLIB_LIB):
- @cd $(HW_ADLIB_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\IDE==----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_IDE_LIB
-$(HW_IDE_LIB):
- @cd $(HW_IDE_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\FLOPPY---------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_FLOPPY_LIB
-$(HW_FLOPPY_LIB):
- @cd $(HW_FLOPPY_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\ISAPNP---------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_ISAPNP_LIB
-$(HW_ISAPNP_LIB):
- @cd $(HW_ISAPNP_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\ULTRASND-------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_ULTRASND_LIB
-$(HW_ULTRASND_LIB):
- @cd $(HW_ULTRASND_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\BIOSDISK-------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_BIOSDISK_LIB
-$(HW_BIOSDISK_LIB):
- @cd $(HW_BIOSDISK_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\FLATREAL-------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_FLATREAL_LIB
-$(HW_FLATREAL_LIB):
- @cd $(HW_FLATREAL_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# WINDOWS\NTVDM-----------------------------------------------------------------------------
-!ifneq NOW_BUILDING WINDOWS_NTVDM
-! ifdef WINDOWS_NTVDMLIB_LIB
-$(WINDOWS_NTVDMLIB_LIB):
- @cd $(WINDOWS_NTVDMLIB_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# HW\VESA-----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_VESA_LIB
-$(HW_VESA_LIB):
- @cd $(HW_VESA_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# WINDOWS\W9XVMM----------------------------------------------------------------------------
-!ifneq NOW_BUILDING WINDOWS_W9XVMM
-$(WINDOWS_W9XVMM_LIB):
- @cd $(WINDOWS_W9XVMM_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# EXT\FAAD----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_FAAD_LIB
-! ifdef EXT_FAAD_LIB
-$(EXT_FAAD_LIB):
- @cd $(EXT_FAAD_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\LIBOGG--------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_LIBOGG_LIB
-! ifdef EXT_LIBOGG_LIB
-$(EXT_LIBOGG_LIB):
- @cd $(EXT_LIBOGG_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\FLAC----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_FLAC_LIB
-! ifdef EXT_FLAC_LIB
-$(EXT_FLAC_LIB):
- @cd $(EXT_FLAC_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-! ifdef EXT_FLAC_EXE
-$(EXT_FLAC_EXE):
- @cd $(EXT_FLAC_EXE_DIR)
- @$(MAKECMD) build exe
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\FLAC----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_JPEG_LIB
-! ifdef EXT_JPEG_LIB
-$(EXT_JPEG_LIB):
- @cd $(EXT_JPEG_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\LAME----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_LAME_LIB
-! ifdef EXT_LAME_LIB
-$(EXT_LAME_LIB):
- @cd $(EXT_LAME_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\LIBMAD--------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_LIBMAD_LIB
-! ifdef EXT_LIBMAD_LIB
-$(EXT_LIBMAD_LIB):
- @cd $(EXT_LIBMAD_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\SPEEX---------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_SPEEX_LIB
-! ifdef EXT_SPEEX_LIB
-$(EXT_SPEEX_LIB):
- @cd $(EXT_SPEEX_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\VORBIS--------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_VORBIS_LIB
-! ifdef EXT_VORBIS_LIB
-$(EXT_VORBIS_LIB):
- @cd $(EXT_VORBIS_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\ZLIB----------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_ZLIB_LIB
-! ifdef EXT_ZLIB_LIB
-$(EXT_ZLIB_LIB):
- @cd $(EXT_ZLIB_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# EXT\BZIP2---------------------------------------------------------------------------------
-!ifneq NOW_BUILDING EXT_BZIP2_LIB
-! ifdef EXT_BZIP2_LIB
-$(EXT_BZIP2_LIB):
- @cd $(EXT_BZIP2_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-! endif
-!endif
-
-# WINDOWS\WIN16EB---------------------------------------------------------------------------
-!ifneq NOW_BUILDING WINDOWS_WIN16EB_LIB
-$(WINDOWS_WIN16EB_LIB):
- @cd $(WINDOWS_WIN16EB_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# WINDOWS\DISPDIB---------------------------------------------------------------------------
-!ifneq NOW_BUILDING WINDOWS_DISPDIB_LIB
-$(WINDOWS_DISPDIB_LIB):
- @cd $(WINDOWS_DISPDIB_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# HW\USB\OHCI-------------------------------------------------------------------------------
-!ifneq NOW_BUILDING HW_USB_OHCI_LIB
-$(HW_USB_OHCI_LIB):
- @cd $(HW_USB_OHCI_LIB_DIR)
- @$(MAKECMD) build lib
- @cd $(HERE)
-!endif
-
-# DEBUG
-!ifndef NOW_BUILDING
-! error no NOW_BUILDING
-!endif
-
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=c\r
-!include "$(REL)$(HPS)mak$(HPS)comdo286.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=l\r
-!include "$(REL)$(HPS)mak$(HPS)comdo286.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=m\r
-!include "$(REL)$(HPS)mak$(HPS)comdo286.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=s\r
-!include "$(REL)$(HPS)mak$(HPS)comdo286.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)comdo386.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)comdo486.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)comdo586.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)comdo686.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=c\r
-!include "$(REL)$(HPS)mak$(HPS)comdos86.mak"\r
-\r
+++ /dev/null
-# To use, do "wmake -f <name>.mak"\r
-\r
-MMODE=l\r
-!include "$(REL)$(HPS)mak$(HPS)comdos86.mak"\r
-\r
+++ /dev/null
-# To use, do "wmake -f <name>.mak"\r
-\r
-MMODE=m\r
-!include "$(REL)$(HPS)mak$(HPS)comdos86.mak"\r
-\r
+++ /dev/null
-# To use, do "wmake -f <name>.mak"\r
-\r
-MMODE=s\r
-!include "$(REL)$(HPS)mak$(HPS)comdos86.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE = f\r
-CPULEV0 = 3\r
-CPULEV2 = 3\r
-CPULEV3 = 3\r
-TARGET86 = 386\r
-!include "$(REL)$(HPS)mak$(HPS)comos232.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE = l\r
-CPULEV0 = 2\r
-CPULEV2 = 2\r
-TARGET86 = 286\r
-!include "$(REL)$(HPS)mak$(HPS)comos216.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=c\r
-!include "$(REL)$(HPS)mak$(HPS)comwn300.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=l\r
-!include "$(REL)$(HPS)mak$(HPS)comwn300.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=m\r
-!include "$(REL)$(HPS)mak$(HPS)comwn300.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=s\r
-!include "$(REL)$(HPS)mak$(HPS)comwn300.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=c\r
-!include "$(REL)$(HPS)mak$(HPS)comwn302.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=l\r
-!include "$(REL)$(HPS)mak$(HPS)comwn302.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=m\r
-!include "$(REL)$(HPS)mak$(HPS)comwn302.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=s\r
-!include "$(REL)$(HPS)mak$(HPS)comwn302.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=c\r
-!include "$(REL)$(HPS)mak$(HPS)comwn303.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=l\r
-!include "$(REL)$(HPS)mak$(HPS)comwn303.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=m\r
-!include "$(REL)$(HPS)mak$(HPS)comwn303.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=s\r
-!include "$(REL)$(HPS)mak$(HPS)comwn303.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=c\r
-!include "$(REL)$(HPS)mak$(HPS)comwn312.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=l\r
-!include "$(REL)$(HPS)mak$(HPS)comwn312.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=m\r
-!include "$(REL)$(HPS)mak$(HPS)comwn312.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=s\r
-!include "$(REL)$(HPS)mak$(HPS)comwn312.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=c\r
-!include "$(REL)$(HPS)mak$(HPS)comwn313.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=l\r
-!include "$(REL)$(HPS)mak$(HPS)comwn313.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=m\r
-!include "$(REL)$(HPS)mak$(HPS)comwn313.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=s\r
-!include "$(REL)$(HPS)mak$(HPS)comwn313.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)cowin32.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)cowin32s.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-CPULEV0 = 4\r
-CPULEV2 = 4\r
-CPULEV3 = 4\r
-CPULEV4 = 4\r
-TARGET86 = 486\r
-!include "$(REL)$(HPS)mak$(HPS)cowin32s.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-CPULEV0 = 5\r
-CPULEV2 = 5\r
-CPULEV3 = 5\r
-CPULEV4 = 5\r
-CPULEV5 = 5\r
-TARGET86 = 586\r
-!include "$(REL)$(HPS)mak$(HPS)cowin32s.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-CPULEV0 = 6\r
-CPULEV2 = 6\r
-CPULEV3 = 6\r
-CPULEV4 = 6\r
-CPULEV5 = 6\r
-CPULEV6 = 6\r
-TARGET86 = 686\r
-!include "$(REL)$(HPS)mak$(HPS)cowin32s.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)cowin386.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)cow38631.mak"\r
-\r
+++ /dev/null
-# do not run directly, use make.sh\r
-\r
-MMODE=f\r
-!include "$(REL)$(HPS)mak$(HPS)cowinnt.mak"\r
-\r
#include "src/lib/midi.h"
static unsigned int midi_trk_count=0;
+struct midi_note midi_notes[ADLIB_FM_VOICES];
+struct midi_channel midi_ch[MIDI_MAX_CHANNELS];
+struct midi_track midi_trk[MIDI_MAX_TRACKS];
/* MIDI params. Nobody ever said it was a straightforward standard!
* NTS: These are for reading reference. Internally we convert everything to 100Hz time base. */
#include <conio.h>
#include <dos.h>
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/emm.h>
-#include <hw/dos/doswin.h>
+//#include "src/lib/doslib/cpu.h"
+#include "src/lib/doslib/dos.h"
+#include "src/lib/doslib/emm.h"
+//#include <hw/dos/doswin.h>
static const char *message = "Hello world. How are you?";
static const char *message2 = "Pingas. Sup dawg. Hello world. Dork. Hahahajajaja.";
static char tmp[128],tmp2[128];
+extern int probe_emm0();
#if 1
# define x_memcpy(a,b,c) memcpy(a,b,c)
probe_dos();
printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
+ /*if (detect_windows()) {
printf("I am running under Windows.\n");
printf(" Mode: %s\n",windows_mode_str(windows_mode));
printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
}
else {
printf("Not running under Windows or OS/2\n");
- }
+ }*/
sanity();
- if (probe_emm()) {
+ if (/*probe_emm0()*/1) {
int h1,h2,h3;
sanity();
#include <conio.h>
#include <dos.h>
-#include <hw/cpu/cpu.h>
-#include <hw/dos/dos.h>
-#include <hw/dos/doswin.h>
-#include <hw/dos/himemsys.h>
+//#include "src/lib/doslib/cpu.h"
+#include "src/lib/doslib/dos.h"
+//#include doswin.h>
+#include "src/lib/doslib/himemsys.h"
int main() {
probe_dos();
printf("DOS version %x.%02u\n",dos_version>>8,dos_version&0xFF);
- if (detect_windows()) {
+ /*if (detect_windows()) {
printf("I am running under Windows.\n");
printf(" Mode: %s\n",windows_mode_str(windows_mode));
printf(" Ver: %x.%02u\n",windows_version>>8,windows_version&0xFF);
}
else {
printf("Not running under Windows or OS/2\n");
- }
+ }*/
if (probe_himem_sys()) {
int h1,h2,h3;