diff --git a/ChangeLog b/ChangeLog index b7862d2..d91901c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +0.56 + - added support for a configclass/configfile + - added support for writing out the configclass into a configfile + - removed the language file and made it internal + - added support for writing the language file (will override the internal one) + - improved mousesupport + - updated readme + - support for screenshots + - some cpu-bug fixes + - dma changes + - Real Sound support + - EMM fixes and new functions. + - VGA fixes + - new wildcompare + - support for size and disktype at mount. + - added new debugger functionalities: start/trace into INTs, write processor status log, + step over rep and loop instructions, breakpoint support without using INT 03 (heavy debugging switch) + - Added more cpu instructions and changed the string operations. + - Added classes for most of the internal dos structures. + - Rewrote most of the fcb calls to use normal dos calls. + +0.55 - fixed the errors/warnings in prefix_66.h and prefix_66_of.h (decimal too large becomming unsigned). - fixed compilation error on FreeBSD when #disable_joystick was defined - int10_writechar has been updated to move the cursor position. diff --git a/INSTALL b/INSTALL index ad94ba9..53dfc97 100644 --- a/INSTALL +++ b/INSTALL @@ -11,8 +11,17 @@ Curses ncurses should be installed on just about every unix distro. For win32 get pdcurses at http://pdcurses.sourceforge.net +Libpng + Needed for the screenshots. + For win32 get libpng from http://www.sourceforge.net/projects/gnuwin32 + +Zlib + Needed by libpng. + For win32 get libz (rename to zlib) from http://www.sourceforge.net/projects/gnuwin32 + + If you want compile from the CVS under a unix system, you'll also need -automake, autoconf. Should be available at http://www.gnu.org +automake (>=1.6), autoconf(>=2.50). Should be available at http://www.gnu.org For building on unix systems. If you are building from the cvs run ./autogen.sh first before doing the following. @@ -21,8 +30,7 @@ If you are building from the cvs run ./autogen.sh first before doing the followi 2. Check settings.h for some setup options. 3. make -Check the src subdir for the binary and dosbox.lang file. -These 2 files should be in the same dir if you want to run dosbox. +Check the src subdir for the binary. Compiling on FreeBSD might be a problem since SDL has no joystick support there. To get around this edit sdlmain.cpp to enable some #define. @@ -32,5 +40,4 @@ Let's hope someday the sdl people will just report 0 joysticks in freebsd or get Build instructions for VC++6 Open the workspace in the visualc subdir and build from there. -Copy the src/dosbox.lang file to the same dir as your executable. diff --git a/NEWS b/NEWS index 517fb04..c39c56c 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,26 @@ +0.56: + - added support for a configclass/configfile + - added support for writing out the configclass into a configfile + - removed the language file and made it internal + - added support for writing the language file (will override the internal one) + - improved mousesupport + - updated readme + - support for screenshots + - some cpu-bug fixes + - dma changes + - Real Sound support + - EMM fixes and new functions. + - VGA fixes + - new wildcompare + - support for size and disktype at mount. + - added new debugger functionalities: start/trace into INTs, write processor status log, + step over rep and loop instructions, breakpoint support without using INT 03 (heavy debugging switch) + - Added more cpu instructions and changed the string operations. + - Added classes for most of the internal dos structures. + - Rewrote most of the fcb calls to use normal dos calls. + + + 0.55: - changed basedir handling. (linux/winXP) - added some FCB-calls @@ -43,4 +66,4 @@ -added the correct time to dir. -bugfixes to batch-file handling. -Lot's of small bugfixes.(Dune1&2,wolf3d, many more). - -Released the source. \ No newline at end of file + -Released the source. diff --git a/README b/README index b6c20dc..7dbc7cc 100644 --- a/README +++ b/README @@ -1,10 +1,11 @@ -DOSBox v0.55 +DOSBox v0.56 Usage: ====== With the new internal shell I've changed the command line a bit, so let's just give some examples of what you can do now. + dosbox With nothing on the command line you'll end up on the internal drive and from there you can mount directories as drives. @@ -14,6 +15,13 @@ dosbox [filename/directory] .bat .com .exe. Doesn't need to have extension included. Then it'll strip the directory from the filename and mount that as c:\ and then run the file. +dosbox -fullscreen + starts dosbox in fullscreen mode. +dosbox -conf file + loads file as a configfile. +dosbox -lang file + loads file as a languagefile. + You can also add commands to be executed before the main program starts. Or you can use them to start the program. To add commands use the -c command line switch. @@ -29,23 +37,49 @@ Internal Programs: ================== MOUNT -Program to mount local directories as drives inside DOSBox. +Program to mount local directories as drives inside DOSBox. +The option -t specifies the media: dir = harddisk, floppy = floppy drive. +The option -size specifies the size. +For example to mount c:\floppy as a floppy : mount -t floppy a c:\floppy -HWSET -Utility to setup the emulated hardware running inside DOSBox, only working for emulated sound cards. +MEM +Program to display the amount of free memory + +CONFIG +Utility for generating a configfile with the current settings and for generating the languagefile. +The option -writeconf filename is used to write the current config settings. +The option -writelang filename is used to write the current language strings. UPCASE Utility to convert all files subdirectories of a local directory into upcase so DOSBox can use that directory for mounting. This tool can be quite dangerous if used unproperly. You have been warned. - To get more information about how to use one these programs use the the /? command line switch. +The Configfile: +=============== +A configfile can be generated by CONFIG.COM. You can edit it to customize DOSBox. +The file is divided in several sections (the names got [] around it). Some sections have options which you can set. +# and % indicate commentlines. +The generated configfile contains the current settings. You can alter them and +start dosbox with the -conf switch to load the file and use these settings. +For example in the section sblaster you can change the irq of the soundblaster and disable/enable the +adlib emulation. + +The Languagefile: +================= +A languagefile can be generated by CONFIG.COM. If you read it you will understand how to change it. +Start Dosbox with -lang switch to use your language file or enter the location of the languagefile +in the configfile.(section:[dosbox] language=full path to languagefile.) Special Keys: ============= ALT-ENTER Go full screen and back. +CTRL-F5 Save a screenshot +CTRL-F7 Decrease frameskip +CTRL-F8 Increase frameskip +CTRL-F9 Go full screen and back. CTRL-F10 Capture/Release the mouse. CTRL-F11 Slowdown emulation. CTRL-F12 Speedup emulation. @@ -70,7 +104,10 @@ FAQ: A: When you mouse touches the edges of the DOSBox screen you can click and drag it to the size you prefer. -3. Check the site/forum. +3.Q: The mouse(cursor) acts weird. (eg only updated when you press the mousebutton) + A: Lock the mouse with ctrl-F10. It should then behave the way you expect it to do. + +4. Check the site/forum. Building your own Version DOSBox: ================================= diff --git a/config.h.in b/config.h.in index ee193ec..63982de 100644 --- a/config.h.in +++ b/config.h.in @@ -26,6 +26,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `png' library (-lpng). */ +#undef HAVE_LIBPNG + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H diff --git a/configure b/configure index 0def7ee..a37a463 100644 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.53a for dosbox 0.55. +# Generated by GNU Autoconf 2.53a for dosbox 0.56. # # Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 # Free Software Foundation, Inc. @@ -272,8 +272,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='dosbox' PACKAGE_TARNAME='dosbox' -PACKAGE_VERSION='0.55' -PACKAGE_STRING='dosbox 0.55' +PACKAGE_VERSION='0.56' +PACKAGE_STRING='dosbox 0.56' PACKAGE_BUGREPORT='' ac_unique_file="README" @@ -786,7 +786,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures dosbox 0.55 to adapt to many kinds of systems. +\`configure' configures dosbox 0.56 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -853,7 +853,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dosbox 0.55:";; + short | recursive ) echo "Configuration of dosbox 0.56:";; esac cat <<\_ACEOF @@ -946,7 +946,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -dosbox configure 0.55 +dosbox configure 0.56 generated by GNU Autoconf 2.53a Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 @@ -961,7 +961,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dosbox $as_me 0.55, which was +It was created by dosbox $as_me 0.56, which was generated by GNU Autoconf 2.53a. Invocation command line was $ $0 $@ @@ -1579,7 +1579,7 @@ fi # Define the identity of the package. PACKAGE=dosbox - VERSION=0.55 + VERSION=0.56 cat >>confdefs.h <<_ACEOF @@ -1712,7 +1712,6 @@ INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" - echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` @@ -4232,6 +4231,76 @@ _ACEOF fi + +echo "$as_me:$LINENO: checking for png_check_sig in -lpng" >&5 +echo $ECHO_N "checking for png_check_sig in -lpng... $ECHO_C" >&6 +if test "${ac_cv_lib_png_png_check_sig+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpng -lz $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char png_check_sig (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +png_check_sig (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_png_png_check_sig=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_png_png_check_sig=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_png_png_check_sig" >&5 +echo "${ECHO_T}$ac_cv_lib_png_png_check_sig" >&6 +if test $ac_cv_lib_png_png_check_sig = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPNG 1 +_ACEOF + + LIBS="-lpng $LIBS" + +else + { { echo "$as_me:$LINENO: error: *** libpng not found!" >&5 +echo "$as_me: error: *** libpng not found!" >&2;} + { (exit 1); exit 1; }; } +fi + + #Check if the compiler support attributes echo "$as_me:$LINENO: checking if compiler allows __attribute__" >&5 echo $ECHO_N "checking if compiler allows __attribute__... $ECHO_C" >&6 @@ -4637,7 +4706,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by dosbox $as_me 0.55, which was +This file was extended by dosbox $as_me 0.56, which was generated by GNU Autoconf 2.53a. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4699,7 +4768,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -dosbox config.status 0.55 +dosbox config.status 0.56 configured by $0, generated by GNU Autoconf 2.53a, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.in b/configure.in index c0cb967..4fa3482 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Init. -AC_INIT(dosbox,0.55) +AC_INIT(dosbox,0.56) AC_CONFIG_SRCDIR(README) dnl Detect the canonical host and target build environment @@ -10,7 +10,6 @@ dnl Setup for automake AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) - dnl Checks for programs. AC_PROG_MAKE_SET AC_PROG_CC @@ -36,6 +35,9 @@ AC_C_INLINE AC_TYPE_SIZE_T AC_STRUCT_TM +dnl Checks for libraries. +AC_CHECK_LIB(png, png_check_sig, , AC_MSG_ERROR([*** libpng not found!]), -lz) + #Check if the compiler support attributes AC_MSG_CHECKING(if compiler allows __attribute__) AC_TRY_COMPILE([], [typedef struct { } __attribute__ ((packed)) junk;], diff --git a/include/bios.h b/include/bios.h index 61d940b..ef37fa8 100644 --- a/include/bios.h +++ b/include/bios.h @@ -84,6 +84,11 @@ #define BIOS_KEYBOARD_FLAGS3 0x496 #define BIOS_KEYBOARD_LEDS 0x497 + +#define BIOS_WAIT_FLAG_POINTER 0x498 +#define BIOS_WAIT_FLAG_COUNT 0x49c +#define BIOS_WAIT_FLAG_ACTIVE 0x4a0 + #define BIOS_PRINT_SCREEN_FLAG 0x500 #define BIOS_VIDEO_SAVEPTR 0x4a8 diff --git a/include/cpu.h b/include/cpu.h index 1712713..ca64958 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -25,9 +25,9 @@ /* Some common Defines */ /* A CPU Handler */ -typedef Bitu (CPU_Decoder)(Bitu count); +typedef Bitu (CPU_Decoder)(Bits count); extern CPU_Decoder * cpudecoder; -extern Bit32u cpu_cycles; +extern Bitu cpu_cycles; //CPU Stuff void SetCPU16bit(); diff --git a/include/cross.h b/include/cross.h index 2dc3d2c..65066cd 100644 --- a/include/cross.h +++ b/include/cross.h @@ -34,7 +34,7 @@ #define CROSS_LEN 512 /* Maximum filename size */ -#if defined (_MSC_VER) /* MS Visual C++ */ +#if defined (WIN32) /* Win 32 */ #define CROSS_FILENAME(blah) #define CROSS_FILESPLIT '\\' #define F_OK 0 @@ -46,7 +46,7 @@ #define CROSS_NONE 0 #define CROSS_FILE 1 #define CROSS_DIR 2 -#if defined (_MSC_VER) +#if defined (WIN32) #define ftruncate(blah,blah2) chsize(blah,blah2) #endif diff --git a/include/debug.h b/include/debug.h index 300fa11..2dfa9c6 100644 --- a/include/debug.h +++ b/include/debug.h @@ -16,10 +16,16 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +void DEBUG_SetupConsole(void); void DEBUG_DrawScreen(void); -bool DEBUG_BreakPoint(void); +bool DEBUG_Breakpoint(void); bool DEBUG_IntBreakpoint(Bit8u intNum); void DEBUG_Enable(void); +void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off); +bool DEBUG_ExitLoop(void); extern Bitu cycle_count; +#ifdef C_HEAVY_DEBUG +bool DEBUG_HeavyIsBreakpoint(); +#endif diff --git a/include/dos_inc.h b/include/dos_inc.h index 5edb717..48bc6ab 100644 --- a/include/dos_inc.h +++ b/include/dos_inc.h @@ -23,57 +23,11 @@ #include #pragma pack (1) - struct CommandTail{ Bit8u count; /* number of bytes returned */ char buffer[127]; /* the buffer itself */ } GCC_ATTRIBUTE(packed); -struct PSP { - Bit8u exit[2]; /* CP/M-like exit poimt */ - Bit16u mem_size; /* memory size in paragraphs */ - Bit8u fill_1; /* single char fill */ - -/* CPM Stuff dunno what this is*/ -//TODO Add some checks for people using this i think - Bit8u far_call; /* far call opcode */ - RealPt cpm_entry; /* CPM Service Request address*/ - RealPt int_22; /* Terminate Address */ - RealPt int_23; /* Break Address */ - RealPt int_24; /* Critical Error Address */ - Bit16u psp_parent; /* Parent PSP Segment */ - Bit8u files[20]; /* File Table - 0xff is unused */ - Bit16u environment; /* Segment of evironment table */ - RealPt stack; /* SS:SP Save point for int 0x21 calls */ - Bit16u max_files; /* Maximum open files */ - RealPt file_table; /* Pointer to File Table PSP:0x18 */ - RealPt prev_psp; /* Pointer to previous PSP */ - RealPt dta; /* Pointer to current Process DTA */ - Bit8u fill_2[16]; /* Lot's of unused stuff i can't care aboue */ - Bit8u service[3]; /* INT 0x21 Service call int 0x21;retf; */ - Bit8u fill_3[45]; /* This has some blocks with FCB info */ - - CommandTail cmdtail; - -} GCC_ATTRIBUTE(packed); - -struct ParamBlock { - union { - struct { - Bit16u loadseg; - Bit16u relocation; - } overlay; - struct { - Bit16u envseg; - RealPt cmdtail; - RealPt fcb1; - RealPt fcb2; - RealPt initsssp; - RealPt initcsip; - } exec; - }; -} GCC_ATTRIBUTE(packed); - struct MCB { Bit8u type; @@ -91,7 +45,6 @@ struct DOS_Date { Bit8u day; }; - struct DOS_Version { Bit8u major,minor,revision; }; @@ -107,10 +60,13 @@ struct DOS_Block { RealPt dta; Bit8u return_code,return_mode; + Bit8u current_drive; bool verify; bool breakcheck; struct { RealPt indosflag; + RealPt mediaid; + RealPt tempdta; } tables; }; @@ -124,6 +80,7 @@ enum { RETURN_EXIT=0,RETURN_CTRLC=1,RETURN_ABORT=2,RETURN_TSR=3}; extern DOS_Block dos; extern DOS_File * Files[DOS_FILES]; extern DOS_Drive * Drives[DOS_DRIVES]; +extern Bit8u dos_copybuf[0x10000]; void DOS_SetError(Bit16u code); @@ -133,17 +90,16 @@ void DOS_SetError(Bit16u code); enum { STDIN=0,STDOUT=1,STDERR=2,STDAUX=3,STDNUL=4,STDPRN=5}; enum { HAND_NONE=0,HAND_FILE,HAND_DEVICE}; - - /* Routines for File Class */ void DOS_SetupFiles (void); - bool DOS_ReadFile(Bit16u handle,Bit8u * data,Bit16u * amount); bool DOS_WriteFile(Bit16u handle,Bit8u * data,Bit16u * amount); bool DOS_SeekFile(Bit16u handle,Bit32u * pos,Bit32u type); bool DOS_CloseFile(Bit16u handle); bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry); bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry); +bool DOS_GetFileDate(Bit16u entry, Bit16u* otime, Bit16u* odate); + /* Routines for Drive Class */ bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry); bool DOS_CreateFile(char * name,Bit16u attribute,Bit16u * entry); @@ -153,6 +109,7 @@ bool DOS_FindNext(void); bool DOS_Canonicalize(char * name,char * big); bool DOS_CreateTempFile(char * name,Bit16u * entry); bool DOS_FileExists(char * name); + /* Drive Handing Routines */ Bit8u DOS_GetDefaultDrive(void); void DOS_SetDefaultDrive(Bit8u drive); @@ -164,14 +121,16 @@ bool DOS_RemoveDir(char * dir); bool DOS_Rename(char * oldname,char * newname); bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free); bool DOS_GetFileAttr(char * name,Bit16u * attr); + /* IOCTL Stuff */ -bool DOS_IOCTL(Bit8u call,Bit16u entry); +bool DOS_IOCTL(void); bool DOS_GetSTDINStatus(); Bit8u DOS_FindDevice(char * name); void DOS_SetupDevices(void); + /* Execute and new process creation */ -bool DOS_NewPSP(Bit16u pspseg); -bool DOS_Execute(char * name,ParamBlock * block,Bit8u flags); +bool DOS_NewPSP(Bit16u pspseg,Bit16u size); +bool DOS_Execute(char * name,PhysPt block,Bit8u flags); bool DOS_Terminate(bool tsr); /* Memory Handling Routines */ @@ -182,33 +141,45 @@ bool DOS_FreeMemory(Bit16u segment); void DOS_FreeProcessMemory(Bit16u pspseg); Bit16u DOS_GetMemory(Bit16u pages); - /* FCB stuff */ -bool DOS_FCBOpen(Bit16u seg,Bit16u offset); +bool DOS_FCBOpenCreate(Bit16u seg,Bit16u offset); bool DOS_FCBClose(Bit16u seg,Bit16u offset); bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset); bool DOS_FCBFindNext(Bit16u seg,Bit16u offset); +Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset, Bit16u numBlocks); +bool DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u numBlocks); +Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore); +bool DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore); +bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset,Bit16u numRec); +bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset); +bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset); +void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset); Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change); +bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters); + /* Extra DOS Interrupts */ void DOS_SetupMisc(void); /* The DOS Tables */ void DOS_SetupTables(void); + /* Internal DOS Setup Programs */ void DOS_SetupPrograms(void); - INLINE Bit16u long2para(Bit32u size) { if (size>0xFFFF0) return 0xffff; if (size&0xf) return (Bit16u)((size>>4)+1); else return (Bit16u)(size>>4); -}; +} -INLINE Bit8u RealHandle(Bit16u handle) { - PSP * psp=(PSP *)HostMake(dos.psp,0); - if (handle>=psp->max_files) return 0xff; - return mem_readb(Real2Phys(psp->file_table)+handle); -}; + +INLINE Bit16u DOS_PackTime(Bit16u hour,Bit16u min,Bit16u sec) { + return (hour&0x1f)<<11 | (min&0x3f) << 5 | ((sec/2)&0x1f); +} + +INLINE Bit16u DOS_PackDate(Bit16u year,Bit16u mon,Bit16u day) { + return ((year-1980)&0x7f)<<9 | (mon&0x3f) << 5 | (day&0x1f); +} /* Dos Error Codes */ #define DOSERR_NONE 0 @@ -233,68 +204,136 @@ INLINE Bit8u RealHandle(Bit16u handle) { #define DOSERR_NO_MORE_FILES 18 /* Remains some classes used to access certain things */ -class DOS_FCB { + +#define sGet(s,m) GetIt(((s *)Phys2Host(pt))->m,(PhysPt)&(((s *)0)->m)) +#define sSave(s,m,val) SaveIt(((s *)Phys2Host(pt))->m,(PhysPt)&(((s *)0)->m),val) + +class MemStruct { public: - DOS_FCB(PhysPt pt){ - off=pt; + INLINE Bit8u GetIt(Bit8u,PhysPt addr) { + return mem_readb(pt+addr); } - DOS_FCB(Bit16u seg, Bit16u offset){ - off=PhysMake(seg,offset); + INLINE Bit16u GetIt(Bit16u,PhysPt addr) { + return mem_readw(pt+addr); } - void Set_drive(Bit8u a); - void Set_filename(char* a); //writes an the first 8 bytes of a as the filename - void Set_ext(char* a); - void Set_current_block(Bit16u a); - void Set_record_size(Bit16u a); - void Set_filesize(Bit32u a); - void Set_date(Bit16u a); - void Set_time(Bit16u a); - // others nog yet handled - Bit8u Get_drive(void); - void Get_filename(char* a); - void Get_ext(char* a); - Bit16u Get_current_block(void); - Bit16u Get_record_size(void); - Bit32u Get_filesize(void); - Bit16u Get_date(void); - Bit16u Get_time(void); -private: - PhysPt off; + INLINE Bit32u GetIt(Bit32u,PhysPt addr) { + return mem_readd(pt+addr); + } + INLINE void SaveIt(Bit8u,PhysPt addr,Bit8u val) { + mem_writeb(pt+addr,val); + } + INLINE void SaveIt(Bit16u,PhysPt addr,Bit16u val) { + mem_writew(pt+addr,val); + } + INLINE void SaveIt(Bit32u,PhysPt addr,Bit32u val) { + mem_writed(pt+addr,val); + } + INLINE void SetPt(Bit16u seg) { pt=PhysMake(seg,0);} + INLINE void SetPt(Bit16u seg,Bit16u off) { pt=PhysMake(seg,off);} + INLINE void SetPt(RealPt addr) { pt=Real2Phys(addr);} +protected: + PhysPt pt; }; - - -class DOS_ParamBlock { +class DOS_PSP :public MemStruct { public: - DOS_ParamBlock(PhysPt pt){ - off=pt; - }; - void InitExec(RealPt cmdtail); - Bit16u loadseg(void); - Bit16u relocation(void); - Bit16u envseg(void); - RealPt initsssp(void); - RealPt initcsip(void); - RealPt fcb1(void); - RealPt fcb2(void); - RealPt cmdtail(void); + DOS_PSP (Bit16u segment) { SetPt(segment);seg=segment;psp=(sPSP *)HostMake(segment,0);}; + void MakeNew (Bit16u memSize); + void CopyFileTable (DOS_PSP* srcpsp); + Bit16u FindFreeFileEntry (void); + void CloseFiles (void); + + void SaveVectors (void); + void RestoreVectors (void); + void SetSize (Bit16u size) { sSave(sPSP,next_seg,size); }; + Bit16u GetSize () { return sGet(sPSP,next_seg); }; + void SetDTA (RealPt ptdta) { sSave(sPSP,dta,ptdta); }; + RealPt GetDTA (void) { return sGet(sPSP,dta); }; + void SetEnvironment (Bit16u envseg) { sSave(sPSP,environment,envseg); }; + Bit16u GetEnvironment (void) { return sGet(sPSP,environment); }; + Bit16u GetSegment (void) { return seg; }; + void SetFileHandle (Bit16u index, Bit8u handle); + Bit8u GetFileHandle (Bit16u index); + void SetParent (Bit16u parent) { sSave(sPSP,psp_parent,parent); }; + Bit16u GetParent (void) { return sGet(sPSP,psp_parent); }; + void SetStack (RealPt stackpt) { sSave(sPSP,stack,stackpt); }; + RealPt GetStack (void) { return sGet(sPSP,stack); }; + void SetInt22 (RealPt int22pt) { sSave(sPSP,int_22,int22pt); }; + RealPt GetInt22 (void) { return sGet(sPSP,int_22); }; + void SetFCB1 (RealPt src); + void SetFCB2 (RealPt src); + void SetCommandTail (RealPt src); + private: - PhysPt off; + #pragma pack(1) + struct sPSP { + Bit8u exit[2]; /* CP/M-like exit poimt */ + Bit16u next_seg; /* Segment of first byte beyond memory allocated or program */ + Bit8u fill_1; /* single char fill */ + Bit8u far_call; /* far call opcode */ + RealPt cpm_entry; /* CPM Service Request address*/ + RealPt int_22; /* Terminate Address */ + RealPt int_23; /* Break Address */ + RealPt int_24; /* Critical Error Address */ + Bit16u psp_parent; /* Parent PSP Segment */ + Bit8u files[20]; /* File Table - 0xff is unused */ + Bit16u environment; /* Segment of evironment table */ + RealPt stack; /* SS:SP Save point for int 0x21 calls */ + Bit16u max_files; /* Maximum open files */ + RealPt file_table; /* Pointer to File Table PSP:0x18 */ + RealPt prev_psp; /* Pointer to previous PSP */ + RealPt dta; /* Pointer to current Process DTA */ + Bit8u fill_2[16]; /* Lot's of unused stuff i can't care aboue */ + Bit8u service[3]; /* INT 0x21 Service call int 0x21;retf; */ + Bit8u fill_3[9]; /* This has some blocks with FCB info */ + Bit8u fcb1[16]; /* first FCB */ + Bit8u fcb2[16]; /* second FCB */ + Bit8u fill_4[4]; /* unused */ + CommandTail cmdtail; + } GCC_ATTRIBUTE(packed); + #pragma pack() + Bit16u seg; + sPSP* psp; +public: + static Bit16u rootpsp; }; -class DOS_InfoBlock { +class DOS_ParamBlock:public MemStruct { public: - DOS_InfoBlock (void) { seg=0; dib=0; }; + DOS_ParamBlock(PhysPt addr) {pt=addr;} + void Clear(void); + void LoadData(void); + void SaveData(void); /* Save it as an exec block */ + #pragma pack (1) + struct sOverlay { + Bit16u loadseg; + Bit16u relocation; + } GCC_ATTRIBUTE(packed); + struct sExec { + Bit16u envseg; + RealPt cmdtail; + RealPt fcb1; + RealPt fcb2; + RealPt initsssp; + RealPt initcsip; + }GCC_ATTRIBUTE(packed); + #pragma pack() + sExec exec; + sOverlay overlay; +}; - void SetLocation (Bit16u segment); - void SetFirstMCB (RealPt pt); - void GetDIBPointer (Bit16u& segment, Bit16u& offset); - +class DOS_InfoBlock:public MemStruct { +public: + DOS_InfoBlock () {}; + void SetLocation(Bit16u seg); + void SetFirstMCB(Bit16u _first_mcb); + void SetfirstFileTable(RealPt _first_table); + RealPt GetPointer (void); private: - #pragma pack (push,1) - struct SDosInfoBlock { + #pragma pack(1) + struct sDIB { Bit8u stuff1[22]; // some stuff, hopefully never used.... - RealPt firstMCB; // first memory control block + Bit16u firstMCB; // first memory control block RealPt firstDPB; // first drive parameter block RealPt firstFileTable; // first system file table RealPt activeClock; // active clock device header @@ -305,13 +344,83 @@ private: RealPt fcbTable; // pointer to system FCB table // some more stuff, hopefully never used. } GCC_ATTRIBUTE(packed); - #pragma pack (pop) - - SDosInfoBlock* dib; - Bit16u seg; + #pragma pack () + Bit16u seg; }; -extern DOS_InfoBlock dosInfoBlock; +class DOS_DTA:public MemStruct{ +public: + DOS_DTA(RealPt addr) { SetPt(addr); } + + void SetupSearch(Bit8u _sdrive,Bit8u _sattr,char * _pattern); + void SetResult(const char * _name,Bit32u _size,Bit16u _date,Bit16u _time,Bit8u _attr); + + Bit8u GetSearchDrive(void); + void GetSearchParams(Bit8u & _sattr,char * _spattern); + void GetResult(char * _name,Bit32u & _size,Bit16u & _date,Bit16u & _time,Bit8u & _attr); +private: + #pragma pack(1) + struct sDTA { + Bit8u sdrive; /* The Drive the search is taking place */ + Bit8u sattr; /* The Attributes that need to be found */ + Bit8u sname[8]; /* The Search pattern for the filename */ + Bit8u sext[3]; /* The Search pattern for the extenstion */ + Bit8u fill[8]; + Bit8u attr; + Bit16u time; + Bit16u date; + Bit32u size; + char name[DOS_NAMELENGTH_ASCII]; + } GCC_ATTRIBUTE(packed); + #pragma pack() +}; + +class DOS_FCB: public MemStruct { +public: + DOS_FCB(Bit16u seg,Bit16u off); + void Create(bool _extended); + void SetName(Bit8u _drive,char * _fname,char * _ext); + void SetSizeDateTime(Bit32u _size,Bit16u _date,Bit16u _time); + void GetSizeDateTime(Bit32u & _size,Bit16u & _date,Bit16u & _time); + void GetName(char * fillname); + void FileOpen(Bit8u _fhandle); + void FileClose(Bit8u & _fhandle); + void GetRecord(Bit16u & _cur_block,Bit8u & _cur_rec); + void SetRecord(Bit16u _cur_block,Bit8u _cur_rec); + void GetSeqData(Bit8u & _fhandle,Bit16u & _rec_size); + void GetRandom(Bit32u & _random); + void SetRandom(Bit32u _random); + Bit8u GetDrive(void); + bool Extended(void); +private: + bool extended; + PhysPt real_pt; + #pragma pack (1) + struct sFCB { + Bit8u drive; /* Drive number 0=default, 1=A, etc */ + Bit8u filename[8]; /* Space padded name */ + Bit8u ext[3]; /* Space padded extension */ + Bit16u cur_block; /* Current Block */ + Bit16u rec_size; /* Logical record size */ + Bit32u filesize; /* File Size */ + Bit16u date; + Bit16u time; + /* Reserved Block should be 8 bytes */ + Bit8u file_handle; + Bit8u reserved[7]; + /* end */ + Bit8u cur_rec; /* Current record in current block */ + Bit32u rndm; /* Current relative record number */ + } GCC_ATTRIBUTE(packed); + #pragma pack () +}; + +extern DOS_InfoBlock dos_infoblock;; + +INLINE Bit8u RealHandle(Bit16u handle) { + DOS_PSP psp(dos.psp); + return psp.GetFileHandle((Bit8u)handle); +} #endif diff --git a/include/dos_system.h b/include/dos_system.h index 0b240d0..0223a9a 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -19,11 +19,13 @@ #ifndef DOSSYSTEM_H_ #define DOSSYSTEM_H_ -#include +#include "dosbox.h" #define DOS_NAMELENGTH 12 -#define DOS_DIRDEPTH 16 -#define DOS_PATHLENGTH (DOS_DIRDEPTH+1)*(DOS_NAMELENGTH+2) +#define DOS_NAMELENGTH_ASCII (DOS_NAMELENGTH+1) +#define DOS_FCBNAME 15 +#define DOS_DIRDEPTH 8 +#define DOS_PATHLENGTH 80 #define DOS_TEMPSIZE 1024 enum { @@ -35,34 +37,29 @@ enum { DOS_ATTR_ARCHIVE= 0x20 }; -#if defined (_MSC_VER) -#pragma pack(1) -#endif -struct DTA_FindBlock { - Bit8u sdrive; /* The Drive the search is taking place */ - Bit16u sattr; /* The attributes that need to be found */ - Bit8u fill[18]; - Bit8u attr; +struct FileStat_Block { + Bit32u size; Bit16u time; Bit16u date; - Bit32u size; - char name[DOS_NAMELENGTH]; -} -#if defined (_MSC_VER) -; -#pragma pack() -#else -__attribute__ ((packed)); -#endif + Bit16u attr; +}; + +class DOS_DTA; class DOS_File { public: + virtual ~DOS_File(){}; virtual bool Read(Bit8u * data,Bit16u * size)=0; virtual bool Write(Bit8u * data,Bit16u * size)=0; virtual bool Seek(Bit32u * pos,Bit32u type)=0; virtual bool Close()=0; virtual Bit16u GetInformation(void)=0; - Bit8u type;Bit32u flags; + Bit8u type; + Bit32u flags; + Bit16u time; + Bit16u date; + Bit16u attr; + Bit32u size; /* Some Device Specific Stuff */ }; @@ -73,24 +70,24 @@ public: Bit8u fhandle; }; - - class DOS_Drive { public: DOS_Drive(); + virtual ~DOS_Drive(){}; virtual bool FileOpen(DOS_File * * file,char * name,Bit32u flags)=0; virtual bool FileCreate(DOS_File * * file,char * name,Bit16u attributes)=0; - virtual bool FileUnlink(char * name)=0; - virtual bool RemoveDir(char * dir)=0; - virtual bool MakeDir(char * dir)=0; - virtual bool TestDir(char * dir)=0; - virtual bool FindFirst(char * search,DTA_FindBlock * dta)=0; - virtual bool FindNext(DTA_FindBlock * dta)=0; + virtual bool FileUnlink(char * _name)=0; + virtual bool RemoveDir(char * _dir)=0; + virtual bool MakeDir(char * _dir)=0; + virtual bool TestDir(char * _dir)=0; + virtual bool FindFirst(char * _dir,DOS_DTA & dta)=0; + virtual bool FindNext(DOS_DTA & dta)=0; virtual bool GetFileAttr(char * name,Bit16u * attr)=0; virtual bool Rename(char * oldname,char * newname)=0; - virtual bool FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free)=0; - virtual bool FileExists(const char* name) const=0; - virtual bool FileStat(const char* name, struct stat* const stat_block) const=0; + virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters)=0; + virtual bool FileExists(const char* name)=0; + virtual bool FileStat(const char* name, FileStat_Block * const stat_block)=0; + virtual Bit8u GetMediaByte(void)=0; char * GetInfo(void); char curdir[DOS_PATHLENGTH]; char info[256]; @@ -109,6 +106,6 @@ typedef bool (MultiplexHandler)(void); void DOS_AddMultiplexHandler(MultiplexHandler * handler); void DOS_AddDevice(DOS_Device * adddev); -void VFILE_Register(char * name,Bit8u * data,Bit32u size); +void VFILE_Register(const char * name,Bit8u * data,Bit32u size); #endif diff --git a/include/dosbox.h b/include/dosbox.h index b277391..25606f6 100644 --- a/include/dosbox.h +++ b/include/dosbox.h @@ -24,6 +24,9 @@ void E_Exit(char * message,...); void S_Warn(char * message,...); +void MSG_Add(const char*,const char*); //add messages to the internal langaugefile +const char* MSG_Get(char const *); //get messages from the internal langaugafile + /* The internal types */ typedef unsigned char Bit8u; typedef signed char Bit8s; @@ -47,14 +50,115 @@ typedef signed int Bits; #include "config.h" #include "../settings.h" +class Section; + + typedef Bitu (LoopHandler)(void); void DOSBOX_RunMachine(); void DOSBOX_SetLoop(LoopHandler * handler); void DOSBOX_SetNormalLoop(); -void DOSBOX_Init(int argc, char* argv[]); -void DOSBOX_StartUp(void); +void DOSBOX_Init(void); + +class Config; +extern Config * control; +extern Bitu errorlevel; + +inline void LOG_MSG(char* message) +{ + if(errorlevel>=0) S_Warn(message); +} + +template +inline void LOG_MSG(char* message,type1 arg1) +{ + + if(errorlevel>=0) S_Warn(message,arg1); +} + +template +inline void LOG_MSG(char* message,type1 arg1,type2 arg2) +{ + + if(errorlevel>=0) S_Warn(message,arg1,arg2); +} + +template +inline void LOG_MSG(char* message,type1 arg1,type2 arg2,type3 arg3) +{ + + if (errorlevel>=0)S_Warn(message,arg1,arg2,arg3); +} + +#if C_LOGGING +inline void LOG_DEBUG(char * message) +{ + + if(errorlevel>=2) S_Warn(message); +} + +template +inline void LOG_DEBUG(char * message, type type1) +{ + + if(errorlevel>=2) S_Warn(message,type1); +} + +template +inline void LOG_WARN(char * message, type type1) +{ + + if(errorlevel>=1) S_Warn(message,type1); +} + +inline void LOG_WARN(char* message) +{ + + if(errorlevel>=1) S_Warn(message); +} + +inline void LOG_ERROR(char * message) +{ + + if(errorlevel>=0) S_Warn(message); +} + +template +inline void LOG_ERROR(char * message, type type1) +{ + + if(errorlevel>=0) S_Warn(message,type1); +} + +template +inline void LOG_ERROR(char * message, type1 arg1,type2 arg2) +{ + + if(errorlevel>=0) S_Warn(message,arg1,arg2); +} + +template +inline void LOG_WARN(char * message, type1 arg1,type2 arg2) +{ + + if(errorlevel>=1) S_Warn(message,arg1,arg2); +} + +template +inline void LOG_DEBUG(char * message, type1 arg1,type2 arg2) +{ + + if(errorlevel>=2) S_Warn(message,arg1,arg2); +} + +#else +#define LOG_DEBUG +#define LOG_WARN +#define LOG_ERROR +#endif + + #endif diff --git a/include/hardware.h b/include/hardware.h index 5edfa4b..514e13a 100644 --- a/include/hardware.h +++ b/include/hardware.h @@ -19,24 +19,7 @@ #ifndef _HARDWARE_H_ #define _HARDWARE_H_ -#include -#include -#include -typedef void (* HW_OutputHandler)(char * towrite); -typedef void (* HW_InputHandler)(char * line); - -struct HWBlock { - char * dev_name; /* 8 characters max dev name */ - char * full_name; /* 60 characters full name */ - char * help; - HW_InputHandler get_input; - HW_OutputHandler show_status; /* Supplied with a string to display 50 chars of status info in */ - HWBlock * next; -}; - - -void HW_Register(HWBlock * block); #endif diff --git a/include/keyboard.h b/include/keyboard.h index ec495d0..0ff524e 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -16,6 +16,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef _KEYBOARD_H_ +#define _KEYBOARD_H_ + typedef void(KEYBOARD_EventHandler)(void); void KEYBOARD_AddCode(Bit8u code); void KEYBOARD_AddKey(Bitu keytype,bool pressed); @@ -51,4 +54,4 @@ enum { KBD_LAST }; - +#endif diff --git a/include/mem.h b/include/mem.h index e891cb4..169e49c 100644 --- a/include/mem.h +++ b/include/mem.h @@ -30,7 +30,7 @@ typedef Bit8u (*MEMORY_ReadHandler)(PhysPt pt); typedef void (*MEMORY_WriteHandler)(PhysPt pt,Bit8u val); #define PAGE_KB 16 -#define PAGE_SIZE PAGE_KB*1024 +#define PAGE_SIZE (PAGE_KB*1024) #define PAGE_SHIFT 14 #define PAGE_COUNT(A) (A & ((1 << PAGE_SHIFT)-1) ? 1+(A >> PAGE_SHIFT) : (A >> PAGE_SHIFT) ) #define MAX_PAGES PAGE_COUNT(C_MEM_MAX_SIZE*1024*1024) diff --git a/include/mixer.h b/include/mixer.h index e41b183..3c02d93 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -37,6 +37,9 @@ void MIXER_SetFreq(MIXER_Channel * chan,Bit32u freq); void MIXER_SetMode(MIXER_Channel * chan,Bit8u mode); void MIXER_Enable(MIXER_Channel * chan,bool enable); -void PCSPEAKER_Enable(bool enable); -void PCSPEAKER_SetFreq(Bit32u freq); +/* PC Speakers functions, tightly related to the timer functions */ + +void PCSPEAKER_Enable(bool enable); +void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode); + diff --git a/include/mouse.h b/include/mouse.h index 4d0c932..764d550 100644 --- a/include/mouse.h +++ b/include/mouse.h @@ -25,4 +25,5 @@ void Mouse_CursorSet(float x,float y); void Mouse_ButtonPressed(Bit8u button); void Mouse_ButtonReleased(Bit8u button); +void Mouse_AutoLock(bool enable); diff --git a/include/pic.h b/include/pic.h index 44a2f76..e7b41be 100644 --- a/include/pic.h +++ b/include/pic.h @@ -20,9 +20,14 @@ #define __PIC_H typedef void (PIC_EOIHandler) (void); -typedef void (PIC_Function)(void); -extern Bit32u PIC_IRQCheck; +#define PIC_MAXIRQ 15 +#define PIC_NOIRQ 0xFF + + +extern Bitu PIC_IRQCheck; +extern Bitu PIC_IRQActive; +extern bool PIC_IRQAgain; void PIC_ActivateIRQ(Bit32u irq); @@ -33,11 +38,6 @@ void PIC_runIRQs(void); void PIC_RegisterIRQ(Bit32u irq,PIC_EOIHandler handler,char * name); void PIC_FreeIRQ(Bit32u irq); -bool PIC_IRQActive(Bit32u irq); - -/* A Queued function should never queue itself again this will go horribly wrong */ -void PIC_QueueFunction(PIC_Function * function); - #endif diff --git a/include/programs.h b/include/programs.h index d716510..3ce261a 100644 --- a/include/programs.h +++ b/include/programs.h @@ -18,32 +18,33 @@ #ifndef __PROGRAM_H #define __PROGRAM_H -#include -#include +#include "dosbox.h" +#include "dos_inc.h" +#include "setup.h" -char * MSG_Get(char * msg); -struct PROGRAM_Info { - Bit16u psp_seg; - PSP psp_copy; - char full_name[32]; //Enough space for programs only on the z:\ drive - char * cmd_line; -}; +class Program; -typedef void (PROGRAMS_Main)(PROGRAM_Info * info); +typedef void (PROGRAMS_Main)(Program * * make); void PROGRAMS_MakeFile(char * name,PROGRAMS_Main * main); class Program { public: - Program(PROGRAM_Info * program_info); + Program(); + virtual ~Program(){ + delete cmd; + delete psp; + } + std::string temp_line; + CommandLine * cmd; + DOS_PSP * psp; virtual void Run(void)=0; - char * GetEnvStr(char * env_entry); - char * GetEnvNum(Bit32u num); - Bit32u GetEnvCount(void); - bool SetEnv(char * env_entry,char * new_string); - void WriteOut(char * format,...); /* Write to standard output */ - PROGRAM_Info * prog_info; + bool Program::GetEnvStr(const char * entry,std::string & result); + bool GetEnvNum(Bitu num,std::string & result); + Bitu GetEnvCount(void); + bool SetEnv(const char * entry,const char * new_string); + void WriteOut(const char * format,...); /* Write to standard output */ }; diff --git a/include/setup.h b/include/setup.h index ec82011..865165f 100644 --- a/include/setup.h +++ b/include/setup.h @@ -19,25 +19,171 @@ #ifndef _SETUP_H_ #define _SETUP_H_ +#pragma warning ( disable : 4786 ) + #include -enum { S_STRING,S_HEX,S_INT,S_BOOL}; +#include +#include -typedef char *(String_Handler)(char * input); -typedef char *(Hex_Handler)(Bitu * input); -typedef char *(Int_Handler)(Bits * input); -typedef char *(Bool_Handler)(bool input); - -class Setup { +class CommandLine { +public: + CommandLine(int argc,char * argv[]); + CommandLine(char * name,char * cmdline); + const char * GetFileName(){ return file_name.c_str();} - + bool FindExist(char * name,bool remove=false); + bool FindHex(char * name,int & value,bool remove=false); + bool FindInt(char * name,int & value,bool remove=false); + bool FindString(char * name,std::string & value,bool remove=false); + bool FindCommand(int which,std::string & value); + bool FindStringBegin(char * begin,std::string & value, bool remove=false); + int GetCount(void); private: - int argc; - char * * argv; + typedef std::list::iterator cmd_it; + std::list cmds; + std::string file_name; + bool FindEntry(char * name,cmd_it & it,bool neednext=false); +}; +union Value{ + int _hex; + bool _bool; + int _int; + std::string* _string; +}; + +class Property { +public: + Property(const char* _propname):propname(_propname) { } + virtual void SetValue(char* input)=0; + virtual void GetValuestring(char* str)=0; + Value GetValue() { return __value;} + std::string propname; + Value __value; + virtual ~Property(){ } +}; + +class Prop_int:public Property { +public: + Prop_int(const char* _propname, int _value):Property(_propname) { + __value._int=_value; + } + void SetValue(char* input); + void GetValuestring(char* str); + ~Prop_int(){ } +}; + +class Prop_bool:public Property { +public: + Prop_bool(const char* _propname, bool _value):Property(_propname) { + __value._bool=_value; + } + void SetValue(char* input); + void GetValuestring(char* str); + ~Prop_bool(){ } +}; + +class Prop_string:public Property{ +public: + Prop_string(const char* _propname, char* _value):Property(_propname) { + __value._string=new std::string(_value); + } + ~Prop_string(){ + delete __value._string; + } + void SetValue(char* input); + void GetValuestring(char* str); +}; +class Prop_hex:public Property { +public: + Prop_hex(const char* _propname, int _value):Property(_propname) { + __value._hex=_value; + } + void SetValue(char* input); + ~Prop_hex(){ } + void GetValuestring(char* str); +}; + +class Section { +public: + Section(const char* _sectionname) { sectionname=_sectionname; } + virtual ~Section(){ ExecuteDestroy();} + + typedef void (*SectionFunction)(Section*); + void AddInitFunction(SectionFunction func) {initfunctions.push_back(func);} + void AddDestroyFunction(SectionFunction func) {destroyfunctions.push_front(func);} + void ExecuteInit() { + typedef std::list::iterator func_it; + for (func_it tel=initfunctions.begin(); tel!=initfunctions.end(); tel++){ + (*tel)(this); + } + } + void ExecuteDestroy() { + typedef std::list::iterator func_it; + for (func_it tel=destroyfunctions.begin(); tel!=destroyfunctions.end(); tel++){ + (*tel)(this); + } + } + std::list initfunctions; + std::list destroyfunctions; + virtual void HandleInputline(char * _line){} + virtual void PrintData(FILE* outfile) {} + std::string sectionname; }; +class Section_prop:public Section { + public: + Section_prop(const char* _sectionname):Section(_sectionname){} -extern char dosbox_basedir[CROSS_LEN]; + void Add_int(const char* _propname, int _value=0); + void Add_string(const char* _propname, char* _value=NULL); + void Add_bool(const char* _propname, bool _value=false); + void Add_hex(const char* _propname, int _value=0); + + int Get_int(const char* _propname); + const char* Get_string(const char* _propname); + bool Get_bool(const char* _propname); + int Get_hex(const char* _propname); + void HandleInputline(char *gegevens); + void PrintData(FILE* outfile); + + std::list properties; + typedef std::list::iterator it; +}; + +class Section_line: public Section{ +public: + Section_line(const char* _sectionname):Section(_sectionname){} + void HandleInputline(char* gegevens); + void PrintData(FILE* outfile); + std::string data; +}; + +class Config{ +public: + Config(CommandLine * cmd){ cmdline=cmd;} + ~Config(); + CommandLine * cmdline; + + Section * AddSection(const char * _name,void (*_initfunction)(Section*)); + Section_line * AddSection_line(const char * _name,void (*_initfunction)(Section*)); + Section_prop * AddSection_prop(const char * _name,void (*_initfunction)(Section*)); + + Section* GetSection(const char* _sectionname); + + void SetStartUp(void (*_function)(void)); + void Init(); + void ShutDown(); + void StartUp(); + void PrintConfig(const char* configfilename); + void ParseConfigFile(const char* configfilename); + + std::list sectionlist; + typedef std::list::iterator it; + typedef std::list::reverse_iterator reverse_it; +private: + void (* _start_function)(void); +}; #endif diff --git a/include/support.h b/include/support.h index 00079ee..8857469 100644 --- a/include/support.h +++ b/include/support.h @@ -39,8 +39,6 @@ char *ltrim(char *str); void rtrim(char * const str); char *trim(char *str); -bool wildcmp(char *wild, char *string); - bool ScanCMDBool(char * cmd,char * check); char * ScanCMDRemain(char * cmd); bool ScanCMDHex(char * cmd,char * check,Bits * result); diff --git a/include/timer.h b/include/timer.h index a481d59..9c07747 100644 --- a/include/timer.h +++ b/include/timer.h @@ -19,9 +19,12 @@ #ifndef _TIMER_H_ #define _TIMER_H_ /* underlying clock rate in HZ */ -#include +#include extern Bit32u LastTicks; + +#define PIT_TICK_RATE 1193182 + #define GetTicks() SDL_GetTicks() typedef void (*TIMER_TickHandler)(Bitu ticks); @@ -48,6 +51,5 @@ void TIMER_CheckPIT(void); /* This will add ms ticks to support the timer handlers */ void TIMER_AddTicks(Bit32u ticks); - #endif diff --git a/include/video.h b/include/video.h index 2519949..f59d8ec 100644 --- a/include/video.h +++ b/include/video.h @@ -19,6 +19,7 @@ #ifndef __VIDEO_H #define __VIDEO_H + typedef void (GFX_DrawHandler)(Bit8u * vidstart); /* Used to reply to the renderer what size to set */ typedef void (GFX_ResizeHandler)(Bitu * width,Bitu * height); @@ -45,6 +46,5 @@ void GFX_Start(void); void GFX_Stop(void); void GFX_SwitchFullScreen(void); - #endif diff --git a/settings.h b/settings.h index b3933b3..81f3ec2 100644 --- a/settings.h +++ b/settings.h @@ -21,6 +21,7 @@ /* Enable the debugger, this only seems to work in win32 for now. */ #define C_DEBUG 0 +#define C_HEAVY_DEBUG 0 /* Enable the logging of extra information for debugging to the console */ #define C_LOGGING 0 @@ -48,16 +49,4 @@ #define DEBUG_DMA 0 /* DMA Debugging */ #define DEBUG_DOS 0 /* DOS Debugging */ -#define LOG_MSG S_Warn - -#if C_LOGGING -#define LOG_DEBUG S_Warn -#define LOG_WARN S_Warn -#define LOG_ERROR S_Warn -#else -#define LOG_DEBUG -#define LOG_WARN -#define LOG_ERROR -#endif - #endif diff --git a/src/Makefile.am b/src/Makefile.am index 0b960ea..151e5e0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,5 +6,5 @@ bin_PROGRAMS = dosbox dosbox_SOURCES = dosbox.cpp dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a hardware/libhardware.a gui/libgui.a \ - ints/libints.a misc/libmisc.a shell/libshell.a -lcurses -EXTRA_DIST = dosbox.lang \ No newline at end of file + ints/libints.a misc/libmisc.a shell/libshell.a -lcurses -lpng + diff --git a/src/Makefile.in b/src/Makefile.in index 0283c01..e7f9ea5 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -89,9 +89,8 @@ bin_PROGRAMS = dosbox dosbox_SOURCES = dosbox.cpp dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a hardware/libhardware.a gui/libgui.a \ - ints/libints.a misc/libmisc.a shell/libshell.a -lcurses + ints/libints.a misc/libmisc.a shell/libshell.a -lcurses -lpng -EXTRA_DIST = dosbox.lang subdir = src mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index d10d5e7..e583dc0 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -135,7 +135,7 @@ bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type) { return true; } -void CALLBACK_Init(void) { +void CALLBACK_Init(Section* sec) { Bitu i; for (i=0;i 0x9F) || flags.cf) { reg_al+=0x60; flags.cf=true; + } else { + flags.cf=false; } flags.sf=(reg_al>>7)>0; flags.zf=(reg_al==0); + //TODO Maybe parity flags.type=t_UNKNOWN; break; case 0x28: /* SUB Eb,Gb */ @@ -545,35 +547,11 @@ restart: } case 0x8d: /* LEA */ { - GetRMrw; - switch (rm & 0xC7) { - case 0x00:*rmrw=reg_bx+reg_si;break; - case 0x01:*rmrw=reg_bx+reg_di;break; - case 0x02:*rmrw=reg_bp+reg_si;break; - case 0x03:*rmrw=reg_bp+reg_di;break; - case 0x04:*rmrw=reg_si;break; - case 0x05:*rmrw=reg_di;break; - case 0x06:*rmrw=Fetchw();break; - case 0x07:*rmrw=reg_bx;break; - case 0x40:*rmrw=reg_bx+reg_si+Fetchbs();break; - case 0x41:*rmrw=reg_bx+reg_di+Fetchbs();break; - case 0x42:*rmrw=reg_bp+reg_si+Fetchbs();break; - case 0x43:*rmrw=reg_bp+reg_di+Fetchbs();break; - case 0x44:*rmrw=reg_si+Fetchbs();break; - case 0x45:*rmrw=reg_di+Fetchbs();break; - case 0x46:*rmrw=reg_bp+Fetchbs();break; - case 0x47:*rmrw=reg_bx+Fetchbs();break; - case 0x80:*rmrw=reg_bx+reg_si+Fetchw();break; - case 0x81:*rmrw=reg_bx+reg_di+Fetchw();break; - case 0x82:*rmrw=reg_bp+reg_si+Fetchw();break; - case 0x83:*rmrw=reg_bp+reg_di+Fetchw();break; - case 0x84:*rmrw=reg_si+Fetchw();break; - case 0x85:*rmrw=reg_di+Fetchw();break; - case 0x86:*rmrw=reg_bp+Fetchw();break; - case 0x87:*rmrw=reg_bx+Fetchw();break; - default: - E_Exit("CPU:8d:Illegal LEA RM Byte"); - } + prefix.segbase=0; + prefix.mark|=PREFIX_SEG; + lookupEATable=EAPrefixTable[prefix.mark]; + GetRMrw;GetEAa; + *rmrw=(Bit16u)eaa; break; } case 0x8e: /* MOV Sw,Ew */ @@ -880,7 +858,7 @@ restart: case 0xcc: /* INT3 */ INTERRUPT(3); #if C_DEBUG - return 0; + return 1; #endif break; case 0xcd: /* INT Ib */ @@ -888,7 +866,7 @@ restart: Bit8u num=Fetchb(); #if C_DEBUG SAVEIP; - if (DEBUG_IntBreakpoint(num)) return 0; + if (DEBUG_IntBreakpoint(num)) return 1; #endif INTERRUPT(num); } @@ -936,8 +914,8 @@ restart: reg_al = get_CF() ? 0xFF : 0; break; case 0xd7: /* XLAT */ - if (prefixes & PREFIX_SEG) { - reg_al=LoadMb(segprefix_base+(Bit16u)(reg_bx+reg_al)); + if (prefix.mark & PREFIX_SEG) { + reg_al=LoadMb(prefix.segbase+(Bit16u)(reg_bx+reg_al)); PrefixReset; } else { reg_al=LoadMb(SegBase(ds)+(Bit16u)(reg_bx+reg_al)); @@ -1042,174 +1020,15 @@ restart: LOG_ERROR("CPU:LOCK"); break; case 0xf1: /* Weird call undocumented */ +// INTERRUPT(1); E_Exit("CPU:F1:Not Handled"); break; case 0xf2: /* REPNZ */ - repcheck=false; - goto repstart; + count-=Repeat_Normal(false,false,count); + break; case 0xf3: /* REPZ */ - repcheck=true; - repstart: - { - EAPoint to=SegBase(es); - EAPoint from; - if (prefixes & PREFIX_SEG) { - from=(segprefix_base); - PrefixReset; - } else { - from=SegBase(ds); - } - Bit16s direct; - if (flags.df) direct=-1; - else direct=1; - reploop: - Bit8u repcode=Fetchb(); - switch (repcode) { - case 0x26: /* ES Prefix */ - from=SegBase(es); - goto reploop; - case 0x2e: /* CS Prefix */ - from=SegBase(cs); - goto reploop; - case 0x36: /* SS Prefix */ - from=SegBase(ss); - goto reploop; - case 0x3e: /* DS Prefix */ - from=SegBase(ds); - goto reploop; -#ifdef CPU_386 - case 0x66: - Rep_66(direct,from,to); - break; -#endif - - case 0x6c: /* REP INSB */ - { - for (Bit32u temp=reg_cx;temp>0;temp--) { - SaveMb(to,IO_Read(reg_dx)); - to+=direct; - }; - reg_di+=Bit16s(reg_cx*direct);reg_cx=0; - break; - } - case 0x6d: /* REP INSW */ - { - for (Bit32u temp=reg_cx;temp>0;temp--) { - SaveMb(to,IO_Read(reg_dx)); - SaveMb((to+1),IO_Read(reg_dx+1)); - to+=direct*2; - } - reg_di+=Bit16s(reg_cx*direct*2);reg_cx=0; - break; - } - case 0x6e: /* REP OUTSB */ - for (;reg_cx>0;reg_cx--) { - IO_Write(reg_dx,LoadMb(from+reg_si)); - reg_si+=direct; - } - break; - case 0x6f: /* REP OUTSW */ - for (;reg_cx>0;reg_cx--) { - IO_Write(reg_dx,LoadMb(from+reg_si)); - IO_Write(reg_dx+1,LoadMb(from+reg_si+1)); - reg_si+=direct*2; - } - break; - case 0xa4: /* REP MOVSB */ - for (;reg_cx>0;reg_cx--) { - SaveMb(to+reg_di,LoadMb(from+reg_si)); - reg_di+=direct; - reg_si+=direct; - } - break; - case 0xa5: /* REP MOVSW */ - for (;reg_cx>0;reg_cx--) { - SaveMw(to+reg_di,LoadMw(from+reg_si)); - reg_di+=direct*2; - reg_si+=direct*2; - } - break; - case 0xa6: /* REP CMPSB */ - if (!reg_cx) break; - for (;reg_cx>0;) { - reg_cx--; - if ((LoadMb(from+reg_si)==LoadMb(to+reg_di))!=repcheck) { - reg_di+=direct; - reg_si+=direct; - break; - } - reg_di+=direct; - reg_si+=direct; - } - CMPB(from+(reg_si-direct),LoadMb(to+(reg_di-direct)),LoadMb,0); - break; - case 0xa7: /* REP CMPSW */ - if (!reg_cx) break; - for (;reg_cx>0;) { - reg_cx--; - if ((LoadMw(from+reg_si)==LoadMw(to+reg_di))!=repcheck) { - reg_di+=direct*2; - reg_si+=direct*2; - break; - } - reg_di+=direct*2; - reg_si+=direct*2; - } - CMPW(from+(reg_si-direct*2),LoadMw(to+(reg_di-direct*2)),LoadMw,0); - break; - case 0xaa: /* REP STOSB */ - for (;reg_cx>0;reg_cx--) { - SaveMb(to+reg_di,reg_al); - reg_di+=direct; - } - break; - case 0xab: /* REP STOSW */ - for (;reg_cx>0;reg_cx--) { - SaveMw(to+reg_di,reg_ax); - reg_di+=direct*2; - } - break; - case 0xac: /* REP LODSB */ - for (;reg_cx>0;reg_cx--) { - reg_al=LoadMb(from+reg_si); - reg_si+=direct; - } - break; - case 0xad: /* REP LODSW */ - for (;reg_cx>0;reg_cx--) { - reg_ax=LoadMw(from+reg_si); - reg_si+=direct*2; - } - break; - case 0xae: /* REP SCASB */ - if (!reg_cx) break; - for (;reg_cx>0;) { - reg_cx--; - if ((reg_al==LoadMb(to+reg_di))!=repcheck) { - reg_di+=direct; - break; - } - reg_di+=direct; - } - CMPB(reg_al,LoadMb(to+(reg_di-direct)),LoadRb,0); - break; - case 0xaf: /* REP SCASW */ - if (!reg_cx) break; - for (;reg_cx>0;) { - reg_cx--; - if ((reg_ax==LoadMw(to+reg_di))!=repcheck) { - reg_di+=direct*2; - break; - } - reg_di+=direct*2; - } - CMPW(reg_ax,LoadMw(to+(reg_di-direct*2)),LoadRw,0); - break; - default: - E_Exit("Illegal REP prefix %2X",repcode); - } - break; - } + count-=Repeat_Normal(true,false,count); + break; case 0xf4: /* HLT */ break; case 0xf5: /* CMC */ @@ -1496,5 +1315,9 @@ restart: } break; } + default: + NOTDONE; + break; + } diff --git a/src/cpu/core_16/prefix_66.h b/src/cpu/core_16/prefix_66.h index d34ad4b..33c2aa5 100644 --- a/src/cpu/core_16/prefix_66.h +++ b/src/cpu/core_16/prefix_66.h @@ -24,7 +24,7 @@ switch(Fetchb()) { RMGdEd(ADDD);break; case 0x05: /* ADD EAX,Id */ EAXId(ADDD);break; - case 0x09: /* OR Ew,Gw */ + case 0x09: /* OR Ed,Gd */ RMEdGd(ORD);break; case 0x0b: /* OR Gd,Ed */ RMGdEd(ORD);break; @@ -69,8 +69,6 @@ switch(Fetchb()) { RMGdEd(CMPD);break; case 0x3d: /* CMP EAX,Id */ EAXId(CMPD);break; - - case 0x26: /* SEG ES: */ SegPrefix_66(es);break; case 0x2e: /* SEG CS: */ @@ -153,6 +151,10 @@ switch(Fetchb()) { break; case 0x68: /* PUSH Id */ Push_32(Fetchd());break; + case 0x64: /* SEG FS: */ + SegPrefix_66(fs);break; + case 0x65: /* SEG GS: */ + SegPrefix_66(gs);break; case 0x69: /* IMUL Gd,Ed,Id */ { GetRMrd; @@ -164,12 +166,21 @@ switch(Fetchb()) { if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {flags.cf=false;flags.of=false;} else {flags.cf=true;flags.of=true;} break; - }; - - - + } case 0x6a: /* PUSH Ib */ Push_32(Fetchbs());break; + case 0x6b: /* IMUL Gd,Ed,Ib */ + { + GetRMrd; + Bit64s res; + if (rm >= 0xc0 ) {GetEArd;res=(Bit64s)(*eards) * (Bit64s)Fetchbs();} + else {GetEAa;res=(Bit64s)LoadMds(eaa) * (Bit64s)Fetchbs();} + *rmrd=(Bit32s)(res); + flags.type=t_MUL; + if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {flags.cf=false;flags.of=false;} + else {flags.cf=true;flags.of=true;} + break; + } case 0x81: /* Grpl Ed,Id */ { GetRM; @@ -186,7 +197,7 @@ switch(Fetchb()) { case 0x38:CMPD(*eard,id,LoadRd,SaveRd);break; } } else { - GetEAa;Bit32u id=Fetchb(); + GetEAa;Bit32u id=Fetchd(); switch (rm & 0x38) { case 0x00:ADDD(eaa,id,LoadMd,SaveMd);break; case 0x08: ORD(eaa,id,LoadMd,SaveMd);break; @@ -232,14 +243,13 @@ switch(Fetchb()) { break; case 0x85: /* TEST Ed,Gd */ RMEdGd(TESTD);break; - case 0x8f: /* POP Ed */ - { - GetRM; - if (rm >= 0xc0 ) {GetEArd;*eard=Pop_32();} - else {GetEAa;SaveMd(eaa,Pop_32());} + case 0x87: /* XCHG Ev,Gv */ + { + GetRMrd;Bit32u oldrmrd=*rmrd; + if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;*eard=oldrmrd;} + else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,oldrmrd);} break; } - case 0x89: /* MOV Ed,Gd */ { GetRMrd; @@ -247,10 +257,6 @@ switch(Fetchb()) { else {GetEAa;SaveMd(eaa,*rmrd);} break; } - case 0x99: /* CDQ */ - if (reg_eax & 0x80000000) reg_edx=0xffffffff; - else reg_edx=0; - break; case 0x8b: /* MOV Gd,Ed */ { GetRMrd; @@ -261,6 +267,42 @@ switch(Fetchb()) { case 0x8c: LOG_WARN("CPU:66:8c looped back"); break; + case 0x8f: /* POP Ed */ + { + GetRM; + if (rm >= 0xc0 ) {GetEArd;*eard=Pop_32();} + else {GetEAa;SaveMd(eaa,Pop_32());} + break; + } + case 0x90: /* NOP */ + break; + case 0x91: /* XCHG CX,AX */ + { Bit32u temp=reg_eax;reg_eax=reg_ecx;reg_ecx=temp; } + break; + case 0x92: /* XCHG DX,AX */ + { Bit32u temp=reg_eax;reg_eax=reg_edx;reg_edx=temp; } + break; + case 0x93: /* XCHG BX,AX */ + { Bit32u temp=reg_eax;reg_eax=reg_ebx;reg_ebx=temp; } + break; + case 0x94: /* XCHG SP,AX */ + { Bit32u temp=reg_eax;reg_eax=reg_esp;reg_esp=temp; } + break; + case 0x95: /* XCHG BP,AX */ + { Bit32u temp=reg_eax;reg_eax=reg_ebp;reg_ebp=temp; } + break; + case 0x96: /* XCHG SI,AX */ + { Bit32u temp=reg_eax;reg_eax=reg_esi;reg_esi=temp; } + break; + case 0x97: /* XCHG DI,AX */ + { Bit32u temp=reg_eax;reg_eax=reg_edi;reg_edi=temp; } + break; + case 0x98: /* CWD */ + reg_eax=(Bit16s)reg_ax;break; + case 0x99: /* CDQ */ + if (reg_eax & 0x80000000) reg_edx=0xffffffff; + else reg_edx=0; + break; case 0x9c: /* PUSHFD */ { Bit32u pflags= @@ -296,6 +338,9 @@ switch(Fetchb()) { else { reg_si+=4;reg_di+=4;} } break; + case 0xa9: /* TEST EAX,Id */ + EAXId(TESTD); + break; case 0xab: /* STOSD */ { stringDI; @@ -349,6 +394,14 @@ switch(Fetchb()) { GRP2D(1);break; case 0xd3: /* GRP2 Ed,CL */ GRP2D(reg_cl);break; + case 0xf2: /* REPNZ */ + prefix.count++; + count-=Repeat_Normal(false,true,count); + break; + case 0xf3: /* REPZ */ + prefix.count++; + count-=Repeat_Normal(true,true,count); + break; case 0xf7: /* GRP3 Ed(,Id) */ { union { Bit64u u;Bit64s s;} temp; @@ -441,12 +494,12 @@ switch(Fetchb()) { { GetRM; switch (rm & 0x38) { - case 0x00: /* INC Ew */ + case 0x00: /* INC Ed */ flags.cf=get_CF();flags.type=t_INCd; if (rm >= 0xc0 ) {GetEArd;flags.result.d=*eard+=1;} else {GetEAa;flags.result.d=LoadMd(eaa)+1;SaveMd(eaa,flags.result.d);} break; - case 0x08: /* DEC Ew */ + case 0x08: /* DEC Ed */ flags.cf=get_CF();flags.type=t_DECd; if (rm >= 0xc0 ) {GetEArd;flags.result.d=*eard-=1;} else {GetEAa;flags.result.d=LoadMd(eaa)-1;SaveMd(eaa,flags.result.d);} diff --git a/src/cpu/core_16/prefix_66_of.h b/src/cpu/core_16/prefix_66_of.h index 676f000..c7b0f81 100644 --- a/src/cpu/core_16/prefix_66_of.h +++ b/src/cpu/core_16/prefix_66_of.h @@ -79,6 +79,8 @@ switch (Fetchb()) { if (flags.cf) *eard&=~mask; else *eard|=mask; break; + default: + E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38); } } else { GetEAa;Bit32u old=LoadMd(eaa); @@ -98,6 +100,8 @@ switch (Fetchb()) { else old|=mask; SaveMd(eaa,old); break; + default: + E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38); } } if (flags.type!=t_CF) flags.prev_type=flags.type; diff --git a/src/cpu/core_16/prefix_of.h b/src/cpu/core_16/prefix_of.h index 3decea1..3e3a4b4 100644 --- a/src/cpu/core_16/prefix_of.h +++ b/src/cpu/core_16/prefix_of.h @@ -314,6 +314,8 @@ switch(Fetchb()) { case 0x38: /* BTC */ *earw^=mask; break; + default: + E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38); } } else { GetEAa;Bit16u old=LoadMw(eaa); @@ -330,6 +332,8 @@ switch(Fetchb()) { case 0x38: /* BTC */ SaveMw(eaa,old ^ mask); break; + default: + E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38); } } if (flags.type!=t_CF) { flags.prev_type=flags.type;flags.type=t_CF; } diff --git a/src/cpu/core_16/support.h b/src/cpu/core_16/support.h index 095f585..ace3a10 100644 --- a/src/cpu/core_16/support.h +++ b/src/cpu/core_16/support.h @@ -88,8 +88,8 @@ static INLINE Bit32u Pop_32() { #define stringSI \ EAPoint from; \ - if (prefixes & PREFIX_SEG) { \ - from=(segprefix_base+reg_si); \ + if (prefix.mark & PREFIX_SEG) { \ + from=(prefix.segbase+reg_si); \ PrefixReset; \ } else { \ from=SegBase(ds)+reg_si; \ @@ -102,48 +102,265 @@ static INLINE Bit32u Pop_32() { #include "instructions.h" -static INLINE void Rep_66(Bit16s direct,EAPoint from,EAPoint to) { - bool again; - do { - again=false; - Bit8u repcode=Fetchb(); - switch (repcode) { - case 0x26: /* ES Prefix */ - again=true; - from=SegBase(es); - break; - case 0x2e: /* CS Prefix */ - again=true; - from=SegBase(cs); - break; - case 0x36: /* SS Prefix */ - again=true; - from=SegBase(ss); - break; - case 0x3e: /* DS Prefix */ - again=true; - from=SegBase(ds); - break; - case 0xa5: /* REP MOVSD */ - for (;reg_cx>0;reg_cx--) { - SaveMd(to+reg_di,LoadMd(from+reg_si)); - reg_di+=direct*4; - reg_si+=direct*4; - } - break; - case 0xab: /* REP STOSW */ - for (;reg_cx>0;reg_cx--) { - SaveMd(to+reg_di,reg_eax); - reg_di+=direct*4; - } - break; - default: - E_Exit("CPU:Opcode 66:Illegal REP prefix %2X",repcode); +static Bits Repeat_Normal(bool testz,bool prefix_66,Bits count_remain) { + + Bits count=count_remain; + PhysPt base_si,base_di; + + Bit16s direct; + if (flags.df) direct=-1; + else direct=1; + base_di=SegBase(es); +rep_again: + if (prefix.mark & PREFIX_SEG) { + base_si=(prefix.segbase); + } else { + base_si=SegBase(ds); + } + switch (Fetchb()) { + case 0x26: /* ES Prefix */ + prefix.segbase=SegBase(es); + prefix.mark|=PREFIX_SEG; + prefix.count++; + goto rep_again; + case 0x2e: /* CS Prefix */ + prefix.segbase=SegBase(cs); + prefix.mark|=PREFIX_SEG; + prefix.count++; + goto rep_again; + case 0x36: /* SS Prefix */ + prefix.segbase=SegBase(ss); + prefix.mark|=PREFIX_SEG; + prefix.count++; + goto rep_again; + case 0x3e: /* DS Prefix */ + prefix.segbase=SegBase(ds); + prefix.mark|=PREFIX_SEG; + prefix.count++; + goto rep_again; + case 0x66: /* Size Prefix */ + prefix.count++; + prefix_66=!prefix_66; + goto rep_again; + case 0x6c: /* REP INSB */ + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMb(base_di+reg_di,IO_Read(reg_dx)); + reg_di+=direct; } - } while (again); + if (reg_cx && count<=0) goto countzero; + break; + case 0x6d: /* REP INSW/D */ + if (prefix_66) { + direct*=4; + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMb(base_di+reg_di+0,IO_Read(reg_dx+0)); + SaveMb(base_di+reg_di+1,IO_Read(reg_dx+1)); + SaveMb(base_di+reg_di+2,IO_Read(reg_dx+2)); + SaveMb(base_di+reg_di+3,IO_Read(reg_dx+3)); + reg_di+=direct; + } + } else { + direct*=2; + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMb(base_di+reg_di+0,IO_Read(reg_dx+0)); + SaveMb(base_di+reg_di+1,IO_Read(reg_dx+1)); + reg_di+=direct; + } + } + if (reg_cx && count<=0) goto countzero; + break; + case 0x6e: /* REP OUTSB */ + for (;(reg_cx && count>0);reg_cx--,count--) { + IO_Write(reg_dx,LoadMb(base_si+reg_si)); + reg_si+=direct; + } + if (reg_cx && count<=0) goto countzero; + break; + case 0x6f: /* REP OUTSW/D */ + if (prefix_66) { + direct*=4; + for (;(reg_cx && count>0);reg_cx--,count--) { + IO_Write(reg_dx+0,LoadMb(base_si+reg_si+0)); + IO_Write(reg_dx+1,LoadMb(base_si+reg_si+1)); + IO_Write(reg_dx+2,LoadMb(base_si+reg_si+2)); + IO_Write(reg_dx+3,LoadMb(base_si+reg_si+3)); + reg_si+=direct; + } + } else { + direct*=2; + for (;(reg_cx && count>0);reg_cx--,count--) { + IO_Write(reg_dx+0,LoadMb(base_si+reg_si+0)); + IO_Write(reg_dx+1,LoadMb(base_si+reg_si+1)); + reg_si+=direct; + } + } + if (reg_cx && count<=0) goto countzero; + break; + case 0xa4: /* REP MOVSB */ + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMb(base_di+reg_di,LoadMb(base_si+reg_si)); + reg_si+=direct;reg_di+=direct; + } + if (reg_cx && count<=0) goto countzero; + break; + case 0xa5: /* REP MOVSW/D */ + if (prefix_66) { + direct*=4; + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMd(base_di+reg_di,LoadMd(base_si+reg_si)); + reg_si+=direct;reg_di+=direct; + } + } else { + direct*=2; + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMw(base_di+reg_di,LoadMw(base_si+reg_si)); + reg_si+=direct;reg_di+=direct; + } + } + if (reg_cx && count<=0) goto countzero; + break; + case 0xa6: /* REP CMPSB */ + { + if (!reg_cx) goto stopit;Bit8u op1,op2; + for (;(reg_cx && count>0);) { + op1=LoadMb(base_si+reg_si);op2=LoadMb(base_di+reg_di); + reg_cx--,count--;reg_si+=direct;reg_di+=direct; + if ((op1==op2)!=testz) break; + } + CMPB(op1,op2,LoadRb,0); + if ((op1==op2)!=testz) goto stopit; + if (reg_cx && count<=0) goto countzero; + } + break; + case 0xa7: /* REP CMPSW */ + { + if (!reg_cx) goto stopit; + if (prefix_66) { + direct*=4; + Bit32u op1,op2; + for (;(reg_cx && count>0);) { + op1=LoadMd(base_si+reg_si);op2=LoadMd(base_di+reg_di); + reg_cx--,count--;reg_si+=direct;reg_di+=direct; + if ((op1==op2)!=testz) break; + } + CMPD(op1,op2,LoadRd,0); + if ((op1==op2)!=testz) goto stopit; + } else { + direct*=2; + Bit16u op1,op2; + for (;(reg_cx && count>0);) { + op1=LoadMw(base_si+reg_si);op2=LoadMw(base_di+reg_di); + reg_cx--,count--;reg_si+=direct;reg_di+=direct; + if ((op1==op2)!=testz) break; + } + CMPW(op1,op2,LoadRw,0); + if ((op1==op2)!=testz) goto stopit; + } + if (reg_cx && count<=0) goto countzero; + } + break; + case 0xaa: /* REP STOSB */ + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMb(base_di+reg_di,reg_al); + reg_di+=direct; + } + if (reg_cx && count<=0) goto countzero; + break; + case 0xab: /* REP STOSW */ + if (prefix_66) { + direct*=4; + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMd(base_di+reg_di,reg_eax); + reg_di+=direct; + } + } else { + direct*=2; + for (;(reg_cx && count>0);reg_cx--,count--) { + SaveMw(base_di+reg_di,reg_ax); + reg_di+=direct; + } + } + if (reg_cx && count<=0) goto countzero; + break; + case 0xac: /* REP LODSB */ + for (;(reg_cx && count>0);reg_cx--,count--) { + reg_al=LoadMb(base_si+reg_si); + reg_si+=direct; + } + if (reg_cx && count<=0) goto countzero; + break; + case 0xad: /* REP LODSW */ + if (prefix_66) { + direct*=4; + for (;(reg_cx && count>0);reg_cx--,count--) { + reg_eax=LoadMd(base_si+reg_si); + reg_si+=direct; + } + } else { + direct*=2; + for (;(reg_cx && count>0);reg_cx--,count--) { + reg_ax=LoadMw(base_si+reg_si); + reg_si+=direct; + } + } + if (reg_cx && count<=0) goto countzero; + break; + case 0xae: /* REP SCASB */ + { + if (!reg_cx) goto stopit;Bit8u op2; + for (;(reg_cx && count>0);) { + op2=LoadMb(base_di+reg_di); + reg_cx--,count--;reg_di+=direct; + if ((reg_al==op2)!=testz) break; + } + CMPB(reg_al,op2,LoadRb,0); + if ((reg_al==op2)!=testz) goto stopit; + if (reg_cx && count<=0) goto countzero; + } + break; + case 0xaf: /* REP SCASW */ + { + if (!reg_cx) goto stopit; + if (prefix_66) { + direct*=4; + Bit32u op2; + for (;(reg_cx && count>0);) { + op2=LoadMd(base_di+reg_di); + reg_cx--,count--;reg_di+=direct; + if ((reg_eax==op2)!=testz) break; + } + CMPD(reg_eax,op2,LoadRd,0); + if ((reg_eax==op2)!=testz) goto stopit; + } else { + direct*=2; + Bit16u op2; + for (;(reg_cx && count>0);) { + op2=LoadMw(base_di+reg_di); + reg_cx--,count--;reg_di+=direct; + if ((reg_ax==op2)!=testz) break; + } + CMPW(reg_ax,op2,LoadRw,0); + if ((reg_ax==op2)!=testz) goto stopit; + } + if (reg_cx && count<=0) goto countzero; + } + break; + default: + IPPoint--; + LOG_DEBUG("Unhandled REP Prefix %X",Fetchb()); + + } +stopit: + PrefixReset; + return count_remain-count; +countzero: + IPPoint-=(prefix.count+2); /* Rep instruction and whatever string instruction */ + PrefixReset; + return count_remain; } //flags.io and nt shouldn't be compiled for 386 +#ifdef CPU_386 #define Save_Flagsw(FLAGW) \ { \ flags.type=t_UNKNOWN; \ @@ -159,7 +376,25 @@ static INLINE void Rep_66(Bit16s direct,EAPoint from,EAPoint to) { PIC_runIRQs(); \ LOADIP; \ } \ - if (flags.tf) E_Exit("CPU:Trap Flag not supported"); \ + if (flags.tf) LOG_DEBUG("CPU:Trap Flag not supported"); \ } +#else +#define Save_Flagsw(FLAGW) \ +{ \ + flags.type=t_UNKNOWN; \ + flags.cf =(FLAGW & 0x001)>0;flags.pf =(FLAGW & 0x004)>0; \ + flags.af =(FLAGW & 0x010)>0;flags.zf =(FLAGW & 0x040)>0; \ + flags.sf =(FLAGW & 0x080)>0;flags.tf =(FLAGW & 0x100)>0; \ + flags.intf =(FLAGW & 0x200)>0; \ + flags.df =(FLAGW & 0x400)>0;flags.of =(FLAGW & 0x800)>0; \ + if (flags.intf && PIC_IRQCheck) { \ + SAVEIP; \ + PIC_runIRQs(); \ + LOADIP; \ + } \ + if (flags.tf) LOG_DEBUG("CPU:Trap Flag not supported"); \ +} + +#endif diff --git a/src/cpu/core_16/table_ea.h b/src/cpu/core_16/table_ea.h index c697269..48fd12a 100644 --- a/src/cpu/core_16/table_ea.h +++ b/src/cpu/core_16/table_ea.h @@ -26,38 +26,56 @@ static GetEATable * lookupEATable; #define PREFIX_ADDR 0x2 #define PREFIX_SEG_ADDR 0x3 - -static Bitu prefixes; -static EAPoint segprefix_base; +static struct { + Bitu mark; + Bitu count; + EAPoint segbase; +} prefix; /* Gets initialized at the bottem, can't seem to declare forward references */ static GetEATable * EAPrefixTable[4]; - #define SegPrefix(blah) \ - segprefix_base=SegBase(blah); \ - prefixes|=PREFIX_SEG; \ - lookupEATable=EAPrefixTable[prefixes]; \ - goto restart; \ + prefix.segbase=SegBase(blah); \ + prefix.mark|=PREFIX_SEG; \ + prefix.count++; \ + lookupEATable=EAPrefixTable[prefix.mark]; \ + goto restart; #define SegPrefix_66(blah) \ - segprefix_base=SegBase(blah); \ - prefixes|=PREFIX_SEG; \ - lookupEATable=EAPrefixTable[prefixes]; \ - goto restart_66; \ + prefix.segbase=SegBase(blah); \ + prefix.mark|=PREFIX_SEG; \ + prefix.count++; \ + lookupEATable=EAPrefixTable[prefix.mark]; \ + goto restart_66; -#define PrefixReset \ - prefixes=PREFIX_NONE;lookupEATable=EAPrefixTable[PREFIX_NONE]; +#define PrefixReset \ + prefix.mark=PREFIX_NONE; \ + prefix.count=0; \ + lookupEATable=EAPrefixTable[PREFIX_NONE]; + +#if 1 #define GetEADirect \ -EAPoint eaa;switch (prefixes) { \ +EAPoint eaa;switch (prefix.mark) { \ case PREFIX_NONE:eaa=SegBase(ds)+Fetchw();break; \ -case PREFIX_SEG:eaa=segprefix_base+Fetchw();PrefixReset;break; \ +case PREFIX_SEG:eaa=prefix.segbase+Fetchw();PrefixReset;break; \ case PREFIX_ADDR:eaa=SegBase(ds)+Fetchd();PrefixReset;break; \ -case PREFIX_SEG_ADDR:eaa=segprefix_base+Fetchd();PrefixReset;break; \ +case PREFIX_SEG_ADDR:eaa=prefix.segbase+Fetchd();PrefixReset;break; \ } +#else + +#define GetEADirect \ +EAPoint eaa; \ +if (!prefix.mark) { eaa=SegBase(ds)+Fetchw();} \ +else if (prefix.mark == PREFIX_SEG) { eaa=prefix.segbase+Fetchw();PrefixReset;} \ +else if (prefix.mark == PREFIX_ADDR) { eaa=SegBase(ds)+Fetchd();PrefixReset;} \ +else if (prefix.mark == PREFIX_SEG_ADDR) { eaa=prefix.segbase+Fetchd();PrefixReset;} + +#endif + @@ -125,7 +143,7 @@ static GetEATable GetEA_16_n={ }; -#define segprefixed(val) EAPoint ret=segprefix_base+val;PrefixReset;return ret; +#define segprefixed(val) EAPoint ret=prefix.segbase+val;PrefixReset;return ret; static EAPoint EA_16_00_s(void) { segprefixed((Bit16u)(reg_bx+(Bit16s)reg_si)) } static EAPoint EA_16_01_s(void) { segprefixed((Bit16u)(reg_bx+(Bit16s)reg_di)) } @@ -189,6 +207,8 @@ static GetEATable GetEA_16_s={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static Bit32u SIBZero=0; +static Bit32u * SIBIndex[8]= { ®_eax,®_ecx,®_edx,®_ebx,&SIBZero,®_ebp,®_esi,®_edi }; INLINE EAPoint Sib(Bitu mode) { Bit8u sib=Fetchb(); @@ -203,7 +223,7 @@ INLINE EAPoint Sib(Bitu mode) { case 3: /* EBX Base */ base=SegBase(ds)+reg_ebx;break; case 4: /* ESP Base */ - base=SegBase(ds)+reg_esp;break; + base=SegBase(ss)+reg_esp;break; case 5: /* #1 Base */ if (!mode) { base=SegBase(ds)+Fetchd();break; @@ -215,25 +235,7 @@ INLINE EAPoint Sib(Bitu mode) { case 7: /* EDI Base */ base=SegBase(ds)+reg_edi;break; } - Bitu shift=sib >> 6; - switch ((sib >>3) &7) { - case 0: /* EAX Index */ - base+=(Bit32s)reg_eax<> 3) &7] << (sib >> 6); return base; }; @@ -305,50 +307,31 @@ INLINE EAPoint Sib_s(Bitu mode) { EAPoint base; switch (sib&7) { case 0: /* EAX Base */ - base=segprefix_base+reg_eax;break; + base=prefix.segbase+reg_eax;break; case 1: /* ECX Base */ - base=segprefix_base+reg_ecx;break; + base=prefix.segbase+reg_ecx;break; case 2: /* EDX Base */ - base=segprefix_base+reg_edx;break; + base=prefix.segbase+reg_edx;break; case 3: /* EBX Base */ - base=segprefix_base+reg_ebx;break; + base=prefix.segbase+reg_ebx;break; case 4: /* ESP Base */ - base=segprefix_base+reg_esp;break; + base=prefix.segbase+reg_esp;break; case 5: /* #1 Base */ if (!mode) { - base=segprefix_base+Fetchd();break; + base=prefix.segbase+Fetchd();break; } else { - base=segprefix_base+reg_ebp;break; + base=prefix.segbase+reg_ebp;break; } case 6: /* ESI Base */ - base=segprefix_base+reg_esi;break; + base=prefix.segbase+reg_esi;break; case 7: /* EDI Base */ - base=segprefix_base+reg_edi;break; + base=prefix.segbase+reg_edi;break; } - Bitu shift=sib >> 6; - switch ((sib >>3) &7) { - case 0: /* EAX Index */ - base+=(Bit32s)reg_eax<> 3) &7] << (sib >> 6); PrefixReset; return base; }; -#define segprefixed_32(val) EAPoint ret=segprefix_base+(Bit32u)(val);PrefixReset;return ret; +#define segprefixed_32(val) EAPoint ret=prefix.segbase+(Bit32u)(val);PrefixReset;return ret; static EAPoint EA_32_00_s(void) { segprefixed_32(reg_eax); } static EAPoint EA_32_01_s(void) { segprefixed_32(reg_ecx); } diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index fbebd89..51090e1 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -21,6 +21,7 @@ #include "memory.h" #include "debug.h" #include "keyboard.h" +#include "setup.h" //Regs regs; @@ -28,27 +29,22 @@ Flag_Info flags; CPU_Regs cpu_regs; - - Segment Segs[6]; -Bit32u cpu_cycles; +Bitu cpu_cycles; CPU_Decoder * cpudecoder; - static void CPU_CycleIncrease(void) { - Bit32u old_cycles=cpu_cycles; - cpu_cycles=(Bit32u)(cpu_cycles*1.2); + Bitu old_cycles=cpu_cycles; + cpu_cycles=(Bitu)(cpu_cycles*1.2); if (cpu_cycles==old_cycles) cpu_cycles++; LOG_MSG("CPU:%d cycles",cpu_cycles); - } static void CPU_CycleDecrease(void) { - cpu_cycles=(Bit32u)(cpu_cycles/1.2); + cpu_cycles=(Bitu)(cpu_cycles/1.2); if (!cpu_cycles) cpu_cycles=1; LOG_MSG("CPU:%d cycles",cpu_cycles); - } Bit8u lastint; @@ -87,7 +83,7 @@ void Interrupt(Bit8u num) { E_Exit("Call to interrupt 0xCD this is BAD"); case 0x03: #if C_DEBUG - if (DEBUG_BreakPoint()) return; + if (DEBUG_Breakpoint()) return; #endif break; case 0x05: @@ -137,7 +133,8 @@ void SetCPU16bit() } -void CPU_Init(void) { +void CPU_Init(Section* sec) { + Section_prop * section=static_cast(sec); reg_eax=0; reg_ebx=0; reg_ecx=0; @@ -166,11 +163,13 @@ void CPU_Init(void) { flags.io=0; SetCPU16bit(); - cpu_cycles=2000; + cpu_cycles=section->Get_int("cycles"); + if (!cpu_cycles) cpu_cycles=300; KEYBOARD_AddEvent(KBD_f11,CTRL_PRESSED,CPU_CycleDecrease); KEYBOARD_AddEvent(KBD_f12,CTRL_PRESSED,CPU_CycleIncrease); reg_al=0; reg_ah=0; + MSG_Add("CPU_CONFIGFILE_HELP","The amount of cycles to execute each loop. Lowering this setting will slowdown dosbox\n"); } diff --git a/src/cpu/slow_16.cpp b/src/cpu/slow_16.cpp index c8d9a2d..0bf3d76 100644 --- a/src/cpu/slow_16.cpp +++ b/src/cpu/slow_16.cpp @@ -61,20 +61,24 @@ extern Bitu cycle_count; #include "core_16/support.h" static Bitu CPU_Real_16_Slow_Decode_Special(Bitu count); -static Bitu CPU_Real_16_Slow_Decode(Bitu count) { + +static Bitu CPU_Real_16_Slow_Decode(Bits count) { #include "core_16/start.h" - while (count) { + do { #if C_DEBUG cycle_count++; #endif - count--; +#if C_HEAVY_DEBUG + SAVEIP; + if (DEBUG_HeavyIsBreakpoint()) return CBRET_NONE; +#endif #include "core_16/main.h" - } + } while (--count>0); #include "core_16/stop.h" return CBRET_NONE; } -static Bitu CPU_Real_16_Slow_Decode_Special(Bitu count) { +static Bitu CPU_Real_16_Slow_Decode_Special(Bits count) { while (count>0) { if (flags.tf) { Interrupt(3); diff --git a/src/debug/debug.cpp b/src/debug/debug.cpp index fdb66ac..29c0dbe 100644 --- a/src/debug/debug.cpp +++ b/src/debug/debug.cpp @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "programs.h" #include #include @@ -32,16 +33,27 @@ #include "inout.h" #include "mixer.h" #include "debug_inc.h" +#include "timer.h" +#include "..\shell\shell_inc.h" #ifdef WIN32 void WIN32_Console(); #endif +// Forwards +static void DrawCode(void); +static bool DEBUG_Log_Loop(int count); +static void DEBUG_RaiseTimerIrq(void); +class DEBUG; + +DEBUG* pDebugcom = 0; +bool exitLoop = false; + static struct { Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip; } oldregs; -static void DrawCode(void); + static Segment oldsegs[6]; static Flag_Info oldflags; @@ -77,127 +89,318 @@ static Bit16u dataSeg,dataOfs; /* Breakpoint stuff */ /********************/ -enum { BKPNT_REALMODE, BKPNT_PHYSICAL, BKPNT_INTERRUPT }; +bool skipFirstInstruction = false; + +enum EBreakpoint { BKPNT_UNKNOWN, BKPNT_PHYSICAL, BKPNT_INTERRUPT }; #define BPINT_ALL 0x100 -typedef struct SBreakPoint { - PhysPt location; - Bit8u olddata; - Bit8u type; - Bit16u ahValue; - Bit16u segment; - Bit32u offset; - bool once; - bool enabled; - bool active; -} TBreakpoint; - -static std::list BPoints; - -static bool IsBreakpoint(PhysPt off) +class CBreakpoint { - // iterate list and remove TBreakpoint - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - if (((*i).type==BKPNT_PHYSICAL) && ((*i).location==off)) return true; - } - return false; +public: + CBreakpoint (void) { location = 0; active = once = false; segment = 0; offset = 0; intNr = 0; ahValue = 0; type = BKPNT_UNKNOWN; }; + + void SetAddress (Bit16u seg, Bit32u off) { location = PhysMake(seg,off); type = BKPNT_PHYSICAL; segment = seg; offset = off; }; + void SetAddress (PhysPt adr) { location = adr; type = BKPNT_PHYSICAL; }; + void SetInt (Bit8u _intNr, Bit16u ah) { intNr = _intNr, ahValue = ah; type = BKPNT_INTERRUPT; }; + void SetOnce (bool _once) { once = _once; }; + + bool IsActive (void) { return active; }; + void Activate (bool _active); + + EBreakpoint GetType (void) { return type; }; + bool GetOnce (void) { return once; }; + PhysPt GetLocation (void) { if (GetType()==BKPNT_PHYSICAL) return location; else return 0; }; + Bit16u GetSegment (void) { return segment; }; + Bit32u GetOffset (void) { return offset; }; + Bit8u GetIntNr (void) { if (GetType()==BKPNT_INTERRUPT) return intNr; else return 0; }; + Bit16u GetValue (void) { if (GetType()==BKPNT_INTERRUPT) return ahValue; else return 0; }; + + // statics + static CBreakpoint* AddBreakpoint (Bit16u seg, Bit32u off, bool once); + static CBreakpoint* AddIntBreakpoint (Bit8u intNum, Bit16u ah, bool once); + static void ActivateBreakpoints (PhysPt adr, bool activate); + static bool CheckBreakpoint (PhysPt adr); + static bool CheckIntBreakpoint (PhysPt adr, Bit8u intNr, Bit16u ahValue); + static bool IsBreakpoint (PhysPt where); + static bool IsBreakpointDrawn (PhysPt where); + static bool DeleteBreakpoint (PhysPt where); + static bool DeleteByIndex (Bit16u index); + static void DeleteAll (void); + static void ShowList (void); + + +private: + EBreakpoint type; + // Physical + PhysPt location; + Bit8u oldData; + Bit16u segment; + Bit32u offset; + // Int + Bit8u intNr; + Bit16u ahValue; + // Shared + bool active; + bool once; + + static std::list BPoints; + static CBreakpoint* ignoreOnce; }; -/* This clears all breakpoints by replacing their 0xcc by the original byte */ -static void ClearBreakpoints(void) +void CBreakpoint::Activate(bool _active) { - // iterate list and place 0xCC - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - if (((*i).type==BKPNT_PHYSICAL) && (*i).active) { - if (mem_readb((*i).location)==0xCC) mem_writeb((*i).location,(*i).olddata); - (*i).active = false; - }; - } -} - -static void DeleteBreakpoint(PhysPt off) -{ - // iterate list and place 0xCC - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - if (((*i).type==BKPNT_PHYSICAL) && (off==(*i).location)) { - if ((*i).active && (mem_readb((*i).location)==0xCC)) mem_writeb((*i).location,(*i).olddata); - (BPoints.erase)(i); - break; - }; - } -} - -static void SetBreakpoints(void) -{ - // iterate list and place 0xCC - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - if (((*i).type==BKPNT_PHYSICAL) && (*i).enabled) { - Bit8u data = mem_readb((*i).location); + if (GetType()==BKPNT_PHYSICAL) { +#if !C_HEAVY_DEBUG + if (_active) { + // Set 0xCC and save old value + Bit8u data = mem_readb(location); if (data!=0xCC) { - (*i).olddata = data; - (*i).active = true; - mem_writeb((*i).location,0xCC); - } - }; + oldData = data; + mem_writeb(location,0xCC); + }; + } else { + // Remove 0xCC and set old value + if (mem_readb (location)==0xCC) { + mem_writeb(location,oldData); + }; + } +#endif } -} - -static void AddBreakpoint(Bit16u seg, Bit32u ofs, bool once) -{ - TBreakpoint bp; - bp.type = BKPNT_PHYSICAL; - bp.enabled = true; - bp.active = false; - bp.location = PhysMake(seg,ofs); - bp.segment = seg; - bp.offset = ofs; - bp.once = once; - BPoints.push_front(bp); -} - -static void AddIntBreakpoint(Bit8u intNum, Bit16u ah, bool once) -{ - TBreakpoint bp; - bp.type = BKPNT_INTERRUPT; - bp.olddata = intNum; - bp.ahValue = ah; - bp.enabled = true; - bp.active = true; - bp.once = once; - BPoints.push_front(bp); + active = _active; }; -static bool RemoveBreakpoint(PhysPt off) +// Statics +std::list CBreakpoint::BPoints; +CBreakpoint* CBreakpoint::ignoreOnce = 0; + +CBreakpoint* CBreakpoint::AddBreakpoint(Bit16u seg, Bit32u off, bool once) { - // iterate list and remove TBreakpoint - std::list::iterator i; + CBreakpoint* bp = new CBreakpoint(); + bp->SetAddress (seg,off); + bp->SetOnce (once); + BPoints.push_front (bp); + return bp; +}; + +CBreakpoint* CBreakpoint::AddIntBreakpoint(Bit8u intNum, Bit16u ah, bool once) +{ + CBreakpoint* bp = new CBreakpoint(); + bp->SetInt (intNum,ah); + bp->SetOnce (once); + BPoints.push_front (bp); + return bp; +}; + +void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate) +{ + ignoreOnce = 0; + // activate all breakpoints + std::list::iterator i; + CBreakpoint* bp; for(i=BPoints.begin(); i != BPoints.end(); i++) { - if (((*i).type==BKPNT_PHYSICAL) && ((*i).location==off)) { - TBreakpoint* bp = &(*i); - if ((*i).active && (mem_readb((*i).location)==0xCC)) mem_writeb((*i).location,(*i).olddata); - (*i).active = false; - if ((*i).once) (BPoints.erase)(i); - + bp = static_cast(*i); + // Do not activate, when bp is an actual adress + if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { + ignoreOnce = bp; + continue; + } + bp->Activate(activate); + }; +}; + +bool CBreakpoint::CheckBreakpoint(PhysPt adr) +// Checks if breakpoint is valid an should stop execution +{ + // if breakpoint is same address as started, it's not valid... + if (ignoreOnce) { + ignoreOnce->Activate(true); + ignoreOnce = 0; + } + // Search matching breakpoint + std::list::iterator i; + CBreakpoint* bp; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + bp = static_cast(*i); + if ((bp->GetType()==BKPNT_PHYSICAL) && bp->IsActive() && (bp->GetLocation()==adr)) { + // Found, + if (bp->GetOnce()) { + // delete it, if it should only be used once + (BPoints.erase)(i); + bp->Activate(false); + delete bp; + } return true; }; - } + }; return false; }; +bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue) +// Checks if interrupt breakpoint is valid an should stop execution +{ + // if breakpoint is same address as started, it's not valid... + if (ignoreOnce) { + ignoreOnce->Activate(true); + ignoreOnce = 0; + } + // Search matching breakpoint + std::list::iterator i; + CBreakpoint* bp; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + bp = static_cast(*i); + if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) { + if ((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) { + // Found + if (bp->GetOnce()) { + // delete it, if it should only be used once + (BPoints.erase)(i); + bp->Activate(false); + delete bp; + } + return true; + } + }; + }; + return false; +}; + +void CBreakpoint::DeleteAll() +{ + std::list::iterator i; + CBreakpoint* bp; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + bp = static_cast(*i); + bp->Activate(false); + delete bp; + }; + (BPoints.clear)(); +}; + + +bool CBreakpoint::DeleteByIndex(Bit16u index) +{ + // Search matching breakpoint + int nr = 0; + std::list::iterator i; + CBreakpoint* bp; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + if (nr==index) { + bp = static_cast(*i); + (BPoints.erase)(i); + bp->Activate(false); + delete bp; + return true; + } + }; + return false; +}; + +bool CBreakpoint::DeleteBreakpoint(PhysPt where) +{ + // Search matching breakpoint + int nr = 0; + std::list::iterator i; + CBreakpoint* bp; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + bp = static_cast(*i); + if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==where)) { + (BPoints.erase)(i); + bp->Activate(false); + delete bp; + return true; + } + }; + return false; +}; + +bool CBreakpoint::IsBreakpoint(PhysPt adr) +// is there a breakpoint at address ? +{ + // Search matching breakpoint + std::list::iterator i; + CBreakpoint* bp; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + bp = static_cast(*i); + if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { + return true; + }; + }; + return false; +}; + +bool CBreakpoint::IsBreakpointDrawn(PhysPt adr) +// valid breakpoint, that should be drawn ? +{ + // Search matching breakpoint + std::list::iterator i; + CBreakpoint* bp; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + bp = static_cast(*i); + if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { + // Only draw, if breakpoint is not only once, + return !bp->GetOnce(); + }; + }; + return false; +}; + +void CBreakpoint::ShowList(void) +{ + // iterate list + int nr = 0; + std::list::iterator i; + for(i=BPoints.begin(); i != BPoints.end(); i++) { + CBreakpoint* bp = static_cast(*i); + if (bp->GetType()==BKPNT_PHYSICAL) { + PhysPt adr = bp->GetLocation(); + + wprintw(dbg.win_out,"%02X. BP %04X:%04X\n",nr,bp->GetSegment(),bp->GetOffset); + nr++; + } else if (bp->GetType()==BKPNT_INTERRUPT) { + if (bp->GetValue()==BPINT_ALL) wprintw(dbg.win_out,"%02X. BPINT %02X\n",nr,bp->GetIntNr()); + else wprintw(dbg.win_out,"%02X. BPINT %02X AH=%02X\n",nr,bp->GetIntNr(),bp->GetValue()); + nr++; + }; + } + wrefresh(dbg.win_out); +}; + +bool DEBUG_Breakpoint(void) +{ + /* First get the phyiscal address and check for a set Breakpoint */ + PhysPt where=SegPhys(cs)+reg_eip-1; + if (!CBreakpoint::CheckBreakpoint(where)) return false; + // Found. Breakpoint is valid + reg_eip -= 1; + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,false); // Deactivate all breakpoints + exitLoop = true; + DEBUG_Enable(); + return true; +}; + +bool DEBUG_IntBreakpoint(Bit8u intNum) +{ + /* First get the phyiscal address and check for a set Breakpoint */ + PhysPt where=SegPhys(cs)+reg_eip-2; + if (!CBreakpoint::CheckIntBreakpoint(where,intNum,reg_ah)) return false; + // Found. Breakpoint is valid + reg_eip -= 2; + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,false); // Deactivate all breakpoints + exitLoop = true; + DEBUG_Enable(); + return true; +}; + static bool StepOver() { PhysPt start=Segs[cs].phys+reg_eip; char dline[200];Bitu size; size=DasmI386(dline, start, reg_eip, false); - if (strstr(dline,"call") || strstr(dline,"int")) { - AddBreakpoint (SegValue(cs),reg_eip+size, true); - SetBreakpoints(); + if (strstr(dline,"call") || strstr(dline,"int") || strstr(dline,"loop") || strstr(dline,"rep")) { + CBreakpoint::AddBreakpoint (SegValue(cs),reg_eip+size, true); + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip, true); debugging=false; DrawCode(); DOSBOX_SetNormalLoop(); @@ -206,56 +409,13 @@ static bool StepOver() return false; }; -bool DEBUG_BreakPoint(void) { - /* First get the phyiscal address and check for a set TBreakpoint */ - PhysPt where=SegPhys(cs)+reg_eip-1; - bool found = false; - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); ++i) { - if ((*i).active && (*i).enabled) { - if ((*i).location==where) { - found=true; - break; - } - } - } - if (!found) return false; - RemoveBreakpoint(where); - ClearBreakpoints(); - reg_eip -= 1; - DEBUG_Enable(); - return true; -} - -bool DEBUG_IntBreakpoint(Bit8u intNum) +bool DEBUG_ExitLoop(void) { - PhysPt where=SegPhys(cs)+reg_eip-2; - bool found=false; - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); ++i) { - if ( ((*i).type==BKPNT_INTERRUPT) && (*i).enabled) { - if (((*i).olddata==intNum) && ( ((*i).ahValue==(Bit16u)reg_ah) || ((*i).ahValue==BPINT_ALL)) ) { - if ((*i).active) { - found=true; - (*i).active=false; - //(BPoints.erase)(i); - //break; - } else { - // One step over is ok -> activate for next occurence - (*i).active=true; - //break; - } - } - } + if (exitLoop) { + exitLoop = false; + return true; } - if (!found) return false; - - // Remove normal breakpoint here, cos otherwise 0xCC wont be removed here - RemoveBreakpoint(where); - ClearBreakpoints(); - reg_eip -= 2; - DEBUG_Enable(); - return true; + return false; }; /********************/ @@ -338,7 +498,7 @@ static void DrawCode(void) wattrset(dbg.win_code,COLOR_PAIR(PAIR_BLACK_GREY)); codeViewData.cursorSeg = codeViewData.useCS; codeViewData.cursorOfs = disEIP; - } else if (IsBreakpoint(start)) { + } else if (CBreakpoint::IsBreakpointDrawn(start)) { wattrset(dbg.win_code,COLOR_PAIR(PAIR_GREY_RED)); } else { wattrset(dbg.win_code,0); @@ -440,7 +600,7 @@ bool ParseCommand(char* str) found+=3; Bit16u seg = GetHexValue(found,found);found++; // skip ":" Bit32u ofs = GetHexValue(found,found); - AddBreakpoint(seg,ofs,false); + CBreakpoint::AddBreakpoint(seg,ofs,false); LOG_DEBUG("DEBUG: Set breakpoint at %04X:%04X",seg,ofs); return true; } @@ -450,10 +610,10 @@ bool ParseCommand(char* str) Bit8u intNr = GetHexValue(found,found); found++; Bit8u valAH = GetHexValue(found,found); if ((valAH==0x00) && (*found=='*')) { - AddIntBreakpoint(intNr,BPINT_ALL,false); + CBreakpoint::AddIntBreakpoint(intNr,BPINT_ALL,false); LOG_DEBUG("DEBUG: Set interrupt breakpoint at INT %02X",intNr); } else { - AddIntBreakpoint(intNr,valAH,false); + CBreakpoint::AddIntBreakpoint(intNr,valAH,false); LOG_DEBUG("DEBUG: Set interrupt breakpoint at INT %02X AH=%02X",intNr,valAH); } return true; @@ -463,19 +623,7 @@ bool ParseCommand(char* str) wprintw(dbg.win_out,"Breakpoint list:\n"); wprintw(dbg.win_out,"-------------------------------------------------------------------------\n"); Bit32u nr = 0; - // iterate list - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - if ((*i).type==BKPNT_PHYSICAL) { - wprintw(dbg.win_out,"%02X. BP %04X:%04X\n",nr,(*i).segment,(*i).offset); - nr++; - } else if ((*i).type==BKPNT_INTERRUPT) { - if ((*i).ahValue==BPINT_ALL) wprintw(dbg.win_out,"%02X. BPINT %02X\n",nr,(*i).olddata); - else wprintw(dbg.win_out,"%02X. BPINT %02X AH=%02X\n",nr,(*i).olddata,(*i).ahValue); - nr++; - }; - } - wrefresh(dbg.win_out); + CBreakpoint::ShowList(); return true; }; @@ -484,29 +632,11 @@ bool ParseCommand(char* str) found+=5; Bit8u bpNr = GetHexValue(found,found); if ((bpNr==0x00) && (*found=='*')) { // Delete all - (BPoints.clear)(); + CBreakpoint::DeleteAll(); LOG_DEBUG("DEBUG: Breakpoints deleted."); } else { // delete single breakpoint - Bit16u nr = 0; - std::list::iterator i; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - if ((*i).type==BKPNT_PHYSICAL) { - if (nr==bpNr) { - DeleteBreakpoint((*i).location); - LOG_DEBUG("DEBUG: Breakpoint %02X deleted.",nr); - break; - } - nr++; - } else if ((*i).type==BKPNT_INTERRUPT) { - if (nr==bpNr) { - (BPoints.erase)(i); - LOG_DEBUG("DEBUG: Breakpoint %02X. deleted.",nr); - break;; - } - nr++; - } - } + CBreakpoint::DeleteByIndex(bpNr); } return true; } @@ -528,6 +658,36 @@ bool ParseCommand(char* str) LOG_DEBUG("DEBUG: Set data overview to %04X:%04X",dataSeg,dataOfs); return true; } + found = strstr(str,"LOG "); + if (found) { // Create Cpu log file + found+=4; + LOG_DEBUG("DEBUG: Starting log"); + DEBUG_Log_Loop(GetHexValue(found,found)); + LOG_DEBUG("DEBUG: Logfile LOGCPU.TXT created."); + return true; + } + found = strstr(str,"INTT "); + if (found) { // Create Cpu log file + found+=4; + Bit8u intNr = GetHexValue(found,found); + LOG_DEBUG("DEBUG: Tracing INT %02X",intNr); + Interrupt(intNr); + SetCodeWinStart(); + return true; + } + found = strstr(str,"INT "); + if (found) { // Create Cpu log file + found+=4; + Bit8u intNr = GetHexValue(found,found); + LOG_DEBUG("DEBUG: Starting INT %02X",intNr); + CBreakpoint::AddBreakpoint (SegValue(cs),reg_eip, true); + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip-1,true); + debugging=false; + DrawCode(); + DOSBOX_SetNormalLoop(); + Interrupt(intNr); + return true; + } if ((*str=='H') || (*str=='?')) { wprintw(dbg.win_out,"Debugger keys:\n"); wprintw(dbg.win_out,"--------------------------------------------------------------------------\n"); @@ -538,7 +698,6 @@ bool ParseCommand(char* str) wprintw(dbg.win_out,"Return - Enable command line input\n"); wprintw(dbg.win_out,"D/E/S/X/B - Set data view to DS:SI/ES:DI/SS:SP/DS:DX/ES:BX\n"); wprintw(dbg.win_out,"R/F - Scroll data view\n"); - wprintw(dbg.win_out,"\n"); wprintw(dbg.win_out,"Debugger commands (enter all values in hex or as register):\n"); wprintw(dbg.win_out,"--------------------------------------------------------------------------\n"); wprintw(dbg.win_out,"BP [segment]:[offset] - Set breakpoint\n"); @@ -547,6 +706,8 @@ bool ParseCommand(char* str) wprintw(dbg.win_out,"BPLIST - List breakpoints\n"); wprintw(dbg.win_out,"BPDEL [bpNr] / * - Delete breakpoint nr / all\n"); wprintw(dbg.win_out,"C / D [segment]:[offset] - Set code / data view address\n"); + wprintw(dbg.win_out,"INT [nr] / INTT [nr] - Execute / Trace into Iinterrupt\n"); + wprintw(dbg.win_out,"LOG [num] - Write cpu log file\n"); wprintw(dbg.win_out,"H - Help\n"); wrefresh(dbg.win_out); return TRUE; @@ -621,6 +782,9 @@ Bit32u DEBUG_CheckKeys(void) { case 'H' : strcpy(codeViewData.inputStr,"H "); ParseCommand(codeViewData.inputStr); break; + case 'T' : DEBUG_RaiseTimerIrq(); + LOG_DEBUG("Debug: Timer Int started."); + break; case 0x0A : // Return : input codeViewData.inputMode = true; @@ -636,23 +800,25 @@ Bit32u DEBUG_CheckKeys(void) { break; case KEY_F(5): // Run Programm debugging=false; - SetBreakpoints(); + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); DOSBOX_SetNormalLoop(); break; case KEY_F(9): // Set/Remove TBreakpoint { PhysPt ptr = PhysMake(codeViewData.cursorSeg,codeViewData.cursorOfs); - if (IsBreakpoint(ptr)) DeleteBreakpoint(ptr); - else AddBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs, false); + if (CBreakpoint::IsBreakpoint(ptr)) CBreakpoint::DeleteBreakpoint(ptr); + else CBreakpoint::AddBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs, false); } break; case KEY_F(10): // Step over inst if (StepOver()) return 0; else { + skipFirstInstruction = true; // for heavy debugger Bitu ret=(*cpudecoder)(1); SetCodeWinStart(); } break; case KEY_F(11): // trace into + skipFirstInstruction = true; // for heavy debugger ret = (*cpudecoder)(1); SetCodeWinStart(); break; @@ -675,8 +841,8 @@ Bitu DEBUG_Loop(void) { Bit32u oldEIP = reg_eip; PIC_runIRQs(); if ((oldCS!=SegValue(cs)) || (oldEIP!=reg_eip)) { - AddBreakpoint(oldCS,oldEIP,true); - SetBreakpoints(); + CBreakpoint::AddBreakpoint(oldCS,oldEIP,true); + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); debugging=false; DOSBOX_SetNormalLoop(); return 0; @@ -686,13 +852,13 @@ Bitu DEBUG_Loop(void) { } void DEBUG_Enable(void) { + debugging=true; SetCodeWinStart(); DEBUG_DrawScreen(); DOSBOX_SetLoop(&DEBUG_Loop); } - void DEBUG_DrawScreen(void) { DrawRegisters(); DrawData(); @@ -702,24 +868,142 @@ static void DEBUG_RaiseTimerIrq(void) { PIC_ActivateIRQ(0); } -void DEBUG_Init(void) { +static bool DEBUG_Log_Loop(int count) { + + char buffer[512]; + getcwd(buffer,512); + + FILE* f = fopen("LOGCPU.TXT","wt"); + if (!f) return false; + + do { +// PIC_runIRQs(); + + Bitu ret; + do { + // Get disasm + Bit16u csValue = SegValue(cs); + Bit32u eipValue = reg_eip; + PhysPt start=Segs[cs].phys+reg_eip; + char dline[200];Bitu size; + size = DasmI386(dline, start, reg_eip, false); + Bitu len = strlen(dline); + if (len<30) for (Bitu i=0; i<30-len; i++) strcat(dline," "); + + PIC_IRQAgain=false; + ret=(*cpudecoder)(1); + + // Get register values + char buffer[512]; + sprintf(buffer,"%04X:%08X %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X\n",csValue,eipValue,dline,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(ds),SegValue(es),SegValue(fs),SegValue(gs),SegValue(ss),get_CF(),get_ZF(),get_SF(),get_OF(),get_AF(),get_PF()); + fprintf(f,"%s",buffer); + count--; + if (count==0) break; + + } while (!ret && PIC_IRQAgain); + if (ret) break; + } while (count>0); + + fclose(f); + return true; +} + +// DEBUG.COM stuff + +class DEBUG : public Program { +public: + DEBUG() { pDebugcom = this; active = false; }; + ~DEBUG() { pDebugcom = 0; }; + + bool IsActive() { return active; }; + + void Run(void) + { + char filename[128]; + char args[128]; + cmd->FindCommand(1,temp_line); + strncpy(filename,temp_line.c_str(),128); + cmd->FindCommand(2,temp_line); + strncpy(args,temp_line.c_str(),128); + // Start new shell and execute prog + active = true; + DOS_Shell shell; + shell.Execute(filename,args); + }; + +private: + bool active; +}; + +void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off) +{ + if (pDebugcom && pDebugcom->IsActive()) { + CBreakpoint::AddBreakpoint(seg,off,true); + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); + pDebugcom = 0; + }; +}; + +static void DEBUG_ProgramStart(Program * * make) { + *make=new DEBUG; +} + +// INIT + +void DEBUG_SetupConsole(void) +{ #ifdef WIN32 WIN32_Console(); - #endif + #endif memset((void *)&dbg,0,sizeof(dbg)); debugging=false; dbg.active_win=3; input_count=0; /* Start the Debug Gui */ DBGUI_StartUp(); +}; + +static void DEBUG_ShutDown(Section * sec) +{ + CBreakpoint::DeleteAll(); +}; + +void DEBUG_Init(Section* sec) { + + MSG_Add("DEBUG_CONFIGFILE_HELP","Nothing to setup yet!\n"); DEBUG_DrawScreen(); /* Add some keyhandlers */ KEYBOARD_AddEvent(KBD_kpminus,0,DEBUG_Enable); KEYBOARD_AddEvent(KBD_kpplus,0,DEBUG_RaiseTimerIrq); /* Clear the TBreakpoint list */ memset((void*)&codeViewData,0,sizeof(codeViewData)); - (BPoints.clear)(); + /* setup debug.com */ + PROGRAMS_MakeFile("DEBUG.COM",DEBUG_ProgramStart); + /* shutdown function */ + sec->AddDestroyFunction(&DEBUG_ShutDown); } -#endif +// HEAVY DEBUGGING STUFF + +#if C_HEAVY_DEBUG + +bool DEBUG_HeavyIsBreakpoint(void) +{ + if (skipFirstInstruction) { + skipFirstInstruction = false; + return false; + } + + PhysPt where = SegPhys(cs)+reg_eip; + if (CBreakpoint::CheckBreakpoint(where)) { + exitLoop = true; + DEBUG_Enable(); + return true; + }; + return false; +}; + +#endif // HEAVY DEBUG + +#endif // DEBUG diff --git a/src/debug/debug_gui.cpp b/src/debug/debug_gui.cpp index dadc282..43d8d30 100644 --- a/src/debug/debug_gui.cpp +++ b/src/debug/debug_gui.cpp @@ -34,7 +34,6 @@ void DEBUG_ShowMsg(char * msg) { char buf[1024]; strcpy(buf,msg); - strcat(buf,"\n"); waddstr(dbg.win_out,buf); wprintw(dbg.win_out," %d\n",cycle_count); diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index c334de4..35533f6 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -29,19 +29,17 @@ #include "dos_inc.h" DOS_Block dos; -DOS_InfoBlock dosInfoBlock; +DOS_InfoBlock dos_infoblock; -static Bit8u dos_copybuf[0x10000]; -static Bitu call_20,call_21,call_theend; +Bit8u dos_copybuf[0x10000]; +static Bitu call_20,call_21; void DOS_SetError(Bit16u code) { dos.errorcode=code; -}; - +} #define DOSNAMEBUF 256 static Bitu DOS_21Handler(void) { -//TODO KEYBOARD Check for break char name1[DOSNAMEBUF+1]; char name2[DOSNAMEBUF+1]; switch (reg_ah) { @@ -151,7 +149,7 @@ static Bitu DOS_21Handler(void) { } break; default: - LOG_ERROR("DOS:0C:Illegal Flush STDIN Buffer call %d",reg_al); +// LOG_ERROR("DOS:0C:Illegal Flush STDIN Buffer call %d",reg_al); break; } } @@ -166,14 +164,13 @@ static Bitu DOS_21Handler(void) { reg_al=26; break; case 0x0f: /* Open File using FCB */ - if(DOS_FCBOpen(SegValue(ds),reg_dx)){ + if(DOS_FCBOpenCreate(SegValue(ds),reg_dx)){ reg_al=0; }else{ reg_al=0xff; } LOG_DEBUG("DOS:0x0f FCB-fileopen used, result:al=%d",reg_al); break; - case 0x10: /* Close File using FCB */ if(DOS_FCBClose(SegValue(ds),reg_dx)){ reg_al=0; @@ -182,7 +179,6 @@ static Bitu DOS_21Handler(void) { } LOG_DEBUG("DOS:0x10 FCB-fileclose used, result:al=%d",reg_al); break; - case 0x11: /* Find First Matching File using FCB */ if(DOS_FCBFindFirst(SegValue(ds),reg_dx)){ reg_al=0; @@ -191,7 +187,6 @@ static Bitu DOS_21Handler(void) { } LOG_DEBUG("DOS:0x11 FCB-FindFirst used, result:al=%d",reg_al); break; - case 0x12: /* Find Next Matching File using FCB */ if(DOS_FCBFindNext(SegValue(ds),reg_dx)){ reg_al=0; @@ -200,23 +195,59 @@ static Bitu DOS_21Handler(void) { } LOG_DEBUG("DOS:0x12 FCB-FindNext used, result:al=%d",reg_al); break; - case 0x13: /* Delete File using FCB */ - case 0x14: /* Sequential read from FCB */ - case 0x15: /* Sequential write to FCB */ - case 0x16: /* Create or truncate file using FCB */ - case 0x17: /* Rename file using FCB */ - case 0x21: /* Read random record from FCB */ - case 0x22: /* Write random record to FCB */ - case 0x23: /* Get file size for FCB */ - case 0x24: /* Set Random Record number for FCB */ - case 0x27: /* Random block read from FCB */ - case 0x28: /* Random Block read to FCB */ - LOG_ERROR("DOS:Unhandled call %02X, FCB Stuff",reg_ah); - reg_al=0xff; /* FCB Calls FAIL */ - //CALLBACK_SCF(true); not needed. + if (DOS_FCBDeleteFile(SegValue(ds),reg_dx)) reg_al = 0x00; + else reg_al = 0xFF; + break; + case 0x14: /* Sequential read from FCB */ + reg_al = DOS_FCBRead(SegValue(ds),reg_dx,0); + LOG_DEBUG("DOS:0x14 FCB-Read used, result:al=%d",reg_al); + break; + case 0x15: /* Sequential write to FCB */ + if (DOS_FCBWrite(SegValue(ds),reg_dx,0)) reg_al = 0x00; + else reg_al = 0x01; + LOG_DEBUG("DOS:0x15 FCB-Write used, result:al=%d",reg_al); + break; + case 0x16: /* Create or truncate file using FCB */ + if (DOS_FCBOpenCreate(SegValue(ds),reg_dx)) reg_al = 0x00; + else reg_al = 0x01; + LOG_DEBUG("DOS:0x16 FCB-Create used, result:al=%d",reg_al); + break; + case 0x17: /* Rename file using FCB */ + if (DOS_FCBRenameFile(SegValue(ds),reg_dx)) reg_al = 0x00; + else reg_al = 0xFF; + break; + case 0x1b: /* Get allocation info for default drive */ + if (!DOS_GetAllocationInfo(0,®_cx,®_ax,®_dx)) reg_al=0xff; + break; + case 0x1c: /* Get allocation info for specific drive */ + if (!DOS_GetAllocationInfo(reg_dl,®_cx,®_ax,®_dx)) reg_al=0xff; + break; + case 0x21: /* Read random record from FCB */ + reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,1,true); + LOG_DEBUG("DOS:0x21 FCB-Random read used, result:al=%d",reg_al); + break; + case 0x22: /* Write random record to FCB */ + if (DOS_FCBRandomWrite(SegValue(ds),reg_dx,1,true)) reg_al = 0x00; + else reg_al = 0x01; + LOG_DEBUG("DOS:0x28 FCB-Random write used, result:al=%d",reg_al); + break; + case 0x23: /* Get file size for FCB */ + if (DOS_FCBGetFileSize(SegValue(ds),reg_dx,reg_cx)) reg_al = 0x00; + else reg_al = 0xFF; + break; + case 0x24: /* Set Random Record number for FCB */ + DOS_FCBSetRandomRecord(SegValue(ds),reg_dx); + break; + case 0x27: /* Random block read from FCB */ + reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,reg_cx,false); + LOG_DEBUG("DOS:0x27 FCB-Random read used, result:al=%d",reg_al); + break; + case 0x28: /* Random Block write to FCB */ + if (DOS_FCBRandomWrite(SegValue(ds),reg_dx,reg_cx,false)) reg_al = 0x00; + else reg_al = 0x01; + LOG_DEBUG("DOS:0x28 FCB-Random write used, result:al=%d",reg_al); break; - case 0x29: /* Parse filename into FCB */ { Bit8u difference; char string[1024]; @@ -226,7 +257,6 @@ static Bitu DOS_21Handler(void) { } LOG_DEBUG("DOS:29:FCB Parse Filename, result:al=%d",reg_al); break; - case 0x18: /* NULL Function for CP/M compatibility or Extended rename FCB */ case 0x1d: /* NULL Function for CP/M compatibility or Extended rename FCB */ case 0x1e: /* NULL Function for CP/M compatibility or Extended rename FCB */ @@ -239,26 +269,11 @@ static Bitu DOS_21Handler(void) { reg_al=DOS_GetDefaultDrive(); break; case 0x1a: /* Set Disk Transfer Area Address */ - dos.dta=RealMakeSeg(ds,reg_dx); - break; - - case 0x1c: /* Get allocation info for specific drive */ - LOG_DEBUG("DOS: Allocation Info call not supported correctly"); - SegSet16(ds,0xf000); - reg_bx=0; - real_writeb(0xf000,0,0); - reg_al=0x7f; - reg_cx=0x200; - reg_dx=0x1000; - break; /* TODO maybe but hardly think a game needs this */ - case 0x1b: /* Get allocation info for default drive */ - LOG_DEBUG("DOS: Allocation Info call not supported correctly"); - SegSet16(ds,0xf000); - reg_bx=0; - real_writeb(0xf000,0,0); - reg_al=0x7f; - reg_cx=0x200; - reg_dx=0x1000; + { + dos.dta=RealMakeSeg(ds,reg_dx); + DOS_PSP psp(dos.psp); + psp.SetDTA(dos.dta); + } break; case 0x1f: /* Get drive parameter block for default drive */ case 0x32: /* Get drive parameter block for specific drive */ @@ -268,7 +283,7 @@ static Bitu DOS_21Handler(void) { RealSetVec(reg_al,RealMakeSeg(ds,reg_dx)); break; case 0x26: /* Create new PSP */ - DOS_NewPSP(reg_dx); + DOS_NewPSP(reg_dx,DOS_PSP(dos.psp).GetSize()); break; case 0x2a: /* Get System Date */ reg_al=0; /* It's always sunday TODO find that correct formula */ @@ -444,6 +459,7 @@ static Bitu DOS_21Handler(void) { case 0x3f: /* READ Read from file or device */ { Bit16u toread=reg_cx; + if (reg_cx+reg_dx>0xffff) LOG_DEBUG("DOS:READ:Buffer overflow %d",reg_cx+reg_dx); if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) { MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread); reg_ax=toread; @@ -457,6 +473,7 @@ static Bitu DOS_21Handler(void) { case 0x40: /* WRITE Write to file or device */ { Bit16u towrite=reg_cx; + if (reg_cx+reg_dx>0xffff) LOG_DEBUG("DOS:WRITE:Buffer overflow %d",reg_cx+reg_dx); MEM_BlockRead(SegPhys(ds)+reg_dx,dos_copybuf,towrite); if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) { reg_ax=towrite; @@ -490,7 +507,6 @@ static Bitu DOS_21Handler(void) { break; } case 0x43: /* Get/Set file attributes */ -//TODO FIX THIS HACK MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); switch (reg_al) case 0x00: /* Get */ @@ -511,7 +527,7 @@ static Bitu DOS_21Handler(void) { } break; case 0x44: /* IOCTL Functions */ - if (DOS_IOCTL(reg_al,reg_bx)) { + if (DOS_IOCTL()) { CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; @@ -535,7 +551,6 @@ static Bitu DOS_21Handler(void) { } break; case 0x47: /* CWD Get current directory */ - //TODO Memory if (DOS_GetCurrentDir(reg_dl,name1)) { MEM_BlockWrite(SegPhys(ds)+reg_si,name1,strlen(name1)+1); reg_ax=0x0100; @@ -581,9 +596,8 @@ static Bitu DOS_21Handler(void) { case 0x4b: /* EXEC Load and/or execute program */ { MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); - if (DOS_Execute(name1,(ParamBlock *)Phys2Host(SegPhys(es)+reg_bx),reg_al)) { - CALLBACK_SCF(false); - } else { + LOG_DEBUG("Execute %s %d",name1,reg_al); + if (!DOS_Execute(name1,SegPhys(es)+reg_bx,reg_al)) { reg_ax=dos.errorcode; CALLBACK_SCF(true); } @@ -593,9 +607,7 @@ static Bitu DOS_21Handler(void) { case 0x4c: /* EXIT Terminate with return code */ { if (DOS_Terminate(false)) { - dos.return_code=reg_al; - dos.return_mode=RETURN_EXIT; - CALLBACK_SCF(false); + /* This can't ever return false normally */ } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); @@ -609,7 +621,8 @@ static Bitu DOS_21Handler(void) { case 0x4e: /* FINDFIRST Find first matching file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); if (DOS_FindFirst(name1,reg_cx)) { - CALLBACK_SCF(false); + CALLBACK_SCF(false); + reg_ax=0; /* Undocumented */ } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); @@ -617,7 +630,8 @@ static Bitu DOS_21Handler(void) { break; case 0x4f: /* FINDNEXT Find next matching file */ if (DOS_FindNext()) { - CALLBACK_SCF(false); + CALLBACK_SCF(false); + reg_ax=0xffff; /* Undocumented */ } else { reg_ax=dos.errorcode; CALLBACK_SCF(true); @@ -630,9 +644,9 @@ static Bitu DOS_21Handler(void) { reg_bx=dos.psp; break; case 0x52: { /* Get list of lists */ - Bit16u seg; - dosInfoBlock.GetDIBPointer(seg,reg_bx); - SegSet16(es,seg); + RealPt addr=dos_infoblock.GetPointer(); + SegSet16(es,RealSeg(addr)); + reg_bx=RealOff(addr); LOG_DEBUG("Call is made for list of lists - let's hope for the best"); break; } //TODO Think hard how shit this is gonna be @@ -640,9 +654,12 @@ static Bitu DOS_21Handler(void) { case 0x53: /* Translate BIOS parameter block to drive parameter block */ //YEAH RIGHT case 0x54: /* Get verify flag */ - case 0x55: /* Create Child PSP*/ E_Exit("Unhandled Dos 21 call %02X",reg_ah); break; + case 0x55: /* Create Child PSP*/ + DOS_NewPSP(reg_dx,reg_si); + dos.psp = reg_dx; + break; case 0x56: /* RENAME Rename file */ MEM_StrCopy(SegPhys(ds)+reg_dx,name1,DOSNAMEBUF); MEM_StrCopy(SegPhys(es)+reg_di,name2,DOSNAMEBUF); @@ -654,12 +671,28 @@ static Bitu DOS_21Handler(void) { } break; case 0x57: /* Get/Set File's Date and Time */ - reg_cx=0; - reg_dx=0; - LOG_DEBUG("DOS:57:Getting/Setting File Date is faked",reg_ah); + if (reg_al==0x00) { + if (DOS_GetFileDate(reg_bx,®_cx,®_dx)) { + CALLBACK_SCF(false); + } else { + CALLBACK_SCF(true); + }; + } else { + reg_cx=0; + reg_dx=0; + LOG_DEBUG("DOS:57:Setting File Date is faked",reg_ah); + } break; case 0x58: /* Get/Set Memory allocation strategy */ - LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation"); + switch (reg_al) { + case 0: /* Get Strategy */ + reg_ax=0; //Low memory first fit + break; + case 1: /* Set Strategy */ + break; + default: + LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al); + } break; case 0x59: /* Get Extended error information */ reg_ax=dos.errorcode; @@ -805,7 +838,8 @@ static Bitu DOS_20Handler(void) { } -void DOS_Init(void) { +void DOS_Init(Section* sec) { + MSG_Add("DOS_CONFIGFILE_HELP","Setting a memory size to 0 will disable it.\n"); call_20=CALLBACK_Allocate(); CALLBACK_Setup(call_20,DOS_20Handler,CB_IRET); RealSetVec(0x20,CALLBACK_RealPointer(call_20)); @@ -816,8 +850,8 @@ void DOS_Init(void) { DOS_SetupFiles(); /* Setup system File tables */ DOS_SetupDevices(); /* Setup dos devices */ - DOS_SetupMemory(); /* Setup first MCB */ DOS_SetupTables(); + DOS_SetupMemory(); /* Setup first MCB */ DOS_SetupPrograms(); DOS_SetupMisc(); /* Some additional dos interrupts */ DOS_SetDefaultDrive(25); diff --git a/src/dos/dos_classes.cpp b/src/dos/dos_classes.cpp index 04cd8a3..3f1c729 100644 --- a/src/dos/dos_classes.cpp +++ b/src/dos/dos_classes.cpp @@ -29,122 +29,73 @@ dos work a bit easier. */ -#pragma pack (1) -struct sPSP { - Bit8u exit[2]; /* CP/M-like exit poimt */ - Bit16u next_seg; /* Segment of first byte beyond memory allocated or program */ - Bit8u fill_1; /* single char fill */ +void DOS_ParamBlock::Clear(void) { + memset(&exec,0,sizeof(exec)); + memset(&overlay,0,sizeof(overlay)); +} -/* CPM Stuff dunno what this is*/ -//TODO Add some checks for people using this i think - Bit8u far_call; /* far call opcode */ - RealPt cpm_entry; /* CPM Service Request address*/ - RealPt int_22; /* Terminate Address */ - RealPt int_23; /* Break Address */ - RealPt int_24; /* Critical Error Address */ - Bit16u psp_parent; /* Parent PSP Segment */ - Bit8u files[20]; /* File Table - 0xff is unused */ - Bit16u environment; /* Segment of evironment table */ - RealPt stack; /* SS:SP Save point for int 0x21 calls */ - Bit16u max_files; /* Maximum open files */ - RealPt file_table; /* Pointer to File Table PSP:0x18 */ - RealPt prev_psp; /* Pointer to previous PSP */ - RealPt dta; /* Pointer to current Process DTA */ - Bit8u fill_2[16]; /* Lot's of unused stuff i can't care aboue */ - Bit8u service[3]; /* INT 0x21 Service call int 0x21;retf; */ - Bit8u fill_3[45]; /* This has some blocks with FCB info */ - CommandTail cmdtail; -} GCC_ATTRIBUTE(packed); +void DOS_ParamBlock::LoadData(void) { + exec.envseg=sGet(sExec,envseg); + exec.cmdtail=sGet(sExec,cmdtail); + exec.fcb1=sGet(sExec,fcb1); + exec.fcb2=sGet(sExec,fcb2); + exec.initsssp=sGet(sExec,initsssp); + exec.initcsip=sGet(sExec,initcsip); + overlay.loadseg=sGet(sOverlay,loadseg); + overlay.relocation=sGet(sOverlay,relocation); +} -union sParamBlock { - struct { - Bit16u loadseg; - Bit16u relocation; - } overlay; - struct { - Bit16u envseg; - RealPt cmdtail; - RealPt fcb1; - RealPt fcb2; - RealPt initsssp; - RealPt initcsip; - } exec; -} GCC_ATTRIBUTE(packed); - -struct sFCB { - Bit8u drive; //0 is current drive. when opened 0 is replaced by drivenumber - Bit8u filename[8]; //spacepadded to fit - Bit8u ext[3]; //spacepadded to fit - Bit16u current_block; // set to 0 by open - Bit16u record_size; // used by reads Set to 80h by OPEN function - Bit32u filesize; //in bytes In this field, the first word is the low-order part of the size - Bit16u date; - Bit16u time; - Bit8u reserved[8]; - Bit8u current_relative_record_number; //open doesn't set this - Bit32u rel_record; //open does not handle this -} GCC_ATTRIBUTE(packed); - -#pragma pack () - -#define sGet(s,m) GetIt(((s *)0)->m,(PhysPt)&(((s *)0)->m)) -#define sSave(s,m,val) SaveIt(((s *)0)->m,(PhysPt)&(((s *)0)->m),val) +void DOS_ParamBlock::SaveData(void) { + sSave(sExec,envseg,exec.envseg); + sSave(sExec,cmdtail,exec.cmdtail); + sSave(sExec,fcb1,exec.fcb1); + sSave(sExec,fcb2,exec.fcb2); + sSave(sExec,initsssp,exec.initsssp); + sSave(sExec,initcsip,exec.initcsip); +} -class MemStruct { -public: - Bit8u GetIt(Bit8u,PhysPt addr) { - return mem_readb(pt+addr); - }; - Bit16u GetIt(Bit16u,PhysPt addr) { - return mem_readw(pt+addr); - }; - Bit32u GetIt(Bit32u,PhysPt addr) { - return mem_readd(pt+addr); - }; - void SaveIt(Bit8u,PhysPt addr,Bit8u val) { - mem_writeb(pt+addr,val); - }; - void SaveIt(Bit16u,PhysPt addr,Bit16u val) { - mem_writew(pt+addr,val); - }; - void SaveIt(Bit32u,PhysPt addr,Bit32u val) { - mem_writed(pt+addr,val); - }; - +void DOS_InfoBlock::SetLocation(Bit16u segment) +{ + seg = segment; + pt=PhysMake(seg,0); +/* Clear the initual Block */ + for(Bitu i=0;i=sGet(sPSP,max_files)) return 0xff; PhysPt files=Real2Phys(sGet(sPSP,file_table)); return mem_readb(files+index); }; -#define FCB_EXTENDED (mem_readb(off)==0xFF ? 7:0) - -void DOS_FCB::Set_drive(Bit8u a){ - mem_writeb(off+offsetof(sFCB,drive)+FCB_EXTENDED,a); -} -void DOS_FCB::Set_filename(char * a){ - MEM_BlockWrite(off+offsetof(sFCB,filename)+FCB_EXTENDED,a,8); -} -void DOS_FCB::Set_ext(char * a) { - MEM_BlockWrite(off+offsetof(sFCB,ext)+FCB_EXTENDED,a,3); -} -void DOS_FCB::Set_current_block(Bit16u a){ - mem_writew(off+offsetof(sFCB,current_block)+FCB_EXTENDED,a); -} -void DOS_FCB::Set_record_size(Bit16u a){ - mem_writew(off+offsetof(sFCB,record_size)+FCB_EXTENDED,a); -} -void DOS_FCB::Set_filesize(Bit32u a){ - mem_writed(off+offsetof(sFCB,filesize)+FCB_EXTENDED,a); -} -void DOS_FCB::Set_date(Bit16u a){ - mem_writew(off+offsetof(sFCB,date)+FCB_EXTENDED,a); -} -void DOS_FCB::Set_time(Bit16u a){ - mem_writew(off+offsetof(sFCB,time)+FCB_EXTENDED,a); -} -Bit8u DOS_FCB::Get_drive(void){ - return mem_readb(off+offsetof(sFCB,drive)+FCB_EXTENDED); -} -void DOS_FCB::Get_filename(char * a){ - MEM_BlockRead(off+offsetof(sFCB,filename)+FCB_EXTENDED,a,8); -} -void DOS_FCB::Get_ext(char * a){ - MEM_BlockRead(off+offsetof(sFCB,ext)+FCB_EXTENDED,a,3); -} -Bit16u DOS_FCB::Get_current_block(void){ - return mem_readw(off+offsetof(sFCB,current_block)+FCB_EXTENDED); -} -Bit16u DOS_FCB::Get_record_size(void){ - return mem_readw(off+offsetof(sFCB,record_size)+FCB_EXTENDED); -} -Bit32u DOS_FCB::Get_filesize(void){ - return mem_readd(off+offsetof(sFCB,filesize)+FCB_EXTENDED); -} -Bit16u DOS_FCB::Get_date(void){ - return mem_readw(off+offsetof(sFCB,date)+FCB_EXTENDED); -} -Bit16u DOS_FCB::Get_time(void){ - return mem_readw(off+offsetof(sFCB,time)+FCB_EXTENDED); -} - - -void DOS_ParamBlock::InitExec(RealPt cmdtail) { - mem_writew(off+offsetof(sParamBlock,exec.envseg),0); - mem_writed(off+offsetof(sParamBlock,exec.fcb1),0); - mem_writed(off+offsetof(sParamBlock,exec.fcb2),0); - mem_writed(off+offsetof(sParamBlock,exec.cmdtail),cmdtail); -} - -Bit16u DOS_ParamBlock::loadseg(void) { - return mem_readw(off+offsetof(sParamBlock,overlay.loadseg)); -} -Bit16u DOS_ParamBlock::relocation(void){ - return mem_readw(off+offsetof(sParamBlock,overlay.loadseg)); -} -Bit16u DOS_ParamBlock::envseg(void){ - return mem_readw(off+offsetof(sParamBlock,exec.envseg)); -} -RealPt DOS_ParamBlock::initsssp(void){ - return mem_readd(off+offsetof(sParamBlock,exec.initsssp)); -} -RealPt DOS_ParamBlock::initcsip(void){ - return mem_readd(off+offsetof(sParamBlock,exec.initcsip)); -} -RealPt DOS_ParamBlock::fcb1(void){ - return mem_readd(off+offsetof(sParamBlock,exec.fcb1)); -} -RealPt DOS_ParamBlock::fcb2(void){ - return mem_readd(off+offsetof(sParamBlock,exec.fcb2)); -} -RealPt DOS_ParamBlock::cmdtail(void){ - return mem_readd(off+offsetof(sParamBlock,exec.cmdtail)); -} - -// * Dos Info Block (list of lists) * - -void DOS_InfoBlock::SetLocation(Bit16u segment) +void DOS_PSP::SetFileHandle(Bit16u index, Bit8u handle) { - seg = segment; - dib = (SDosInfoBlock*)HostMake(segment,0); - Bit16u size = sizeof(SDosInfoBlock); - memset(dib,0,sizeof(SDosInfoBlock)); + if (indexfirstMCB = pt; + PhysPt files=Real2Phys(sGet(sPSP,file_table)); + for (Bit16u i=0;iGetFileHandle(i); + SetFileHandle(i,handle); + } +}; + +void DOS_PSP::CloseFiles(void) +{ + for (Bit16u i=0;i8) size=8; + MEM_BlockWrite(pt+offsetof(sDTA,sname),pattern,size); + find_ext++; + MEM_BlockWrite(pt+offsetof(sDTA,sext),find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); + } else { + MEM_BlockWrite(pt+offsetof(sDTA,sname),pattern,(strlen(pattern) > 8) ? 8 : strlen(pattern)); + } +} + +void DOS_DTA::SetResult(const char * _name,Bit32u _size,Bit16u _date,Bit16u _time,Bit8u _attr) { + MEM_BlockWrite(pt+offsetof(sDTA,name),(void *)_name,DOS_NAMELENGTH_ASCII); + sSave(sDTA,size,_size); + sSave(sDTA,date,_date); + sSave(sDTA,time,_time); + sSave(sDTA,attr,_attr); +} + + +void DOS_DTA::GetResult(char * _name,Bit32u & _size,Bit16u & _date,Bit16u & _time,Bit8u & _attr) { + MEM_BlockRead(pt+offsetof(sDTA,name),_name,DOS_NAMELENGTH_ASCII); + _size=sGet(sDTA,size); + _date=sGet(sDTA,date); + _time=sGet(sDTA,time); + _attr=sGet(sDTA,attr); +} + +Bit8u DOS_DTA::GetSearchDrive(void) { + return sGet(sDTA,sdrive); +} + +void DOS_DTA::GetSearchParams(Bit8u & attr,char * pattern) { + attr=sGet(sDTA,sattr); + char temp[11]; + MEM_BlockRead(pt+offsetof(sDTA,sname),temp,11); + memcpy(pattern,temp,8); + pattern[8]='.'; + memcpy(&pattern[9],&temp[8],3); + pattern[12]=0; + +} + +DOS_FCB::DOS_FCB(Bit16u seg,Bit16u off) { + SetPt(seg,off); + real_pt=pt; + if (sGet(sFCB,drive)==0xff) { + pt+=7; + extended=true; + } else extended=false; +} + +bool DOS_FCB::Extended(void) { + return extended; +} + +void DOS_FCB::Create(bool _extended) { + Bitu fill; + if (_extended) fill=36+7; + else fill=36; + Bitu i; + for (i=0;isize); + sSave(sFCB,time,Files[temp]->time); + sSave(sFCB,date,Files[temp]->date); +} + +void DOS_FCB::FileClose(Bit8u & _fhandle) { + _fhandle=sGet(sFCB,file_handle); + sSave(sFCB,file_handle,0xff); +} + +Bit8u DOS_FCB::GetDrive(void) { + Bit8u drive=sGet(sFCB,drive); + if (!drive) return dos.current_drive; + else return drive-1; +} + +void DOS_FCB::GetName(char * fillname) { + fillname[0]=GetDrive()+'A'; + fillname[1]=':'; + MEM_BlockRead(pt+offsetof(sFCB,filename),&fillname[2],8); + fillname[10]='.'; + MEM_BlockRead(pt+offsetof(sFCB,ext),&fillname[11],3); + fillname[14]=0; +} + +class DOS_MCB : public MemStruct{ +public: + DOS_MCB(Bit16u seg) { SetPt(seg); } +private: + struct sMCB { + Bit8u type; + Bit16u psp_segment; + Bit16u size; + Bit8u unused[3]; + Bit8u filename[8]; + } GCC_ATTRIBUTE(packed); }; diff --git a/src/dos/dos_execute.cpp b/src/dos/dos_execute.cpp index 9cb7796..bb3c623 100644 --- a/src/dos/dos_execute.cpp +++ b/src/dos/dos_execute.cpp @@ -21,12 +21,11 @@ #include "mem.h" #include "dos_inc.h" #include "cpu.h" -#if defined (_MSC_VER) -#pragma pack(1) -#endif +#include "callback.h" +#include "debug.h" +#pragma pack(1) struct EXE_Header { - Bit16u signature; /* EXE Signature MZ or ZM */ Bit16u extrabytes; /* Bytes on the last page */ Bit16u pages; /* Pages in file */ @@ -41,13 +40,8 @@ struct EXE_Header { Bit16u initCS; Bit16u reloctable; Bit16u overlay; -} -#if defined (_MSC_VER) -; +} GCC_ATTRIBUTE(packed); #pragma pack() -#else -__attribute__ ((packed)); -#endif #define MAGIC1 0x5a4d #define MAGIC2 0x4d5a @@ -63,32 +57,64 @@ __attribute__ ((packed)); #define OVERLAY 3 -bool DOS_Terminate(bool tsr) { - PSP * psp=(PSP *)HostMake(dos.psp,0); - if (!tsr) { - /* Free Files owned by process */ - for (Bit16u i=0;imax_files;i++) { - DOS_CloseFile(i); - } - DOS_FreeProcessMemory(dos.psp); - }; - dos.psp=psp->psp_parent; - PSP * oldpsp=(PSP *)HostMake(dos.psp,0); - /* Restore the DTA */ - dos.dta=psp->dta; - /* Restore the old CS:IP from int 22h */ - RealPt old22; - old22=RealGetVec(0x22); - SegSet16(cs,RealSeg(old22)); - reg_ip=RealOff(old22); - /* Restore the SS:SP to the previous one */ - SegSet16(ss,RealSeg(oldpsp->stack)); - reg_sp=RealOff(oldpsp->stack); - /* Restore interrupt 22,23,24 */ - RealSetVec(0x22,psp->int_22); - RealSetVec(0x23,psp->int_23); - RealSetVec(0x24,psp->int_24); +static void SaveRegisters(void) { + reg_sp-=20; + mem_writew(SegPhys(ss)+reg_sp+ 0,reg_ax); + mem_writew(SegPhys(ss)+reg_sp+ 2,reg_cx); + mem_writew(SegPhys(ss)+reg_sp+ 4,reg_dx); + mem_writew(SegPhys(ss)+reg_sp+ 6,reg_bx); + mem_writew(SegPhys(ss)+reg_sp+ 8,reg_si); + mem_writew(SegPhys(ss)+reg_sp+10,reg_di); + mem_writew(SegPhys(ss)+reg_sp+12,reg_bp); + mem_writew(SegPhys(ss)+reg_sp+14,SegValue(ds)); + mem_writew(SegPhys(ss)+reg_sp+16,SegValue(es)); +} + +static void RestoreRegisters(void) { + reg_ax=mem_readw(SegPhys(ss)+reg_sp+ 0); + reg_cx=mem_readw(SegPhys(ss)+reg_sp+ 2); + reg_dx=mem_readw(SegPhys(ss)+reg_sp+ 4); + reg_bx=mem_readw(SegPhys(ss)+reg_sp+ 6); + reg_si=mem_readw(SegPhys(ss)+reg_sp+ 8); + reg_di=mem_readw(SegPhys(ss)+reg_sp+10); + reg_bp=mem_readw(SegPhys(ss)+reg_sp+12); + SegSet16(ds,mem_readw(SegPhys(ss)+reg_sp+14)); + SegSet16(es,mem_readw(SegPhys(ss)+reg_sp+16)); + reg_sp+=20; +} + + +bool DOS_Terminate(bool tsr) { + + dos.return_code=reg_al; + dos.return_mode=RETURN_EXIT; + + Bit16u mempsp = dos.psp; + DOS_PSP curpsp(dos.psp); + if (dos.psp==curpsp.GetParent()) return true; + + /* Free Files owned by process */ + if (!tsr) curpsp.CloseFiles(); + /* Get the termination address */ + RealPt old22 = curpsp.GetInt22(); + /* Restore vector 22,23,24 */ + curpsp.RestoreVectors(); + /* Set the parent PSP */ + dos.psp = curpsp.GetParent(); + DOS_PSP parentpsp(curpsp.GetParent()); + /* Restore the DTA of the parent psp */ + dos.dta = parentpsp.GetDTA(); + /* Restore the SS:SP to the previous one */ + SegSet16(ss,RealSeg(parentpsp.GetStack())); + reg_sp = RealOff(parentpsp.GetStack()); + /* Restore the old CS:IP from int 22h */ + RestoreRegisters(); + /* Set the CS:IP stored in int 0x22 back on the stack */ + mem_writew(SegPhys(ss)+reg_sp+0,RealOff(old22)); + mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(old22)); + // Free memory owned by process + if (!tsr) DOS_FreeProcessMemory(mempsp); return true; } @@ -97,20 +123,19 @@ bool DOS_Terminate(bool tsr) { static bool MakeEnv(char * name,Bit16u * segment) { /* If segment to copy environment is 0 copy the caller's environment */ - PSP * psp=(PSP *)HostMake(dos.psp,0); + DOS_PSP psp(dos.psp); Bit8u * envread,*envwrite; Bit16u envsize=1; bool parentenv=true; if (*segment==0) { - if (!psp->environment) parentenv=false; //environment seg=0 - envread=HostMake(psp->environment,0); + if (!psp.GetEnvironment()) parentenv=false; //environment seg=0 + envread=HostMake(psp.GetEnvironment(),0); } else { if (!*segment) parentenv=false; //environment seg=0 envread=HostMake(*segment,0); } - //TODO Make a good DOS first psp if (parentenv) { for (envsize=0; ;envsize++) { if (envsize>=MAXENV - ENV_KEEPFREE) { @@ -132,319 +157,189 @@ static bool MakeEnv(char * name,Bit16u * segment) { } *((Bit16u *) envwrite)=1; envwrite+=2; - //TODO put the filename here + return DOS_Canonicalize(name,(char *)envwrite); }; -bool DOS_NewPSP(Bit16u pspseg) { - PSP * newpsp=(PSP *)HostMake(pspseg,0); - PSP * prevpsp=(PSP *)HostMake(dos.psp,0); - - memset((void *)newpsp,0,sizeof(PSP)); - newpsp->exit[0]=0xcd;newpsp->exit[1]=0x20; - newpsp->service[0]=0xcd;newpsp->service[0]=0x21;newpsp->service[0]=0xcb; - - newpsp->mem_size=prevpsp->mem_size; - newpsp->environment=0; - - newpsp->int_22=RealGetVec(0x22); - newpsp->int_23=RealGetVec(0x23); - newpsp->int_24=RealGetVec(0x24); - - newpsp->psp_parent=dos.psp; - newpsp->prev_psp=0xFFFFFFFF; - - Bit32u i; - Bit8u * prevfile=Real2Host(prevpsp->file_table); - for (i=0;i<20;i++) newpsp->files[i]=prevfile[i]; - - newpsp->max_files=20; - newpsp->file_table=RealMake(pspseg,offsetof(PSP,files)); - /* Save the old DTA in this psp */ - newpsp->dta=dos.dta; - /* Setup the DTA */ - dos.dta=RealMake(pspseg,0x80); +bool DOS_NewPSP(Bit16u segment, Bit16u size) +{ + DOS_PSP psp(segment); + psp.MakeNew(size); + DOS_PSP psp_parent(psp.GetParent()); + psp.CopyFileTable(&psp_parent); return true; }; static void SetupPSP(Bit16u pspseg,Bit16u memsize,Bit16u envseg) { - PSP * psp=(PSP *)HostMake(pspseg,0); - /* Fix the PSP index of this MCB */ + /* Fix the PSP for psp and environment MCB's */ MCB * pspmcb=(MCB *)HostMake(pspseg-1,0); pspmcb->psp_segment=pspseg; MCB * envmcb=(MCB *)HostMake(envseg-1,0); envmcb->psp_segment=pspseg; - memset((void *)psp,0,sizeof(PSP)); - Bit32u i; - - psp->exit[0]=0xcd;psp->exit[1]=0x20; - psp->mem_size=memsize+pspseg; - psp->environment=envseg; - - psp->int_22=RealGetVec(0x22); - psp->int_23=RealGetVec(0x23); - psp->int_24=RealGetVec(0x24); - - psp->service[0]=0xcd;psp->service[0]=0x21;psp->service[0]=0xcb; - - psp->psp_parent=dos.psp; - psp->prev_psp=RealMake(dos.psp,0); - - for (i=0;i<20;i++) psp->files[i]=0xff; - psp->files[STDIN]=DOS_FindDevice("CON"); - psp->files[STDOUT]=DOS_FindDevice("CON"); - psp->files[STDERR]=DOS_FindDevice("CON"); - psp->files[STDAUX]=DOS_FindDevice("CON"); - psp->files[STDNUL]=DOS_FindDevice("CON"); - psp->files[STDPRN]=DOS_FindDevice("CON"); - - psp->max_files=20; - psp->file_table=RealMake(pspseg,offsetof(PSP,files)); + DOS_PSP psp(pspseg); + psp.MakeNew(memsize); + psp.SetEnvironment(envseg); + psp.SetFileHandle(STDIN ,DOS_FindDevice("CON")); + psp.SetFileHandle(STDOUT,DOS_FindDevice("CON")); + psp.SetFileHandle(STDERR,DOS_FindDevice("CON")); + psp.SetFileHandle(STDAUX,DOS_FindDevice("CON")); + psp.SetFileHandle(STDNUL,DOS_FindDevice("CON")); + psp.SetFileHandle(STDPRN,DOS_FindDevice("CON")); /* Save old DTA in psp */ - psp->dta=dos.dta; - + psp.SetDTA(dos.dta); /* Setup the DTA */ dos.dta=RealMake(pspseg,0x80); } -static void SetupCMDLine(Bit16u pspseg,ParamBlock * block) { - PSP * psp=(PSP *)HostMake(pspseg,0); - - if (block->exec.cmdtail) { - memcpy((void *)&psp->cmdtail,(void *)Real2Host(block->exec.cmdtail),128); - } else { - char temp[]=""; - psp->cmdtail.count=strlen(temp); - strcpy((char *)&psp->cmdtail.buffer,temp); - psp->cmdtail.buffer[0]=0x0d; - - } +static void SetupCMDLine(Bit16u pspseg,DOS_ParamBlock & block) +{ + DOS_PSP psp(pspseg); + // if cmdtail==0 it will inited as empty in SetCommandTail + psp.SetCommandTail(block.exec.cmdtail); } - - - -static bool COM_Load(char * name,ParamBlock * block,Bit8u flag) { - Bit16u fhandle; - Bit16u size;Bit16u readsize; - Bit16u envseg,comseg; - Bit32u pos; - - PSP * callpsp=(PSP *)HostMake(dos.psp,0); - - if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false; - if (flag!=OVERLAY) { - /* Allocate a new Environment */ - envseg=block->exec.envseg; - if (!MakeEnv(name,&envseg)) return false; - /* Allocate max memory for COM file and PSP */ - size=0xffff; - DOS_AllocateMemory(&comseg,&size); - //TODO Errors check for minimun of 64kb in pages - if (Bit32u(size <<4)<0x1000) { - DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); - DOS_FreeMemory(envseg); - return false; - } - DOS_AllocateMemory(&comseg,&size); - } else { - comseg=block->overlay.loadseg; +bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { + EXE_Header head;Bitu i; + Bit16u fhandle;Bit16u len;Bit32u pos; + Bit16u pspseg,envseg,loadseg,memsize,readsize; + HostPt loadaddress;RealPt relocpt; + Bitu headersize,imagesize; + DOS_ParamBlock block(block_pt); + block.LoadData(); + if (flags!=LOADNGO && flags!=OVERLAY) { + E_Exit("DOS:Not supported execute mode %d for file %s",flags,name); } - /* Memory allocated now load the program */ - /* Now copy the File into allocated memory */ - pos=0; - DOS_SeekFile(fhandle,&pos,0); - readsize=0xffff-256; - if (flag==OVERLAY) { - DOS_ReadFile(fhandle,HostMake(comseg,0),&readsize); - } else { - DOS_ReadFile(fhandle,HostMake(comseg,256),&readsize); - } - DOS_CloseFile(fhandle); - if (flag==OVERLAY) /* Everything what should be done for Overlays */ - return true; - SetupPSP(comseg,size,envseg); - SetupCMDLine(comseg,block); - /* Setup termination Address */ - RealSetVec(0x22,RealMakeSeg(cs,reg_ip)); - /* Everything setup somewhat setup CS:IP and SS:SP */ - /* First save the SS:SP of program that called execute */ - callpsp->stack=RealMakeSeg(ss,reg_sp); - /* Clear out first Stack entry to point to int 20h at psp:0 */ - real_writew(comseg,0xfffe,0); - dos.psp=comseg; - switch (flag) { - case LOADNGO: - SegSet16(cs,comseg); - SegSet16(ss,comseg); - SegSet16(ds,comseg); - SegSet16(es,comseg); - flags.intf=true; - reg_ip=0x100; - reg_sp=0xFFFE; - reg_ax=0; - reg_bx=reg_cx=reg_dx=reg_si=reg_di=reg_bp=0; - return true; - case LOAD: - block->exec.initsssp=RealMake(comseg,0xfffe); - block->exec.initcsip=RealMake(comseg,0x100); - return true; - } - return false; - -} - - -static bool EXE_Load(char * name,ParamBlock* _block,Bit8u flag) { - - EXE_Header header; - Bit16u fhandle;Bit32u i; - Bit16u size,minsize,maxsize,freesize;Bit16u readsize; - Bit16u envseg,pspseg,exeseg; - Bit32u imagesize,headersize; - - // During loading process, th param-block-mem might be overwritten (HostPt!) and - // therefore change the relocation address, so save these values. - ParamBlock block; - memcpy(&block,_block,sizeof(ParamBlock)); - - PSP * callpsp=(PSP *)HostMake(dos.psp,0); - - if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false; - if (flag!=OVERLAY) { - /* Allocate a new Environment */ - envseg=block.exec.envseg; - if (!MakeEnv(name,&envseg)) return false; - }; - - /* First Read the EXE Header */ - readsize=sizeof(EXE_Header); - DOS_ReadFile(fhandle,(Bit8u*)&header,&readsize); - /* Calculate the size of the image to load */ - headersize=header.headersize*16; - imagesize=header.pages*512-headersize; - if (flag!=OVERLAY) { - minsize=long2para(imagesize+(header.minmemory<<4)+256); - if (header.maxmemory!=0) maxsize=long2para(imagesize+(header.maxmemory<<4)+256); - else maxsize=0xffff; - freesize=0xffff; - /* Check for enough free memory */ - DOS_AllocateMemory(&exeseg,&freesize); - if (minsize>freesize) { - DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); - DOS_FreeMemory(envseg); - return false; - } - if (maxsize>freesize) { - size=freesize; - } else size=maxsize; - if ((header.minmemory|header.maxmemory)==0) { - size=freesize; - E_Exit("Special case exe header max and min=0"); - } - if (!DOS_AllocateMemory(&pspseg,&size)) { - DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); - DOS_FreeMemory(envseg); - return false; - } - SetupPSP(pspseg,size,envseg); - SetupCMDLine(pspseg,&block); - exeseg=pspseg+16; - } else { - /* For OVERLAY */ - exeseg=block.overlay.loadseg; - } - /* Load the image in 32k blocks */ - DOS_SeekFile(fhandle,&headersize,0); - Bit8u * imageoff=HostMake(exeseg,0); -//TODO File size checking and remove size - // Remove psp size -// imagesize=256; - // Maybe remove final page and add last bytes on page - if (header.extrabytes) { - imagesize-=512; - imagesize+=header.extrabytes; - }; - while (imagesize>0x7FFF) { - readsize=0x8000; - DOS_ReadFile(fhandle,imageoff,&readsize); - if (readsize!=0x8000) { - E_Exit("Illegal header"); - } - imageoff+=0x8000; - imagesize-=0x8000; - } - if (imagesize>0) { - readsize=(Bit16u) imagesize; - DOS_ReadFile(fhandle,imageoff,&readsize); - } - headersize=header.reloctable; - DOS_SeekFile(fhandle,&headersize,0); - RealPt reloc; - for (i=0;istack=RealMakeSeg(ss,reg_sp); - dos.psp=pspseg; - SegSet16(cs,exeseg+header.initCS); - SegSet16(ss,exeseg+header.initSS); - SegSet16(ds,pspseg); - SegSet16(es,pspseg); - reg_ip=header.initIP; - reg_sp=header.initSP; - reg_ax=0; - reg_bx=reg_cx=reg_dx=reg_si=reg_di=reg_bp=0; - flags.intf=true; - return true; -}; - - -bool DOS_Execute(char * name,ParamBlock * block,Bit8u flags) { - - EXE_Header head; - Bit16u fhandle; - Bit16u size; + /* Check for EXE or COM File */ bool iscom=false; if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false; - - size=sizeof(EXE_Header); - if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&size)) { + len=sizeof(EXE_Header); + if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&len)) { DOS_CloseFile(fhandle); return false; } - if (!DOS_CloseFile(fhandle)) return false; - if (size0x7FFF) { + readsize=0x8000;DOS_ReadFile(fhandle,loadaddress,&readsize); + if (readsize!=0x8000) E_Exit("Illegal header"); + loadaddress+=0x8000;imagesize-=0x8000; + } + if (imagesize>0) { + readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadaddress,&readsize); + if (readsize!=imagesize) E_Exit("Illegal header"); + } + /* Relocate the exe image */ + Bit16u relocate; + if (flags==OVERLAY) relocate=block.overlay.relocation; + else relocate=loadseg; + pos=head.reloctable;DOS_SeekFile(fhandle,&pos,0); + for (i=0;i=DOS_DRIVES || !Drives[*drive]) { + DOS_SetError(DOSERR_PATH_NOT_FOUND); + return false; + } + r=0;w=0; while (name[r]!=0 && (r='a') && (c<='z')) {upname[w++]=c-32;continue;} if ((c>='A') && (c<='Z')) {upname[w++]=c;continue;} if ((c>='0') && (c<='9')) {upname[w++]=c;continue;} switch (c) { - case ':': - if (hasdrive) { DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; } - else hasdrive=true; - if ((upname[0]>='A') && (upname[0]<='Z')) { - *drive=upname[0]-'A'; - w=0; - } else { - DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; - } - break; case '/': upname[w++]='\\'; break; @@ -83,15 +85,9 @@ bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) { break; } } + if (r>=DOS_PATHLENGTH) { DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; } upname[w]=0; - /* This should get us an upcase filename and no incorrect chars */ /* Now parse the new file name to make the final filename */ - if ((*drive>=26)) { - DOS_SetError(DOSERR_INVALID_DRIVE);return false; - }; - if (!Drives[*drive]) { - DOS_SetError(DOSERR_INVALID_DRIVE);return false; - }; if (upname[0]!='\\') strcpy(fullname,Drives[*drive]->curdir); else fullname[0]=0; Bit32u lastdir=0;Bit32u t=0; @@ -126,8 +122,13 @@ bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) { lastdir=strlen(fullname); //TODO Maybe another check for correct type because of .... stuff if (lastdir!=0) strcat(fullname,"\\"); + char * ext=strchr(tempdir,'.'); + if (ext) { + ext[4]=0; + Bitu blah=strlen(tempdir); + if (strlen(tempdir)>12) memmove(tempdir+8,ext,5); + } else tempdir[8]=0; strcat(fullname,tempdir); - tempdir[0]=0; w=0;r++; continue; @@ -181,21 +182,36 @@ bool DOS_Rename(char * oldname,char * newname) { if (Drives[drivenew]->Rename(fullold,fullnew)) return true; DOS_SetError(DOSERR_FILE_NOT_FOUND); return false; -}; +} bool DOS_FindFirst(char * search,Bit16u attr) { + DOS_DTA dta(dos.dta); Bit8u drive;char fullsearch[DOS_PATHLENGTH]; + char dir[DOS_PATHLENGTH];char pattern[DOS_PATHLENGTH]; if (!DOS_MakeName(search,fullsearch,&drive)) return false; - DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta); - dtablock->sattr=attr | DOS_ATTR_ARCHIVE; - dtablock->sdrive=drive; - return Drives[drive]->FindFirst(fullsearch,dtablock); -}; + /* Split the search in dir and pattern */ + char * find_last; + find_last=strrchr(fullsearch,'\\'); + if (!find_last) { /*No dir */ + strcpy(pattern,fullsearch); + dir[0]=0; + } else { + *find_last=0; + strcpy(pattern,find_last+1); + strcpy(dir,fullsearch); + } + dta.SetupSearch(drive,(Bit8u)attr,pattern); + if (Drives[drive]->FindFirst(dir,dta)) return true; + DOS_SetError(DOSERR_FILE_NOT_FOUND); + return false; +} bool DOS_FindNext(void) { - DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta); - return Drives[dtablock->sdrive]->FindNext(dtablock); -}; + DOS_DTA dta(dos.dta); + if (Drives[dta.GetSearchDrive()]->FindNext(dta)) return true; + DOS_SetError(DOSERR_FILE_NOT_FOUND); + return false; +} bool DOS_ReadFile(Bit16u entry,Bit8u * data,Bit16u * amount) { @@ -269,9 +285,9 @@ bool DOS_CloseFile(Bit16u entry) { }; //TODO Figure this out with devices :) - PSP * psp=(PSP *)HostMake(dos.psp,0); - Bit8u * table=Real2Host(psp->file_table); - table[entry]=0xFF; + DOS_PSP psp(dos.psp); + psp.SetFileHandle(entry,0xff); + /* Devices won't allow themselves to be closed or killed */ if (Files[handle]->Close()) { delete Files[handle]; @@ -282,7 +298,7 @@ bool DOS_CloseFile(Bit16u entry) { bool DOS_CreateFile(char * name,Bit16u attributes,Bit16u * entry) { char fullname[DOS_PATHLENGTH];Bit8u drive; - PSP * psp=(PSP *)HostMake(dos.psp,0); + DOS_PSP psp(dos.psp); if (!DOS_MakeName(name,fullname,&drive)) return false; /* Check for a free file handle */ Bit8u handle=DOS_FILES;Bit8u i; @@ -297,21 +313,14 @@ bool DOS_CreateFile(char * name,Bit16u attributes,Bit16u * entry) { return false; } /* We have a position in the main table now find one in the psp table */ - Bit8u * table=Real2Host(psp->file_table); - *entry=0xff; - for (i=0;imax_files;i++) { - if (table[i]==0xFF) { - *entry=i; - break; - } - } + *entry = psp.FindFreeFileEntry(); if (*entry==0xff) { DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES); return false; } bool foundit=Drives[drive]->FileCreate(&Files[handle],fullname,attributes); if (foundit) { - table[*entry]=handle; + psp.SetFileHandle(*entry,handle); return true; } else { return false; @@ -320,7 +329,9 @@ bool DOS_CreateFile(char * name,Bit16u attributes,Bit16u * entry) { bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) { /* First check for devices */ - PSP * psp=(PSP *)HostMake(dos.psp,0); + if (flags>2) LOG_DEBUG("Special file open command %X file %s",flags,name); + flags&=3; + DOS_PSP psp(dos.psp); Bit8u handle=DOS_FindDevice((char *)name); bool device=false;char fullname[DOS_PATHLENGTH];Bit8u drive;Bit8u i; if (handle!=255) { @@ -341,14 +352,7 @@ bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) { } } /* We have a position in the main table now find one in the psp table */ - Bit8u * table=Real2Host(psp->file_table); - *entry=0xff; - for (i=0;imax_files;i++) { - if (table[i]==0xFF) { - *entry=i; - break; - } - } + *entry = psp.FindFreeFileEntry(); if (*entry==0xff) { DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES); return false; @@ -356,7 +360,7 @@ bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) { bool exists=false; if (!device) exists=Drives[drive]->FileOpen(&Files[handle],fullname,flags); if (exists || device ) { - table[*entry]=handle; + psp.SetFileHandle(*entry,handle); return true; } else { DOS_SetError(DOSERR_FILE_NOT_FOUND); @@ -391,7 +395,7 @@ bool DOS_Canonicalize(char * name,char * big) { big[2]='\\'; strcpy(&big[3],fullname); return true; -}; +} bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) { if (drive==0) drive=DOS_GetDefaultDrive(); @@ -400,7 +404,7 @@ bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * c DOS_SetError(DOSERR_INVALID_DRIVE); return false; } - return Drives[drive]->FreeSpace(bytes,sectors,clusters,free); + return Drives[drive]->AllocationInfo(bytes,sectors,clusters,free); } bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry) { @@ -413,20 +417,13 @@ bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry) { DOS_SetError(DOSERR_INVALID_HANDLE); return false; }; - PSP * psp=(PSP *)HostMake(dos.psp,0); - Bit8u * table=Real2Host(psp->file_table); - *newentry=0xff; - for (Bit16u i=0;imax_files;i++) { - if (table[i]==0xFF) { - *newentry=i; - break; - } - } + DOS_PSP psp(dos.psp); + *newentry = psp.FindFreeFileEntry(); if (*newentry==0xff) { DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES); return false; } - table[*newentry]=handle; + psp.SetFileHandle(*newentry,handle); return true; }; @@ -449,17 +446,15 @@ bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry) { DOS_CloseFile(newentry); return false; }; - PSP * psp=(PSP *)HostMake(dos.psp,0); - Bit8u * table=Real2Host(psp->file_table); - table[newentry]=(Bit8u)entry; + DOS_PSP psp(dos.psp); + psp.SetFileHandle(newentry,(Bit8u)entry); return true; }; bool DOS_CreateTempFile(char * name,Bit16u * entry) { - -/* First add random crap to the end of the name and try to open */ + /* First add random crap to the end of the name and try to open */ /* Todo maybe check for euhm existence of the path name */ char * tempname; tempname=name+strlen(name); @@ -472,41 +467,26 @@ bool DOS_CreateTempFile(char * name,Bit16u * entry) { for (i=9;i<12;i++) { tempname[i]=(rand()%26)+'A'; } - tempname[13]=0; + tempname[12]=0; } while (!DOS_CreateFile(name,0,entry)); return true; } + #if 1 -static bool FCB_MakeName (DOS_FCB* fcb, char* outname, Bit8u* outdrive){ - char naam[15]; - Bit8s teller=0; - Bit8u drive=fcb->Get_drive(); - if(drive!=0){ - naam[0]=(drive-1)+'A'; - naam[1]=':'; - naam[2]='\0';} - else{ - naam[0]='\0'; - }; - char temp[10]; - fcb->Get_filename(temp); - temp[8]='.'; - temp[9]='\0'; - strcat(naam,temp); - char ext[4]; - fcb->Get_ext(ext); - ext[3]='\0'; - strcat(naam,ext); - return DOS_MakeName(naam,outname, outdrive); + +static bool FCB_MakeName2 (DOS_FCB & fcb, char* outname, Bit8u* outdrive){ + char short_name[DOS_FCBNAME]; + fcb.GetName(short_name); + return DOS_MakeName(short_name,outname, outdrive); } + #define FCB_SEP ":.;,=+" #define ILLEGAL ":.;,=+ \t/\"[]<>|" -static bool isvalid(const char* in){ - +static bool isvalid(const char in){ const char ill[]=ILLEGAL; - return (Bit8u(*in)>0x1F) && (strchr(ill,*in)==0); + return (Bit8u(in)>0x1F) && (!strchr(ill,in)); } static void vullen (char* veld,char* pveld){ @@ -515,218 +495,352 @@ static void vullen (char* veld,char* pveld){ } return; } + +#define PARSE_SEP_STOP 0x01 +#define PARSE_DFLT_DRIVE 0x02 +#define PARSE_BLNK_FNAME 0x04 +#define PARSE_BLNK_FEXT 0x08 + +#define PARSE_RET_NOWILD 0 +#define PARSE_RET_WILD 1 +#define PARSE_RET_BADDRIVE 0xff + Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change){ - char* backup; - backup=string; + + char * string_begin=string;Bit8u ret=0; DOS_FCB fcb(seg,offset); - Bit8u retwaarde=0; - char naam[9]=" "; - char ext[4]=" "; - if(parser & 1) { //ignore leading seperator - char sep[] = FCB_SEP; - char a[2]; - a[0]= *string;a[1]='\0'; - if (strcspn(a,sep)==0) string++; - } - if((!(parser &4)) ==true){ // fill name with spaces if no name - fcb.Set_filename(naam); - } - if((!(parser &8)) ==true){ // fill ext with spaces if no ext - fcb.Set_ext(ext); - } - if((parser & 2)==false) fcb.Set_drive(0); //Set allready the defaultdrive (Will stay set when it's not specified) - // strip leading spaces - while((*string==' ')||(*string=='\t')) string++; - if( *(string+1)==':') { - Bit8u drive=toupper(*string); - if( (drive>'Z') | (drive<'A') | (Drives[drive-'A']==NULL)) { - *change=string-backup; - return 0xFF; - } - fcb.Set_drive(drive-'A'+1); - string+=2; - } - //startparsing - char* pnaam=naam; - while(isvalid(string)==true) { - if(*string=='*'){ - vullen(naam,pnaam); //fill with ???? - string++; - retwaarde=1; - break; - } - - *pnaam=*string; - pnaam++; - string++; - } - fcb.Set_filename(naam); - if((*string=='.')==false) { - *change=string-backup; - return retwaarde; - } - //extension exist - string++; - char* pext=ext; - while(isvalid(string)==true) { - if(*string=='*'){ - vullen(ext,pext); //fill with ???? - string++; - retwaarde=1; - break; - } - - *pext=*string; - pext++; - string++; - } - fcb.Set_ext(ext); - *change=string-backup; - return retwaarde; - - - + bool hasdrive,hasname,hasext; + hasdrive=hasname=hasext=false; + Bitu index;bool finished;Bit8u fill; +/* First get the old data from the fcb */ +#pragma pack (1) + union { + struct { + char drive[2]; + char name[9]; + char ext[4]; + } part GCC_ATTRIBUTE (packed) ; + char full[DOS_FCBNAME]; + } fcb_name; +#pragma pack() + /* Get the old information from the previous fcb */ + fcb.GetName(fcb_name.full);fcb_name.part.drive[1]=0;fcb_name.part.name[8]=0;fcb_name.part.ext[3]=0; + /* Strip of the leading sepetaror */ + if((parser & PARSE_SEP_STOP) && *string) { //ignore leading seperator + char sep[] = FCB_SEP;char a[2]; + a[0]= *string;a[1]='\0'; + if (strcspn(a,sep)==0) string++; + } + /* strip leading spaces */ + while((*string==' ')||(*string=='\t')) string++; + /* Check for a drive */ + if (string[1]==':') { + fcb_name.part.drive[0]=0; + hasdrive=true; + if (isalpha(string[0]) && Drives[toupper(string[0])-'A']) { + fcb_name.part.drive[0]=toupper(string[0])-'A'+1; + } else ret=0xff; + string+=2; + } + /* Special checks for . and .. */ + if (string[0]=='.') { + string++; + if (!string[0]) { + hasname=true; + ret=PARSE_RET_NOWILD; + strcpy(fcb_name.part.name,". "); + goto savefcb; + } + if (string[1]=='.' && !string[1]) { + string++; + hasname=true; + ret=PARSE_RET_NOWILD; + strcpy(fcb_name.part.name,".. "); + goto savefcb; + } + goto checkext; + } + /* Copy the name */ + hasname=true;finished=false;fill=' ';index=0; + while (index<8) { + if (!finished) { + if (string[0]=='*') {fill='?';fcb_name.part.name[index]='?';if (!ret) ret=1;finished=true;} + else if (string[0]=='?') {fcb_name.part.name[index]='?';if (!ret) ret=1;} + else if (isvalid(string[0])) {fcb_name.part.name[index]=toupper(string[0]);} + else { finished=true;continue; } + string++; + } else { + fcb_name.part.name[index]=fill; + } + index++; + } + if (!(string[0]=='.')) goto savefcb; + string++; +checkext: + /* Copy the extension */ + hasext=true;finished=false;fill=' ';index=0; + while (index<3) { + if (!finished) { + if (string[0]=='*') {fill='?';fcb_name.part.ext[index]='?';finished=true;} + else if (string[0]=='?') {fcb_name.part.ext[index]='?';if (!ret) ret=1;} + else if (isvalid(string[0])) {fcb_name.part.ext[index]=toupper(string[0]);} + else { finished=true;continue; } + string++; + } else { + fcb_name.part.ext[index]=fill; + } + index++; + } +savefcb: + if (!hasdrive & !(parser & PARSE_DFLT_DRIVE)) fcb_name.part.drive[0]=dos.current_drive+1; + if (!hasname & !(parser & PARSE_BLNK_FNAME)) strcpy(fcb_name.part.name," "); + if (!hasext & !(parser & PARSE_BLNK_FEXT)) strcpy(fcb_name.part.ext," "); + fcb.SetName(fcb_name.part.drive[0],fcb_name.part.name,fcb_name.part.ext); + *change=(Bit8u)(string-string_begin); + return ret; } -bool DOS_FCBOpen(Bit16u seg,Bit16u offset) { + +static void DTAExtendName(char * name,char * filename,char * ext) { + char * find=strchr(name,'.'); + if (find) { + strcpy(ext,find+1); + *find=0; + } else ext[0]=0; + strcpy(filename,name); + Bitu i; + for (i=strlen(name);i<8;i++) filename[i]=' ';filename[8]=0; + for (i=strlen(ext);i<3;i++) ext[i]=' ';ext[3]=0; +} + +static void SaveFindResult(DOS_FCB & find_fcb) { + DOS_DTA find_dta(dos.tables.tempdta); + char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u date;Bit16u time;Bit8u attr;Bit8u drive; + char file_name[9];char ext[4]; + find_dta.GetResult(name,size,date,time,attr); + drive=find_fcb.GetDrive(); + /* Create a correct file and extention */ + DTAExtendName(name,file_name,ext); + DOS_FCB fcb(RealSeg(dos.dta),RealOff(dos.dta)); + fcb.Create(find_fcb.Extended()); + fcb.SetName(drive,file_name,ext); + fcb.SetSizeDateTime(size,date,time); +} + +bool DOS_FCBOpenCreate(Bit16u seg,Bit16u offset) { DOS_FCB fcb(seg,offset); - Bit8u drive; - char fullname[DOS_PATHLENGTH]; - if(!FCB_MakeName (&fcb, fullname, &drive)) return false; - if(!Drives[drive]->FileExists(fullname)) return false; //not really needed as stat will error. + char shortname[DOS_FCBNAME];Bit16u handle; + fcb.GetName(shortname); + if (!DOS_OpenFile(shortname,2,&handle)) return false; + fcb.FileOpen((Bit8u)handle); + return true; +} - struct stat stat_block; - if(!Drives[drive]->FileStat(fullname, &stat_block)) return false; - fcb.Set_filesize((Bit32u)stat_block.st_size); - Bit16u constant = 0; - fcb.Set_current_block(constant); - constant=0x80; - fcb.Set_record_size(constant); - - struct tm *time; - if((time=localtime(&stat_block.st_mtime))!=0){ - - constant=(time->tm_hour<<11)+(time->tm_min<<5)+(time->tm_sec/2); /* standard way. */ - fcb.Set_time(constant); - constant=((time->tm_year-80)<<9)+((time->tm_mon+1)<<5)+(time->tm_mday); - fcb.Set_date(constant); - } - else{ - constant=6; - fcb.Set_time(constant); - constant=4; - fcb.Set_date(constant); - } - fcb.Set_drive(drive +1); - return true; - } - -bool DOS_FCBClose(Bit16u seg,Bit16u offset) -{ DOS_FCB fcb(seg,offset); - Bit8u drive; - char fullname[DOS_PATHLENGTH]; - if(!FCB_MakeName (&fcb, fullname, &drive)) return false; - if(!Drives[drive]->FileExists(fullname)) return false; - - return true;} +bool DOS_FCBClose(Bit16u seg,Bit16u offset) { + DOS_FCB fcb(seg,offset); + Bit8u fhandle; + fcb.FileClose(fhandle); + DOS_CloseFile(fhandle); + return true; +} bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset) { - DOS_FCB* fcb = new DOS_FCB(seg,offset); - Bit8u drive; - Bitu i; - char fullname[DOS_PATHLENGTH]; - FCB_MakeName (fcb, fullname, &drive); - DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta); - dtablock->sattr=DOS_ATTR_ARCHIVE; - dtablock->sdrive=drive; - - if(Drives[drive]->FindFirst(fullname,dtablock)==false) return false; - - char naam[9]; - char ext[4]; - char * point=strrchr(dtablock->name,'.'); - if(point==NULL|| *(point+1)=='\0') { - ext[0]=' '; - ext[1]=' '; - ext[2]=' '; - }else{ - strcpy(ext,(point+1)); - i=strlen((point+1)); - while(i!=3) {ext[i]=' ';i++;} - } - - if(point!=NULL) *point='\0'; - - strcpy (naam,dtablock->name); - i=strlen(dtablock->name); - while(i!=8) {naam[i]=' '; i++;} - delete fcb; - DOS_FCB* fcbout= new DOS_FCB((PhysPt)Real2Phys(dos.dta)); - fcbout->Set_drive(drive +1); - fcbout->Set_filename(naam); - fcbout->Set_ext(ext); - return true; - + DOS_FCB fcb(seg,offset); + RealPt old_dta=dos.dta;dos.dta=dos.tables.tempdta; + char name[DOS_FCBNAME];fcb.GetName(name); + bool ret=DOS_FindFirst(name,DOS_ATTR_ARCHIVE); + dos.dta=old_dta; + if (ret) SaveFindResult(fcb); + return ret; } + bool DOS_FCBFindNext(Bit16u seg,Bit16u offset) { - DOS_FCB* fcb = new DOS_FCB(seg,offset); - Bit8u drive; - Bitu i; - char fullname[DOS_PATHLENGTH]; - FCB_MakeName (fcb, fullname, &drive); - DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta); - dtablock->sattr=DOS_ATTR_ARCHIVE; - dtablock->sdrive=drive; + DOS_FCB fcb(seg,offset); + RealPt old_dta=dos.dta;dos.dta=dos.tables.tempdta; + bool ret=DOS_FindNext(); + dos.dta=old_dta; + if (ret) SaveFindResult(fcb); + return ret; +} - if(Drives[dtablock->sdrive]->FindNext(dtablock)==false) return false; - char naam[9]; - char ext[4]; - char * point=strrchr(dtablock->name,'.'); - if(point==NULL|| *(point+1)=='\0') { - ext[0]=' '; - ext[1]=' '; - ext[2]=' '; - }else - { - strcpy(ext,point+1); - i=strlen(point+1); - while(i!=3) {ext[i]=' ';i++;} - } +Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset,Bit16u recno) { + DOS_FCB fcb(seg,offset); + Bit8u fhandle,cur_rec;Bit16u cur_block,rec_size; + fcb.GetSeqData(fhandle,rec_size); + fcb.GetRecord(cur_block,cur_rec); + Bit32u pos=((cur_block*128)+cur_rec)*rec_size; + if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET)) return FCB_READ_NODATA; + Bit16u toread=rec_size; + if (!DOS_ReadFile(fhandle,dos_copybuf,&toread)) return FCB_READ_NODATA; + if (toread==0) return FCB_READ_NODATA; + if (toread0;i--) mem_writeb(fill++,0); + } + MEM_BlockWrite(Real2Phys(dos.dta)+recno*rec_size,dos_copybuf,rec_size); + if (++cur_rec>127) { cur_block++;cur_rec=0; } + fcb.SetRecord(cur_block,cur_rec); + if (toread==rec_size) return FCB_SUCCESS; + if (toread==0) return FCB_READ_NODATA; + return FCB_READ_PARTIAL; +} - if(point!=NULL) *point='\0'; - - strcpy (naam,dtablock->name); - i=strlen(dtablock->name); - while(i!=8) {naam[i]=' '; i++;} - delete fcb; - DOS_FCB* fcbout= new DOS_FCB(Real2Phys(dos.dta)); - fcbout->Set_drive(drive +1); - fcbout->Set_filename(naam); - fcbout->Set_ext(ext); - return true; - } +bool DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno) +{ + DOS_FCB fcb(seg,offset); + Bit8u fhandle,cur_rec;Bit16u cur_block,rec_size; + fcb.GetSeqData(fhandle,rec_size); + fcb.GetRecord(cur_block,cur_rec); + Bit32u pos=((cur_block*128)+cur_rec)*rec_size; + if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET)) return FCB_ERR_WRITE; + MEM_BlockRead(Real2Phys(dos.dta)+recno*rec_size,dos_copybuf,rec_size); + Bit16u towrite=rec_size; + if (!DOS_WriteFile(fhandle,dos_copybuf,&towrite)) return FCB_ERR_WRITE; + Bit32u size;Bit16u date,time; + fcb.GetSizeDateTime(size,date,time); + if (pos+towrite>size) size=pos+towrite; + //TODO Set time to current time? + fcb.SetSizeDateTime(size,date,time); + if (++cur_rec>127) { cur_block++;cur_rec=0; } + fcb.SetRecord(cur_block,cur_rec); + return FCB_SUCCESS; +} + +Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) { + + DOS_FCB fcb(seg,offset); + Bit32u random;Bit16u old_block;Bit8u old_rec;Bit8u error; + /* Set the correct record from the random data */ + fcb.GetRandom(random); + if (restore) fcb.GetRecord(old_block,old_rec); + fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127)); + // Read records + for (int i=0; isize; + DOS_CloseFile(entry);fcb.GetSeqData(handle,rec_size); + Bit32u random=(size/rec_size); + if (size % rec_size) random++; + fcb.SetRandom(random); + return true; +} + +bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset){ + DOS_FCB fcb(seg,offset); + char shortname[DOS_FCBNAME]; + fcb.GetName(shortname); + return DOS_UnlinkFile(shortname); +} + +bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset){ + DOS_FCB fcbold(seg,offset); + DOS_FCB fcbnew(seg,offset+16); + char oldname[DOS_FCBNAME]; + char newname[DOS_FCBNAME]; + fcbold.GetName(oldname);fcbnew.GetName(newname); + return DOS_Rename(oldname,newname); +} + +void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset) { + DOS_FCB fcb(seg,offset); + Bit16u block;Bit8u rec; + fcb.GetRecord(block,rec); + fcb.SetRandom(block*128+rec); +} #endif bool DOS_FileExists(char * name) { - char fullname[DOS_PATHLENGTH];Bit8u drive; if (!DOS_MakeName(name,fullname,&drive)) return false; return Drives[drive]->FileExists(fullname); } +bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters) { + if (!drive) drive=dos.current_drive; + else drive--; + if (!Drives[drive]) return false; + Bit16u _free_clusters; + Drives[drive]->AllocationInfo(_bytes_sector,_sectors_cluster,_total_clusters,&_free_clusters); + SegSet16(ds,RealSeg(dos.tables.mediaid)); + reg_bx=RealOff(dos.tables.mediaid+drive); + return true; +} bool DOS_SetDrive(Bit8u drive) { if (Drives[drive]) { DOS_SetDefaultDrive(drive); return true; - } else { return false; } }; +bool DOS_GetFileDate(Bit16u entry, Bit16u* otime, Bit16u* odate) +{ + Bit32u handle=RealHandle(entry); + if (handle>=DOS_FILES) { + DOS_SetError(DOSERR_INVALID_HANDLE); + return false; + }; + if (!Files[handle]) { + DOS_SetError(DOSERR_INVALID_HANDLE); + return false; + }; + struct stat stat_block; + if (fstat(handle, &stat_block)!=0) { + DOS_SetError(DOSERR_INVALID_HANDLE); + return false; + } + struct tm *time; + if ((time=localtime(&stat_block.st_mtime))!=0) { + *otime = (time->tm_hour<<11)+(time->tm_min<<5)+(time->tm_sec/2); /* standard way. */ + *odate = ((time->tm_year-80)<<9)+((time->tm_mon+1)<<5)+(time->tm_mday); + } else { + *otime = 6; + *odate = 4; + } + return true; +}; void DOS_SetupFiles (void) { /* Setup the File Handles */ diff --git a/src/dos/dos_ioctl.cpp b/src/dos/dos_ioctl.cpp index 9b25352..f01b181 100644 --- a/src/dos/dos_ioctl.cpp +++ b/src/dos/dos_ioctl.cpp @@ -26,16 +26,20 @@ #define MAX_DEVICE 20 static DOS_File * dos_devices[MAX_DEVICE]; -bool DOS_IOCTL(Bit8u call,Bit16u entry) { - Bit32u handle=RealHandle(entry); - if (handle>=DOS_FILES) { - DOS_SetError(DOSERR_INVALID_HANDLE); - return false; - }; - if (!Files[handle]) { - DOS_SetError(DOSERR_INVALID_HANDLE); - return false; - }; + +bool DOS_IOCTL(void) { + Bitu handle;Bit8u drive; + if (reg_al<8) { /* call 0-7 use a file handle */ + handle=RealHandle(reg_bx); + if (handle>=DOS_FILES) { + DOS_SetError(DOSERR_INVALID_HANDLE); + return false; + } + if (!Files[handle]) { + DOS_SetError(DOSERR_INVALID_HANDLE); + return false; + } + } switch(reg_al) { case 0x00: /* Get Device Information */ reg_dx=Files[handle]->GetInformation(); @@ -44,23 +48,46 @@ bool DOS_IOCTL(Bit8u call,Bit16u entry) { LOG_DEBUG("DOS:IOCTL:07:Fakes output status is ready for handle %d",handle); reg_al=0xff; return true; - case 0x0D: { - PhysPt ptr = SegPhys(ds)+reg_dx; - Bit8u drive = reg_bl ? reg_bl : DOS_GetDefaultDrive()+1; // A=1, B=2, C=3... - switch (reg_cl) { - case 0x60 : mem_writeb(ptr ,0x03); // special function - mem_writeb(ptr+1,(drive>=3)?0x05:0x14); // fixed disc(5), 1.44 floppy(14) - mem_writew(ptr+2,drive>=3); // nonremovable ? - mem_writew(ptr+4,0x0000); // num of cylinders - mem_writeb(ptr+6,0x00); // media type (00=other type) - break; - default : LOG_ERROR("DOS:IOCTL Call 0D:%2X Drive %2X unhandled",reg_cl,drive); - return false; + case 0x08: /* Check if block device removable */ + drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; + if (Drives[drive]) { + if (drive<2) reg_ax=0; /* Drive a,b are removable if mounted */ + else reg_ax=1; + return true; + } else { + DOS_SetError(DOSERR_INVALID_DRIVE); + return false; } - return true; + case 0x0D: /* Generic block device request */ + { + PhysPt ptr = SegPhys(ds)+reg_dx; + drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; + switch (reg_cl) { + case 0x60: /* Get Device parameters */ + mem_writeb(ptr ,0x03); // special function + mem_writeb(ptr+1,(drive>=2)?0x05:0x14); // fixed disc(5), 1.44 floppy(14) + mem_writew(ptr+2,drive>=2); // nonremovable ? + mem_writew(ptr+4,0x0000); // num of cylinders + mem_writeb(ptr+6,0x00); // media type (00=other type) + break; + default : + LOG_ERROR("DOS:IOCTL Call 0D:%2X Drive %2X unhandled",reg_cl,drive); + return false; + } + return true; } + case 0xE: /* Get Logical Drive Map */ + drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; + if (Drives[drive]) { + reg_al=0; /* Only 1 logical drive assigned */ + return true; + } else { + DOS_SetError(DOSERR_INVALID_DRIVE); + return false; + } + break; default: - LOG_ERROR("DOS:IOCTL Call %2X Handle %2X unhandled",reg_al,handle); + LOG_ERROR("DOS:IOCTL Call %2X unhandled",reg_al); return false; }; return false; diff --git a/src/dos/dos_memory.cpp b/src/dos/dos_memory.cpp index 14e8a5d..0140655 100644 --- a/src/dos/dos_memory.cpp +++ b/src/dos/dos_memory.cpp @@ -99,7 +99,7 @@ bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { mcb_segment+=pmcb->size+1; } return false; -}; +} bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks) { @@ -135,7 +135,7 @@ bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks) { *blocks=total; DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); return false; -}; +} bool DOS_FreeMemory(Bit16u segment) { @@ -151,16 +151,11 @@ bool DOS_FreeMemory(Bit16u segment) { void DOS_SetupMemory(void) { -//TODO Maybe allocate some memory for dos transfer buffers -//Although i could use bios regions for that for max free low memory MCB * mcb=(MCB *) HostMake(MEM_START,0); mcb->psp_segment=MCB_FREE; //Free mcb->size=0x9FFE - MEM_START; mcb->type=0x5a; //Last Block dos.firstMCB=MEM_START; - - // Create Dos Info Block : maximum size 95 Bytes.... - dosInfoBlock.SetLocation(DOS_GetMemory(6)); - dosInfoBlock.SetFirstMCB(RealMake(dos.firstMCB,0)); + dos_infoblock.SetFirstMCB(MEM_START); } diff --git a/src/dos/dos_misc.cpp b/src/dos/dos_misc.cpp index cce5ada..5280a52 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -54,6 +54,16 @@ static Bitu INT2A_Handler(void) { return CBRET_NONE; }; +static bool DOS_MultiplexFunctions(void) { + switch (reg_ax) { + case 0x1680: /* RELEASE CURRENT VIRTUAL MACHINE TIME-SLICE */ + //TODO Maybe do some idling but could screw up other systems :) + reg_al=0; + return true; + } + return false; +} + void DOS_SetupMisc(void) { /* Setup the dos multiplex interrupt */ @@ -61,9 +71,10 @@ void DOS_SetupMisc(void) { call_int2f=CALLBACK_Allocate(); CALLBACK_Setup(call_int2f,&INT2F_Handler,CB_IRET); RealSetVec(0x2f,CALLBACK_RealPointer(call_int2f)); + DOS_AddMultiplexHandler(DOS_MultiplexFunctions); /* Setup the dos network interrupt */ call_int2a=CALLBACK_Allocate(); CALLBACK_Setup(call_int2a,&INT2A_Handler,CB_IRET); - RealSetVec(0x2A<<2,CALLBACK_RealPointer(call_int2a)); + RealSetVec(0x2A,CALLBACK_RealPointer(call_int2a)); }; diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index 5a2857d..1046e12 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -28,69 +28,97 @@ class MOUNT : public Program { public: - MOUNT(PROGRAM_Info * program_info):Program(program_info){}; - void Run(void){ + void Run(void) + { + DOS_Drive * newdrive;char drive; + /* Parse the command line */ /* if the command line is empty show current mounts */ - if (!*prog_info->cmd_line) { - WriteOut("Current mounted drives are\n"); + if (!cmd->GetCount()) { + WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_1")); for (int d=0;dGetInfo()); + WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_2"),d+'A',Drives[d]->GetInfo()); } } return; } + std::string type="dir"; + cmd->FindString("-t",type,true); + if (type=="floppy" || type=="dir") { + Bit16u sizes[4]; + Bit8u mediaid; + std::string str_size; + if (type=="floppy") { + str_size="512,1,2847,2847";/* All space free */ + mediaid=0xF0; /* Floppy 1.44 media */ + } + if (type=="dir") { + str_size="512,127,16513,1700"; + mediaid=0xF8; /* Hard Disk */ + } + cmd->FindString("-size",str_size,true); + char number[20];const char * scan=str_size.c_str(); + Bitu index=0;Bitu count=0; + /* Parse the str_size string */ + while (*scan) { + if (*scan==',') { + number[index]=0;sizes[count++]=atoi(number); + index=0; + } else number[index++]=*scan; + scan++; + } + number[index]=0;sizes[count++]=atoi(number); - char drive; drive=toupper(*prog_info->cmd_line); - char * dir=strchr(prog_info->cmd_line,' '); if (dir) { - if (!*dir) dir=0; - else dir=trim(dir); - } - if (!isalpha(drive) || !dir) { - WriteOut("Usage MOUNT Drive-Letter Local-Directory\nSo a MOUNT c c:\\windows mounts windows directory as the c: drive in DOSBox\n"); - return; - }; - struct stat test; - if (stat(dir,&test)) { - WriteOut("Directory %s Doesn't exist",dir); - return; - } - /* Not a switch so a normal directory/file */ - if (!(test.st_mode & S_IFDIR)) { - WriteOut("%s isn't a directory",dir); - return; + if (!cmd->FindCommand(2,temp_line)) goto showusage; + if (!temp_line.size()) goto showusage; + struct stat test; + if (stat(temp_line.c_str(),&test)) { + WriteOut(MSG_Get("PROGRAM_MOUNT_ERROR_1"),temp_line.c_str()); + return; + } + /* Not a switch so a normal directory/file */ + if (!(test.st_mode & S_IFDIR)) { + WriteOut(MSG_Get("PROGRAM_MOUNT_ERROR_2"),temp_line.c_str()); + return; + } + if (temp_line[temp_line.size()-1]!=CROSS_FILESPLIT) temp_line+=CROSS_FILESPLIT; + newdrive=new localDrive(temp_line.c_str(),sizes[0],sizes[1],sizes[2],sizes[3],mediaid); } + cmd->FindCommand(1,temp_line); + if (temp_line.size()>1) goto showusage; + drive=toupper(temp_line[0]); + if (!isalpha(drive)) goto showusage; if (Drives[drive-'A']) { - WriteOut("Drive %c already mounted with %s\n",drive,Drives[drive-'A']->GetInfo()); + WriteOut(MSG_Get("PROGRAM_MOUNT_ALLREADY_MOUNDTED"),drive,Drives[drive-'A']->GetInfo()); + if (newdrive) delete newdrive; return; } - char fulldir[DOS_PATHLENGTH]; - strcpy(fulldir,dir); - static char theend[2]={CROSS_FILESPLIT,0}; - char * last=strrchr(fulldir,CROSS_FILESPLIT); - if (!last || *(++last)) strcat(fulldir,theend); - Drives[drive-'A']=new localDrive(fulldir); - WriteOut("Mounting drive %c as %s\n",drive,fulldir); + if (!newdrive) E_Exit("DOS:Can't create drive"); + Drives[drive-'A']=newdrive; + /* Set the correct media byte in the table */ + mem_writeb(Real2Phys(dos.tables.mediaid)+drive-'A',newdrive->GetMediaByte()); + WriteOut("Drive %c mounted as %s\n",drive,newdrive->GetInfo()); + return; +showusage: + WriteOut(MSG_Get("PROGRAM_MOUNT_USAGE")); + return; } }; -static void MOUNT_ProgramStart(PROGRAM_Info * info) { - MOUNT * tempmount=new MOUNT(info); - tempmount->Run() ; - delete tempmount; +static void MOUNT_ProgramStart(Program * * make) { + *make=new MOUNT; } class MEM : public Program { public: - MEM(PROGRAM_Info * program_info):Program(program_info){}; void Run(void) { /* Show conventional Memory */ WriteOut("\n"); Bit16u seg,blocks;blocks=0xffff; DOS_AllocateMemory(&seg,&blocks); - WriteOut("%10d Kb free conventional memory\n",blocks*16/1024); + WriteOut(MSG_Get("PROGRAM_MEM_CONVEN"),blocks*16/1024); /* Test for and show free XMS */ reg_ax=0x4300;CALLBACK_RunRealInt(0x2f); if (reg_al==0x80) { @@ -99,7 +127,7 @@ public: reg_ah=8; CALLBACK_RunRealFar(xms_seg,xms_off); if (!reg_bl) { - WriteOut("%10d Kb free extended memory\n",reg_dx); + WriteOut(MSG_Get("PROGRAM_MEM_EXTEND"),reg_dx); } } /* Test for and show free EMS */ @@ -108,34 +136,26 @@ public: DOS_CloseFile(handle); reg_ah=0x42; CALLBACK_RunRealInt(0x67); - WriteOut("%10d Kb free expanded memory\n",reg_bx*16); + WriteOut(MSG_Get("PROGRAM_MEM_EXPAND"),reg_bx*16); } } }; - -static void MEM_ProgramStart(PROGRAM_Info * info) { - MEM mem(info); - mem.Run(); +static void MEM_ProgramStart(Program * * make) { + *make=new MEM; } #if !defined (WIN32) /* Unix */ + class UPCASE : public Program { public: - UPCASE(PROGRAM_Info * program_info); void Run(void); - void upcasedir(char * directory); + void upcasedir(const char * directory); }; - -UPCASE::UPCASE(PROGRAM_Info * info):Program(info) { - -} - - -void UPCASE::upcasedir(char * directory) { +void UPCASE::upcasedir(const char * directory) { DIR * sdir; char fullname[512]; char newname[512]; @@ -143,10 +163,10 @@ void UPCASE::upcasedir(char * directory) { struct stat finfo; if(!(sdir=opendir(directory))) { - WriteOut("Failed to open directory %s\n",directory); + WriteOut(MSG_Get("PROGRAM_UPCASE_ERROR_DIR"),directory); return; } - WriteOut("Scanning directory %s\n",fullname); + WriteOut(MSG_Get("PROGRAM_UPCASE_SCANNING_DIR"),fullname); while (tempdata=readdir(sdir)) { if (strcmp(tempdata->d_name,".")==0) continue; if (strcmp(tempdata->d_name,"..")==0) continue; @@ -157,7 +177,7 @@ void UPCASE::upcasedir(char * directory) { strcat(newname,"/"); upcase(tempdata->d_name); strcat(newname,tempdata->d_name); - WriteOut("Renaming %s to %s\n",fullname,newname); + WriteOut(MSG_Get("PROGRAM_UPCASE_RENAME"),fullname,newname); rename(fullname,newname); stat(fullname,&finfo); if(S_ISDIR(finfo.st_mode)) { @@ -171,42 +191,60 @@ void UPCASE::upcasedir(char * directory) { void UPCASE::Run(void) { /* First check if the directory exists */ struct stat info; - WriteOut("UPCASE 0.1 Directory case convertor.\n"); - if (!strlen(prog_info->cmd_line)) { - WriteOut("Usage UPCASE [local directory]\n"); - WriteOut("This tool will convert all files and subdirectories in a directory.\n"); - WriteOut("Be VERY sure this directory contains only dos related material.\n"); - WriteOut("Otherwise you might horribly screw up your filesystem.\n"); + WriteOut(MSG_Get("PROGRAM_UPCASE_RUN_1")); + if (!cmd->GetCount()) { + WriteOut(MSG_Get("PROGRAM_UPCASE_USAGE")); return; } - if (stat(prog_info->cmd_line,&info)) { - WriteOut("%s doesn't exist\n",prog_info->cmd_line); + cmd->FindCommand(1,temp_line); + if (stat(temp_line.c_str(),&info)) { + WriteOut(MSG_Get("PROGRAM_UPCASE_RUN_ERROR_1"),temp_line.c_str()); return; } if(!S_ISDIR(info.st_mode)) { - WriteOut("%s isn't a directory\n",prog_info->cmd_line); + WriteOut(MSG_Get("PROGRAM_UPCASE_RUN_ERROR_2"),temp_line.c_str()); return; } - WriteOut("Converting the wrong directories can be very harmfull, please be carefull.\n"); - WriteOut("Are you really really sure you want to convert %s to upcase?Y/N\n",prog_info->cmd_line); + WriteOut(MSG_Get("PROGRAM_UPCASE_RUN_CHOICE"),temp_line.c_str()); Bit8u key;Bit16u n=1; DOS_ReadFile(STDIN,&key,&n); if (toupper(key)=='Y') { - upcasedir(prog_info->cmd_line); + upcasedir(temp_line.c_str()); } else { - WriteOut("Okay better not do it.\n"); + WriteOut(MSG_Get("PROGRAM_UPCASE_RUN_NO")); } } -static void UPCASE_ProgramStart(PROGRAM_Info * info) { - UPCASE * tempUPCASE=new UPCASE(info); - tempUPCASE->Run(); - delete tempUPCASE; +static void UPCASE_ProgramStart(Program * * make) { + *make=new UPCASE; } - #endif void DOS_SetupPrograms(void) { + /*Add Messages */ + MSG_Add("PROGRAM_MOUNT_STATUS_2","Drive %c is mounted as %s\n"); + MSG_Add("PROGRAM_MOUNT_STATUS_1","Current mounted drives are:\n"); + MSG_Add("PROGRAM_MOUNT_ERROR_1","Directory %s doesn't exist.\n"); + MSG_Add("PROGRAM_MOUNT_ERROR_2","%s isn't a directory\n"); + MSG_Add("PROGRAM_MOUNT_ALLREADY_MOUNTED","Drive %c already mounted with %s\n"); + MSG_Add("PROGRAM_MOUNT_USAGE","Usage MOUNT Drive-Letter Local-Directory\nSo a MOUNT c c:\\windows mounts windows directory as the c: drive in DOSBox\n"); + + MSG_Add("PROGRAM_MEM_CONVEN","%10d Kb free conventional memory\n"); + MSG_Add("PROGRAM_MEM_EXTEND","%10d Kb free extended memory\n"); + MSG_Add("PROGRAM_MEM_EXPAND","%10d Kb free expanded memory\n"); + +#if !defined (WIN32) /* Unix */ + MSG_Add("PROGRAM_UPCASE_ERROR_DIR","Failed to open directory %s\n"); + MSG_Add("PROGRAM_UPCASE_SCANNING_DIR","Scanning directory %s\n"); + MSG_Add("PROGRAM_UPCASE_RENAME","Renaming %s to %s\n"); + MSG_Add("PROGRAM_UPCASE_RUN_1","UPCASE 0.1 Directory case convertor.\n"); + MSG_Add("PROGRAM_UPCASE_USAGE","Usage UPCASE [local directory]\nThis tool will convert all files and subdirectories in a directory.\nBe VERY sure this directory contains only dos related material.\nOtherwise you might horribly screw up your filesystem.\n"); + MSG_Add("PROGRAM_UPCASE_RUN_ERROR_1","%s doesn't exist\n"); + MSG_Add("PROGRAM_UPCASE_RUN_ERROR_2","%s isn't a directory\n"); + MSG_Add("PROGRAM_UPCASE_RUN_CHOICE","Converting the wrong directories can be very harmfull, please be carefull.\nAre you really really sure you want to convert %s to upcase?Y/N\n"); + MSG_Add("PROGRAM_UPCASE_RUN_NO","Okay better not do it.\n"); +#endif + /*regular setup*/ PROGRAMS_MakeFile("MOUNT.COM",MOUNT_ProgramStart); PROGRAMS_MakeFile("MEM.COM",MEM_ProgramStart); #if !defined (WIN32) /* Unix */ diff --git a/src/dos/dos_tables.cpp b/src/dos/dos_tables.cpp index 2318655..dc94f92 100644 --- a/src/dos/dos_tables.cpp +++ b/src/dos/dos_tables.cpp @@ -20,25 +20,18 @@ #include "mem.h" #include "dos_inc.h" -#if defined (_MSC_VER) #pragma pack(1) -#endif struct DOS_TableCase { Bit16u size; Bit8u chars[256]; } -#if defined (_MSC_VER) -; -#pragma pack() -#else -__attribute__ ((packed)); -#endif - +GCC_ATTRIBUTE (packed); +#pragma pack () RealPt DOS_TableUpCase; RealPt DOS_TableLowCase; -static Bit16u dos_memseg=0xd000; +static Bit16u dos_memseg; Bit16u DOS_GetMemory(Bit16u pages) { if (pages+dos_memseg>=0xe000) { E_Exit("DOS:Not enough memory for internal tables"); @@ -50,9 +43,21 @@ Bit16u DOS_GetMemory(Bit16u pages) { void DOS_SetupTables(void) { + dos_memseg=0xd000; + Bit16u seg;Bitu i; dos.tables.indosflag=RealMake(DOS_GetMemory(1),0); + dos.tables.mediaid=RealMake(DOS_GetMemory(2),0); + dos.tables.tempdta=RealMake(DOS_GetMemory(4),0); + for (i=0;i #include #include "dosbox.h" -#include "dos_system.h" +#include "dos_inc.h" #include "drives.h" #include "support.h" #include "cross.h" @@ -38,13 +38,14 @@ public: Bit16u GetInformation(void); private: FILE * fhandle; + enum { NONE,READ,WRITE } last_action; Bit16u info; }; bool localDrive:: FileCreate(DOS_File * * file,char * name,Bit16u attributes) { //TODO Maybe care for attributes but not likely - char newname[512]; + char newname[CROSS_LEN]; strcpy(newname,basedir); strcat(newname,name); CROSS_FILENAME(newname); @@ -67,7 +68,7 @@ bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) { // return false; }; - char newname[512]; + char newname[CROSS_LEN]; strcpy(newname,basedir); strcat(newname,name); CROSS_FILENAME(newname); @@ -79,7 +80,7 @@ bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) { }; bool localDrive::FileUnlink(char * name) { - char newname[512]; + char newname[CROSS_LEN]; strcpy(newname,basedir); strcat(newname,name); CROSS_FILENAME(newname); @@ -88,79 +89,64 @@ bool localDrive::FileUnlink(char * name) { }; -bool localDrive::FindFirst(char * search,DTA_FindBlock * dta) { - //TODO Find some way for lowcase and highcase drives oneday - char name[512]; - strcpy(name,basedir); - strcat(name,search); - CROSS_FILENAME(name); - char * last=strrchr(name, CROSS_FILESPLIT); - *last=0; - last++; - /* Check the wildcard string for an extension */ - strcpy(wild_name,last); - wild_ext=strrchr(wild_name,'.'); - if (wild_ext) { - *wild_ext++=0; - } - strcpy(directory,name); -/* make sure / is last sign */ - if (pdir) closedir(pdir); - if(directory[(strlen(directory)-1)]!=CROSS_FILESPLIT) strcat(directory, "/"); - if((pdir=opendir(directory))==NULL) return false; +bool localDrive::FindFirst(char * _dir,DOS_DTA & dta) { + if (srch_opendir) closedir(srch_opendir); + strcpy(srch_dir,basedir); + strcat(srch_dir,_dir); + CROSS_FILENAME(srch_dir); + + char end[2]={CROSS_FILESPLIT,0}; + if (srch_dir[strlen(srch_dir)-1]!=CROSS_FILESPLIT) strcat(srch_dir,end); + if((srch_opendir=opendir(srch_dir))==NULL) return false; return FindNext(dta); } -bool localDrive::FindNext(DTA_FindBlock * dta) { - Bit8u tempattr=0; - struct dirent *tempdata; +bool localDrive::FindNext(DOS_DTA & dta) { + struct dirent * dir_ent; struct stat stat_block; - char werkbuffer[512]; + char full_name[CROSS_LEN]; + Bit8u srch_attr;char srch_pattern[DOS_NAMELENGTH_ASCII]; + Bit8u find_attr; + + if(!srch_opendir) return false; - if(pdir==NULL){ - return false; - }; - start: - if((tempdata=readdir(pdir))==NULL) { - closedir(pdir); - pdir=NULL; + dta.GetSearchParams(srch_attr,srch_pattern); + again: + if((dir_ent=readdir(srch_opendir))==NULL) { + closedir(srch_opendir); + srch_opendir=NULL; return false; } - strcpy(werkbuffer,tempdata->d_name); - if (wild_ext) { - char * ext=strrchr(werkbuffer,'.'); - if (!ext) ext="*"; - else *ext++=0; - if(!wildcmp(wild_ext,ext)) goto start; + if(!WildFileCmp(dir_ent->d_name,srch_pattern)) goto again; + strcpy(full_name,srch_dir); + strcat(full_name,dir_ent->d_name); + if(stat(full_name,&stat_block)!=0){ + goto again; } - if(!wildcmp(wild_name,werkbuffer)) goto start; - werkbuffer[0]='\0'; - strcpy(werkbuffer,directory); - strcat(werkbuffer,tempdata->d_name); - if(stat(werkbuffer,&stat_block)!=0){ - /*nu is er iets fout!*/ exit(1); - } - if(S_ISDIR(stat_block.st_mode)) tempattr=DOS_ATTR_DIRECTORY; - else tempattr=DOS_ATTR_ARCHIVE; - if(!(dta->sattr & tempattr)) goto start; - /*file is oke so filldtablok */ - if(strlen(tempdata->d_name)<=DOS_NAMELENGTH) strcpy(dta->name,upcase(tempdata->d_name)); - dta->attr=tempattr; - dta->size=(Bit32u) stat_block.st_size; + if(S_ISDIR(stat_block.st_mode)) find_attr=DOS_ATTR_DIRECTORY; + else find_attr=DOS_ATTR_ARCHIVE; + if (~srch_attr & find_attr & (DOS_ATTR_DIRECTORY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM)) goto again; + /*file is okay, setup everything to be copied in DTA Block */ + char find_name[DOS_NAMELENGTH_ASCII];Bit16u find_date,find_time;Bit32u find_size; + if(strlen(dir_ent->d_name)d_name); + upcase(find_name); + } else strcpy(find_name,"LONGNAME.ERR"); + find_size=(Bit32u) stat_block.st_size; struct tm *time; if((time=localtime(&stat_block.st_mtime))!=0){ - - dta->time=(time->tm_hour<<11)+(time->tm_min<<5)+(time->tm_sec/2); /* standard way. */ - dta->date=((time->tm_year-80)<<9)+((time->tm_mon+1)<<5)+(time->tm_mday); + find_date=DOS_PackDate(time->tm_year+1900,time->tm_mon+1,time->tm_mday); + find_time=DOS_PackTime(time->tm_hour,time->tm_min,time->tm_sec); }else { - dta->time=6; - dta->date=4; + find_time=6; + find_date=4; } + dta.SetResult(find_name,find_size,find_date,find_time,find_attr); return true; } bool localDrive::GetFileAttr(char * name,Bit16u * attr) { - char newname[512]; + char newname[CROSS_LEN]; strcpy(newname,basedir); strcat(newname,name); CROSS_FILENAME(newname); @@ -175,7 +161,7 @@ bool localDrive::GetFileAttr(char * name,Bit16u * attr) { }; bool localDrive::MakeDir(char * dir) { - char newdir[512]; + char newdir[CROSS_LEN]; strcpy(newdir,basedir); strcat(newdir,dir); CROSS_FILENAME(newdir); @@ -189,7 +175,7 @@ bool localDrive::MakeDir(char * dir) { } bool localDrive::RemoveDir(char * dir) { - char newdir[512]; + char newdir[CROSS_LEN]; strcpy(newdir,basedir); strcat(newdir,dir); CROSS_FILENAME(newdir); @@ -198,7 +184,7 @@ bool localDrive::RemoveDir(char * dir) { } bool localDrive::TestDir(char * dir) { - char newdir[512]; + char newdir[CROSS_LEN]; strcpy(newdir,basedir); strcat(newdir,dir); CROSS_FILENAME(newdir); @@ -207,11 +193,11 @@ bool localDrive::TestDir(char * dir) { } bool localDrive::Rename(char * oldname,char * newname) { - char newold[512]; + char newold[CROSS_LEN]; strcpy(newold,basedir); strcat(newold,oldname); CROSS_FILENAME(newold); - char newnew[512]; + char newnew[CROSS_LEN]; strcpy(newnew,basedir); strcat(newnew,newname); CROSS_FILENAME(newnew); @@ -220,18 +206,18 @@ bool localDrive::Rename(char * oldname,char * newname) { }; -bool localDrive::FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) { +bool localDrive::AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) { /* Always report 100 mb free should be enough */ /* Total size is always 1 gb */ - *bytes=512; - *sectors=127; - *clusters=16513; - *free=1700; + *_bytes_sector=allocation.bytes_sector; + *_sectors_cluster=allocation.sectors_cluster; + *_total_clusters=allocation.total_clusters; + *_free_clusters=allocation.free_clusters; return true; }; -bool localDrive::FileExists(const char* name) const { - char newname[512]; +bool localDrive::FileExists(const char* name) { + char newname[CROSS_LEN]; strcpy(newname,basedir); strcat(newname,name); CROSS_FILENAME(newname); @@ -241,38 +227,60 @@ bool localDrive::FileExists(const char* name) const { return true; } -bool localDrive::FileStat(const char* name, struct stat* const stat_block) const { - char newname[512]; +bool localDrive::FileStat(const char* name, FileStat_Block * const stat_block) { + char newname[CROSS_LEN]; strcpy(newname,basedir); strcat(newname,name); CROSS_FILENAME(newname); - if(stat(newname,stat_block)!=0) return false; - return true; + struct stat temp_stat; + if(stat(newname,&temp_stat)!=0) return false; + /* Convert the stat to a FileStat */ + struct tm *time; + if((time=localtime(&temp_stat.st_mtime))!=0) { + stat_block->time=DOS_PackTime(time->tm_hour,time->tm_min,time->tm_sec); + stat_block->date=DOS_PackDate(time->tm_year,time->tm_mon,time->tm_mday); + } else { + } + stat_block->size=(Bit32u)temp_stat.st_size; + return true; } +Bit8u localDrive::GetMediaByte(void) { + return allocation.mediaid; +} -localDrive::localDrive(char * startdir) { +localDrive::localDrive(const char * startdir,Bit16u _bytes_sector,Bit16u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid) { strcpy(basedir,startdir); sprintf(info,"local directory %s",startdir); - pdir=NULL; + srch_opendir=NULL; + allocation.bytes_sector=_bytes_sector; + allocation.sectors_cluster=_sectors_cluster; + allocation.total_clusters=_total_clusters; + allocation.free_clusters=_free_clusters; + allocation.mediaid=_mediaid; } +//TODO Maybe use fflush, but that seemed to fuck up in visual c bool localFile::Read(Bit8u * data,Bit16u * size) { + if (last_action==WRITE) fseek(fhandle,ftell(fhandle),SEEK_SET); + last_action=READ; *size=fread(data,1,*size,fhandle); return true; }; bool localFile::Write(Bit8u * data,Bit16u * size) { - if(*size==0){ + if (last_action==READ) fseek(fhandle,ftell(fhandle),SEEK_SET); + last_action=WRITE; + if(*size==0){ return (!ftruncate(fileno(fhandle),ftell(fhandle))); } else { - *size=fwrite(data,1,*size,fhandle); - return true; + *size=fwrite(data,1,*size,fhandle); + return true; } } bool localFile::Seek(Bit32u * pos,Bit32u type) { @@ -291,7 +299,7 @@ bool localFile::Seek(Bit32u * pos,Bit32u type) { //TODO Hope we don't encouter files with 64 bits size Bit32u * fake_pos=(Bit32u*)&temppos; *pos=*fake_pos; - + last_action=NONE; return true; } @@ -304,9 +312,22 @@ Bit16u localFile::GetInformation(void) { return info; } + localFile::localFile(FILE * handle,Bit16u devinfo) { fhandle=handle; info=devinfo; + struct stat temp_stat; + fstat(fileno(handle),&temp_stat); + struct tm * ltime; + if((ltime=localtime(&temp_stat.st_mtime))!=0) { + time=DOS_PackTime(ltime->tm_hour,ltime->tm_min,ltime->tm_sec); + date=DOS_PackDate(ltime->tm_year,ltime->tm_mon,ltime->tm_mday); + } else { + time=0;date=0; + } + size=(Bit32u)temp_stat.st_size; + attr=DOS_ATTR_ARCHIVE; + last_action=NONE; } diff --git a/src/dos/drive_virtual.cpp b/src/dos/drive_virtual.cpp index 0be5dc6..84235e3 100644 --- a/src/dos/drive_virtual.cpp +++ b/src/dos/drive_virtual.cpp @@ -21,13 +21,13 @@ #include #include #include "dosbox.h" -#include "dos_system.h" +#include "dos_inc.h" #include "drives.h" #include "support.h" #include "cross.h" struct VFILE_Block { - char * name; + const char * name; Bit8u * data; Bit32u size; VFILE_Block * next; @@ -36,7 +36,7 @@ struct VFILE_Block { static VFILE_Block * first_file; -void VFILE_Register(char * name,Bit8u * data,Bit32u size) { +void VFILE_Register(const char * name,Bit8u * data,Bit32u size) { VFILE_Block * new_file=new VFILE_Block; new_file->name=name; new_file->data=data; @@ -153,16 +153,14 @@ bool Virtual_Drive::TestDir(char * dir) { return false; } -bool Virtual_Drive::FileStat(const char* name, struct stat* const stat_block) const { - VFILE_Block * cur_file=first_file; +bool Virtual_Drive::FileStat(const char* name, FileStat_Block * const stat_block){ + VFILE_Block * cur_file=first_file; while (cur_file) { if (strcasecmp(name,cur_file->name)==0) { - stat_block->st_size=cur_file->size; - struct tm tijd; - tijd.tm_hour=0;tijd.tm_min=0;tijd.tm_sec=0; - tijd.tm_year=80;tijd.tm_mday=6;tijd.tm_mon=0; - stat_block->st_mtime=mktime(&tijd); - /* more not needed at the moment (fcbopen.....)*/ + stat_block->attr=DOS_ATTR_ARCHIVE; + stat_block->size=cur_file->size; + stat_block->date=DOS_PackDate(2002,0,0); + stat_block->time=DOS_PackTime(12,12,12); return true; } cur_file=cur_file->next; @@ -170,7 +168,7 @@ bool Virtual_Drive::FileStat(const char* name, struct stat* const stat_block) co return false; } -bool Virtual_Drive::FileExists(const char* name) const { +bool Virtual_Drive::FileExists(const char* name){ VFILE_Block * cur_file=first_file; while (cur_file) { if (strcasecmp(name,cur_file->name)==0) return true; @@ -179,32 +177,17 @@ bool Virtual_Drive::FileExists(const char* name) const { return false; } -static void FillDTABlock(DTA_FindBlock * dta,VFILE_Block * fill_file) { - strcpy(dta->name,fill_file->name); - dta->size=fill_file->size; - dta->attr=DOS_ATTR_ARCHIVE; - dta->time=2; - dta->date=6; -} - -bool Virtual_Drive::FindFirst(char * search,DTA_FindBlock * dta) { +bool Virtual_Drive::FindFirst(char * _dir,DOS_DTA & dta) { search_file=first_file; - strcpy(search_string,search); - while (search_file) { - if (wildcmp(search_string,search_file->name)) { - FillDTABlock(dta,search_file); - search_file=search_file->next; - return true; - } - search_file=search_file->next; - } - return false; + return FindNext(dta); } -bool Virtual_Drive::FindNext(DTA_FindBlock * dta) { +bool Virtual_Drive::FindNext(DOS_DTA & dta) { + Bit8u attr;char pattern[DOS_NAMELENGTH_ASCII]; + dta.GetSearchParams(attr,pattern); while (search_file) { - if (wildcmp(search_string,search_file->name)) { - FillDTABlock(dta,search_file); + if (WildFileCmp(search_file->name,pattern)) { + dta.SetResult(search_file->name,search_file->size,6,2,DOS_ATTR_ARCHIVE); search_file=search_file->next; return true; } @@ -221,13 +204,17 @@ bool Virtual_Drive::Rename(char * oldname,char * newname) { return false; } -bool Virtual_Drive::FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) { +bool Virtual_Drive::AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) { /* Always report 100 mb free should be enough */ /* Total size is always 1 gb */ - *bytes=512; - *sectors=127; - *clusters=16513; - *free=00; + *_bytes_sector=512; + *_sectors_cluster=127; + *_total_clusters=16513; + *_free_clusters=00; return true; } +Bit8u Virtual_Drive::GetMediaByte(void) { + return 0xF8; +} + diff --git a/src/dos/drives.cpp b/src/dos/drives.cpp index 2a71172..2785b18 100644 --- a/src/dos/drives.cpp +++ b/src/dos/drives.cpp @@ -19,6 +19,58 @@ #include "dosbox.h" #include "dos_system.h" #include "drives.h" +#include "support.h" + +bool WildFileCmp(const char * file, const char * wild) +{ + char file_name[9]; + char file_ext[4]; + char wild_name[9]; + char wild_ext[4]; + char * find_ext; + Bitu r; + + strcpy(file_name," "); + strcpy(file_ext," "); + strcpy(wild_name," "); + strcpy(wild_ext," "); + + find_ext=strchr(file,'.'); + if (find_ext) { + Bitu size=find_ext-file;if (size>8) size=8; + memcpy(file_name,file,size); + find_ext++; + memcpy(file_ext,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); + } else { + memcpy(file_name,file,(strlen(file) > 8) ? 8 : strlen(file)); + } + upcase(file_name);upcase(file_ext); + find_ext=strchr(wild,'.'); + if (find_ext) { + Bitu size=find_ext-wild;if (size>8) size=8; + memcpy(wild_name,wild,size); + find_ext++; + memcpy(wild_ext,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); + } else { + memcpy(wild_name,wild,(strlen(wild) > 8) ? 8 : strlen(wild)); + } + upcase(wild_name);upcase(wild_ext); + /* Names are right do some checking */ + r=0; + while (r<8) { + if (wild_name[r]=='*') goto checkext; + if (wild_name[r]!='?' && wild_name[r]!=file_name[r]) return false; + r++; + } +checkext: + while (r<3) { + if (wild_ext[r]=='*') return true; + if (wild_ext[r]!='?' && wild_ext[r]!=file_ext[r]) return false; + r++; + } + return true; +} + DOS_Drive::DOS_Drive() { diff --git a/src/dos/drives.h b/src/dos/drives.h index b46e376..910f147 100644 --- a/src/dos/drives.h +++ b/src/dos/drives.h @@ -22,30 +22,39 @@ #include #include #include "dos_system.h" +#include "cross.h" + + +bool WildFileCmp(const char * file, const char * wild); class localDrive : public DOS_Drive { public: - localDrive(char * startdir); + localDrive(const char * startdir,Bit16u _bytes_sector,Bit16u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid); bool FileOpen(DOS_File * * file,char * name,Bit32u flags); bool FileCreate(DOS_File * * file,char * name,Bit16u attributes); bool FileUnlink(char * name); bool RemoveDir(char * dir); bool MakeDir(char * dir); bool TestDir(char * dir); - bool FindFirst(char * search,DTA_FindBlock * dta); - bool FindNext(DTA_FindBlock * dta); + bool FindFirst(char * _dir,DOS_DTA & dta); + bool FindNext(DOS_DTA & dta); bool GetFileAttr(char * name,Bit16u * attr); bool Rename(char * oldname,char * newname); - bool FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free); - bool FileExists(const char* name) const ; - bool FileStat(const char* name, struct stat* const stat_block) const; + bool AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters); + bool FileExists(const char* name); + bool FileStat(const char* name, FileStat_Block * const stat_block); + Bit8u GetMediaByte(void); private: - bool FillDTABlock(DTA_FindBlock * dta); - char basedir[512]; - char directory[512]; - char wild_name[15]; - char * wild_ext; - DIR *pdir; + char basedir[CROSS_LEN]; + char srch_dir[CROSS_LEN]; + DIR * srch_opendir; + struct { + Bit16u bytes_sector; + Bit16u sectors_cluster; + Bit16u total_clusters; + Bit16u free_clusters; + Bit8u mediaid; + } allocation; }; struct VFILE_Block; @@ -60,17 +69,16 @@ public: bool RemoveDir(char * dir); bool MakeDir(char * dir); bool TestDir(char * dir); - bool FindFirst(char * search,DTA_FindBlock * dta); - bool FindNext(DTA_FindBlock * dta); + bool FindFirst(char * _dir,DOS_DTA & dta); + bool FindNext(DOS_DTA & dta); bool GetFileAttr(char * name,Bit16u * attr); bool Rename(char * oldname,char * newname); - bool FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free); - bool FileExists(const char* name) const ; - bool FileStat(const char* name, struct stat* const stat_block) const; - + bool AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters); + bool FileExists(const char* name); + bool FileStat(const char* name, FileStat_Block* const stat_block); + Bit8u GetMediaByte(void); private: VFILE_Block * search_file; - char search_string[255]; }; #endif diff --git a/src/dosbox.cpp b/src/dosbox.cpp index e5ea0c7..83ed464 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -35,119 +35,53 @@ #include "setup.h" #include "cross.h" #include "programs.h" +#include "support.h" -char dosbox_basedir[CROSS_LEN]; +Config * control; +Bitu errorlevel=1; + +/* The whole load of startups for all the subfunctions */ +void MSG_Init(Section_prop *); +void MEM_Init(Section *); +void IO_Init(Section * ); +void CALLBACK_Init(Section*); +void PROGRAMS_Init(Section*); + +void RENDER_Init(Section*); +void VGA_Init(Section*); + +void DOS_Init(Section*); -#if 0 - -int main(int argc, char* argv[]) { - - - - /* Strip out the dosbox startup directory */ - - - - /* Handle the command line for new stuff to add to autoexec.bat */ - int argl=1; - if (argc>1) { - if (*argv[1]!='-') { - struct stat test; - if (stat(argv[1],&test)) { - E_Exit("%s Doesn't exist",argv[1]); - } - /* Not a switch so a normal directory/file */ - if (test.st_mode & S_IFDIR) { - SHELL_AddAutoexec("MOUNT C %s",argv[1]); - SHELL_AddAutoexec("C:"); - } else { - char * name=strrchr(argv[1],CROSS_FILESPLIT); - if (!name) E_Exit("This is weird %s",argv[1]); - *name++=0; - if (access(argv[1],F_OK)) E_Exit("Illegal Directory %s",argv[1]); - SHELL_AddAutoexec("MOUNT C %s",argv[1]); - SHELL_AddAutoexec("C:"); - SHELL_AddAutoexec(name); - } - argl++; - } - } - bool sw_c=false; - while (arglLastTicks) { - Bit32u ticks=new_ticks-LastTicks; - if (ticks>20) ticks=20; -// if (ticks>3) LOG_DEBUG("Ticks %d",ticks); - LastTicks=new_ticks; - TIMER_AddTicks(ticks); - cycles+=cpu_cycles*ticks; - } TIMER_CheckPIT(); - GFX_Events(); PIC_runIRQs(); - return (*cpudecoder)(cycles); + Bitu ret; + do { + PIC_IRQAgain=false; + ret=(*cpudecoder)(cpu_cycles); + } while (!ret && PIC_IRQAgain); +#if C_DEBUG + if (DEBUG_ExitLoop()) return 0; +#endif + return ret; } void DOSBOX_SetLoop(LoopHandler * handler) { @@ -200,111 +122,89 @@ void DOSBOX_RunMachine(void){ } while (!ret); } +static void DOSBOX_RealInit(Section * sec) { + Section_prop * section=static_cast(sec); + /* Initialize some dosbox internals */ + errorlevel=section->Get_int("warnings"); + MSG_Add("DOSBOX_CONFIGFILE_HELP","General Dosbox settings\n"); + LastTicks=GetTicks(); + DOSBOX_SetLoop(&Normal_Loop); + MSG_Init(section); +} -static void InitSystems(void) { - MSG_Init(); - MEM_Init(); - IO_Init(); - CALLBACK_Init(); - PROGRAMS_Init(); - HARDWARE_Init(); - TIMER_Init(); - CPU_Init(); +void DOSBOX_Init(void) { +// Section * sec; + Section_prop * secprop; + Section_line * secline; + + /* Setup all the different modules making up DOSBox */ + + secprop=control->AddSection_prop("dosbox",&DOSBOX_RealInit); + secprop->Add_string("language",""); +#if C_DEBUG + secprop->Add_int("warnings",4); +#else + secprop->Add_int("warnings",0); +#endif + + secprop->AddInitFunction(&MEM_Init); + secprop->AddInitFunction(&IO_Init); + secprop->AddInitFunction(&CALLBACK_Init); + secprop->AddInitFunction(&PIC_Init); + secprop->AddInitFunction(&PROGRAMS_Init); + secprop->AddInitFunction(&TIMER_Init); + secprop->AddInitFunction(&RENDER_Init); + secprop->Add_string("snapshots","snapshots"); + + secprop=control->AddSection_prop("cpu",&CPU_Init); + secprop->Add_int("cycles",4000); + + secprop->AddInitFunction(&DMA_Init); + secprop->AddInitFunction(&VGA_Init); + secprop->AddInitFunction(&KEYBOARD_Init); + secprop->AddInitFunction(&MOUSE_Init); + secprop->AddInitFunction(&JOYSTICK_Init); + + secprop=control->AddSection_prop("mixer",&MIXER_Init); +#if C_DEBUG + secprop=control->AddSection_prop("debug",&DEBUG_Init); +#endif + secprop=control->AddSection_prop("sblaster",&SBLASTER_Init); + secprop->Add_hex("base",0x220); + secprop->Add_int("irq",7); + secprop->Add_int("dma",1); + secprop->Add_int("hdma",5); + secprop->Add_bool("enabled",true); + + secprop->AddInitFunction(&ADLIB_Init); + secprop->Add_bool("adlib",true); + secprop->AddInitFunction(&CMS_Init); + secprop->Add_bool("cms",false); + + secprop=control->AddSection_prop("speaker",&PCSPEAKER_Init); + secprop->Add_bool("sinewave",false); + secprop->AddInitFunction(&TANDYSOUND_Init); + secprop->Add_bool("tandy",false); + + secprop=control->AddSection_prop("bios",&BIOS_Init); + secprop->AddInitFunction(&INT10_Init); + + /* All the DOS Related stuff, which will eventually start up in the shell */ + //TODO Maybe combine most of the dos stuff in one section like ems,xms + secprop=control->AddSection_prop("dos",&DOS_Init); + secprop->AddInitFunction(&EMS_Init); + secprop->Add_int("emssize",4); + secprop->AddInitFunction(&XMS_Init); + secprop->Add_int("xmssize",8); + + secline=control->AddSection_line("autoexec",&AUTOEXEC_Init); + + control->SetStartUp(&SHELL_Init); + #if C_FPU FPU_Init(); #endif - MIXER_Init(); -#if C_DEBUG - DEBUG_Init(); -#endif - //Start up individual hardware - DMA_Init(); - PIC_Init(); - VGA_Init(); - KEYBOARD_Init(); - MOUSE_Init(); - JOYSTICK_Init(); - SBLASTER_Init(); - TANDY_Init(); - PCSPEAKER_Init(); - ADLIB_Init(); - CMS_Init(); - - PLUGIN_Init(); -/* Most of teh interrupt handlers */ - BIOS_Init(); - DOS_Init(); - EMS_Init(); //Needs dos first - XMS_Init(); //Needs dos first - -/* Setup the normal system loop */ - LastTicks=GetTicks(); - DOSBOX_SetLoop(&Normal_Loop); -// DOSBOX_SetLoop(&Speed_Loop); } -void DOSBOX_Init(int argc, char* argv[]) { -/* Find the base directory */ - SHELL_AddAutoexec("SET PATH=Z:\\"); - SHELL_AddAutoexec("SET COMSPEC=Z:\\COMMAND.COM"); - strcpy(dosbox_basedir,argv[0]); - char * last=strrchr(dosbox_basedir,CROSS_FILESPLIT); //if windowsversion fails: - if (!last){ - getcwd(dosbox_basedir,CROSS_LEN); - char a[2]; - a[0]=CROSS_FILESPLIT; - a[1]='\0'; - strcat(dosbox_basedir,a); - } else { - *++last=0; - } - /* Parse the command line with a setup function */ - int argl=1; - if (argc>1) { - if (*argv[1]!='-') { - struct stat test; - if (stat(argv[1],&test)) { - E_Exit("%s Doesn't exist",argv[1]); - } - /* Not a switch so a normal directory/file */ - if (test.st_mode & S_IFDIR) { - SHELL_AddAutoexec("MOUNT C %s",argv[1]); - SHELL_AddAutoexec("C:"); - } else { - char * name=strrchr(argv[1],CROSS_FILESPLIT); - if (!name) E_Exit("This is weird %s",argv[1]); - *name++=0; - if (access(argv[1],F_OK)) E_Exit("Illegal Directory %s",argv[1]); - SHELL_AddAutoexec("MOUNT C %s",argv[1]); - SHELL_AddAutoexec("C:"); - SHELL_AddAutoexec(name); - } - argl++; - } - } - bool sw_c=false; - while (argl +#include + #include "dosbox.h" #include "video.h" #include "render.h" - - +#include "setup.h" +#include "keyboard.h" +#include "cross.h" #define MAX_RES 2048 + + struct PalData { struct { Bit8u red; @@ -51,8 +57,104 @@ static struct { PalData pal; bool remake; bool enlarge; + bool screenshot; } render; +static const char * snapshots_dir; + +/* Take a screenshot of the data that should be rendered */ +static void TakeScreenShot(Bit8u * bitmap) { + Bitu last=0;char file_name[CROSS_LEN]; + DIR * dir;struct dirent * dir_ent; + png_structp png_ptr; + png_infop info_ptr; + png_bytep * row_pointers; + png_color palette[256]; + Bitu i; + +/* First try to alloacte the png structures */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); + if (!png_ptr) return; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr,(png_infopp)NULL); + return; + } +/* Find a filename to open */ + dir=opendir(snapshots_dir); + if (!dir) { + LOG_WARN("Can't open snapshot dir %s",snapshots_dir); + return; + } + while (dir_ent=readdir(dir)) { + char tempname[CROSS_LEN]; + strcpy(tempname,dir_ent->d_name); + char * test=strstr(tempname,".png"); + if (!test) continue; + *test=0; + if (strlen(tempname)<5) continue; + if (strncmp(tempname,"snap",4)!=0) continue; + Bitu num=atoi(&tempname[4]); + if (num>=last) last=num+1; + } + closedir(dir); + sprintf(file_name,"%s%csnap%05d.png",snapshots_dir,CROSS_FILESPLIT,last); +/* Open the actual file */ + FILE * fp=fopen(file_name,"wb"); + if (!fp) { + LOG_WARN("Can't open snapshot file %s",file_name); + return; + } +/* Finalize the initing of png library */ + png_init_io(png_ptr, fp); + png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192); + + if (render.src.bpp==8) { + png_set_IHDR(png_ptr, info_ptr, render.src.width, render.src.height, + 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + for (i=0;i<256;i++) { + palette[i].red=render.pal.rgb[i].red; + palette[i].green=render.pal.rgb[i].green; + palette[i].blue=render.pal.rgb[i].blue; + } + png_set_PLTE(png_ptr, info_ptr, palette,256); + } else { + png_set_IHDR(png_ptr, info_ptr, render.src.width, render.src.height, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + } + /*Allocate an array of scanline pointers*/ + row_pointers=(png_bytep*)malloc(render.src.height*sizeof(png_bytep)); + for (i=0;irender.pal.last) return; @@ -98,8 +200,11 @@ void RENDER_Draw(Bit8u * bitdata) { render.remake=false; } render.handler(&src_data); + if (render.screenshot) { + TakeScreenShot(src_data); + render.screenshot=false; + } Draw_8_Normal(src_data,bitdata); - } @@ -151,10 +256,15 @@ void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu } - -void RENDER_Init(void) { +static void EnableScreenShot(void) { + render.screenshot=true; +} +void RENDER_Init(Section * sec) { + Section_prop * section=static_cast(sec); + snapshots_dir=section->Get_string("snapshots"); render.pal.first=256; render.pal.last=0; - render.enlarge=false; + render.enlarge=false; + KEYBOARD_AddEvent(KBD_f5,CTRL_PRESSED,EnableScreenShot); } diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 63810e9..7da7a2d 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -18,8 +18,9 @@ #include #include -#include -#include +#include +#include + #include "dosbox.h" #include "video.h" #include "keyboard.h" @@ -27,7 +28,8 @@ #include "joystick.h" #include "pic.h" #include "timer.h" - +#include "setup.h" +#include "debug.h" //#define DISABLE_JOYSTICK @@ -39,13 +41,23 @@ struct SDL_Block { Bitu bpp; GFX_DrawHandler * draw; GFX_ResizeHandler * resize; - bool mouse_grabbed; bool full_screen; SDL_Thread * thread; SDL_mutex * mutex; SDL_Surface * surface; SDL_Joystick * joy; SDL_Color pal[256]; + struct { + bool autolock; + bool autoenable; + bool requestlock; + bool locked; + Bitu sensitivity; + } mouse; + struct { + Bitu skip; + Bitu count; + } frames ; }; static SDL_Block sdl; @@ -98,8 +110,8 @@ void GFX_Resize(Bitu width,Bitu height,Bitu bpp,GFX_ResizeHandler * resize) { } static void CaptureMouse() { - sdl.mouse_grabbed=!sdl.mouse_grabbed; - if (sdl.mouse_grabbed) { + sdl.mouse.locked=!sdl.mouse.locked; + if (sdl.mouse.locked) { SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(SDL_DISABLE); } else { @@ -108,6 +120,16 @@ static void CaptureMouse() { } } +static void DecreaseSkip() { + if (sdl.frames.skip>0) sdl.frames.skip--; + LOG_MSG("Frame Skip %d",sdl.frames.skip); +} + +static void IncreaseSkip() { + if (sdl.frames.skip<10) sdl.frames.skip++; + LOG_MSG("Frame Skip %d",sdl.frames.skip); +} + static void SwitchFullScreen(void) { GFX_Stop(); sdl.full_screen=!sdl.full_screen; @@ -120,6 +142,10 @@ static void SwitchFullScreen(void) { ResetScreen(); GFX_Start(); } +//only prototype existed +void GFX_SwitchFullScreen(void) { + SwitchFullScreen(); +} static void GFX_Redraw() { #if C_THREADED @@ -127,6 +153,9 @@ static void GFX_Redraw() { E_Exit("Can't Lock Mutex"); }; #endif + + if (++sdl.frames.countpixels && sdl.draw) (*sdl.draw)((Bit8u *)sdl.surface->pixels); @@ -134,6 +163,7 @@ static void GFX_Redraw() { if (sdl.full_screen) SDL_Flip(sdl.surface); else SDL_UpdateRect(sdl.surface,0,0,0,0); }; +skipframe: #if C_THREADED if (SDL_mutexV(sdl.mutex)) { E_Exit("Can't Release Mutex"); @@ -193,32 +223,53 @@ void GFX_Start() { sdl.active=true; } +static void GUI_ShutDown(Section * sec) { + GFX_Stop(); + if (sdl.mouse.locked) CaptureMouse(); + if (sdl.full_screen) SwitchFullScreen(); +} -void GFX_StartUp() { +static void GUI_StartUp(Section * sec) { + MSG_Add("SDL_CONFIGFILE_HELP","SDL related options.\n"); + sec->AddDestroyFunction(&GUI_ShutDown); + Section_prop * section=static_cast(sec); sdl.active=false; sdl.full_screen=false; + sdl.frames.skip=0; + sdl.frames.count=0; sdl.draw=0; + sdl.mouse.locked=false; + sdl.mouse.requestlock=false; + sdl.mouse.autoenable=section->Get_bool("autolock"); + sdl.mouse.autolock=false; + sdl.mouse.sensitivity=section->Get_int("sensitivity"); + GFX_Resize(640,400,8,0); #if C_THREADED sdl.mutex=SDL_CreateMutex(); sdl.thread = SDL_CreateThread(&SDLGFX_Thread,0); #else TIMER_RegisterMicroHandler(GFX_Redraw,1000000/70); #endif - GFX_Resize(640,400,8,0); SDL_EnableKeyRepeat(250,30); /* Get some Keybinds */ - KEYBOARD_AddEvent(KBD_f9,CTRL_PRESSED,SwitchFullScreen); KEYBOARD_AddEvent(KBD_f10,CTRL_PRESSED,CaptureMouse); + KEYBOARD_AddEvent(KBD_f7,CTRL_PRESSED,DecreaseSkip); + KEYBOARD_AddEvent(KBD_f8,CTRL_PRESSED,IncreaseSkip); KEYBOARD_AddEvent(KBD_enter,ALT_PRESSED,SwitchFullScreen); } void GFX_ShutDown() { if (sdl.full_screen) SwitchFullScreen(); - if (sdl.mouse_grabbed) CaptureMouse(); + if (sdl.mouse.locked) CaptureMouse(); GFX_Stop(); } +void Mouse_AutoLock(bool enable) { + sdl.mouse.autolock=enable; + if (enable && sdl.mouse.autoenable) sdl.mouse.requestlock=true; + else sdl.mouse.requestlock=false; +} static void HandleKey(SDL_KeyboardEvent * key) { Bit32u code; @@ -348,16 +399,17 @@ static void HandleKey(SDL_KeyboardEvent * key) { } static void HandleMouseMotion(SDL_MouseMotionEvent * motion) { - if (!sdl.mouse_grabbed) { - Mouse_CursorSet((float)motion->x/(float)sdl.width,(float)motion->y/(float)sdl.height); + if (sdl.mouse.locked) { + Mouse_CursorMoved((float)motion->xrel*sdl.mouse.sensitivity/100,(float)motion->yrel*sdl.mouse.sensitivity/100); } else { - Mouse_CursorMoved((float)motion->xrel/(float)sdl.width,(float)motion->yrel/(float)sdl.height); +// Mouse_CursorSet((float)motion->x/(float)sdl.width,(float)motion->y/(float)sdl.height); } } static void HandleMouseButton(SDL_MouseButtonEvent * button) { switch (button->state) { case SDL_PRESSED: + if (sdl.mouse.requestlock && !sdl.mouse.locked) CaptureMouse(); switch (button->button) { case SDL_BUTTON_LEFT: Mouse_ButtonPressed(0); @@ -424,6 +476,13 @@ void GFX_Events() { SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { + case SDL_ACTIVEEVENT: + if (event.active.state & SDL_APPINPUTFOCUS) { + if (!event.active.gain && sdl.mouse.locked) { + CaptureMouse(); + } + } + break; case SDL_KEYDOWN: case SDL_KEYUP: HandleKey(&event.key); @@ -451,24 +510,6 @@ void GFX_Events() { } } } -#if 0 - -void E_Exit(char * format,...) { - char buf[1024]; - - va_list msg; - strcpy(buf,"EXIT:"); - va_start(msg,format); - vsprintf(buf+strlen(buf),format,msg); - va_end(msg); - waddstr(dbg.win_out,buf); - wprintw(dbg.win_out," %d\n",cycle_count); - wrefresh(dbg.win_out); - throw ((Bitu)1); -} - -#endif - void GFX_ShowMsg(char * msg) { char buf[1024]; @@ -478,36 +519,57 @@ void GFX_ShowMsg(char * msg) { }; int main(int argc, char* argv[]) { - try { - if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER + +#if C_DEBUG + DEBUG_SetupConsole(); +#endif + + try { + CommandLine com_line(argc,argv); + Config myconf(&com_line); + control=&myconf; + + if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER #ifndef DISABLE_JOYSTICK |SDL_INIT_JOYSTICK #endif - ) < 0 ) { - E_Exit("Can't init SDL %s",SDL_GetError()); - } - GFX_StartUp(); -/* Init all the dosbox subsystems */ - DOSBOX_Init(argc,argv); -/* Start the systems that SDL should provide */ + ) < 0 ) E_Exit("Can't init SDL %s",SDL_GetError()); + Section_prop * sdl_sec=control->AddSection_prop("sdl",&GUI_StartUp); + sdl_sec->Add_bool("fullscreen",false); + sdl_sec->Add_bool("autolock",true); + sdl_sec->Add_int("sensitivity",100); + + /* Init all the dosbox subsystems */ + DOSBOX_Init(); + std::string config_file; + if (control->cmdline->FindString("-conf",config_file,true)) { + + } else { + config_file="dosbox.conf"; + } + /* Parse the config file */ + control->ParseConfigFile(config_file.c_str()); + /* Init all the sections */ + control->Init(); + /* Some extra SDL Functions */ #ifndef DISABLE_JOYSTICK - if (SDL_NumJoysticks()>0) { - SDL_JoystickEventState(SDL_ENABLE); - sdl.joy=SDL_JoystickOpen(0); - LOG_MSG("Using joystick %s with %d axes and %d buttons",SDL_JoystickName(0),SDL_JoystickNumAxes(sdl.joy),SDL_JoystickNumButtons(sdl.joy)); - JOYSTICK_Enable(0,true); + if (SDL_NumJoysticks()>0) { + SDL_JoystickEventState(SDL_ENABLE); + sdl.joy=SDL_JoystickOpen(0); + LOG_MSG("Using joystick %s with %d axes and %d buttons",SDL_JoystickName(0),SDL_JoystickNumAxes(sdl.joy),SDL_JoystickNumButtons(sdl.joy)); + JOYSTICK_Enable(0,true); + } +#endif + if (control->cmdline->FindExist("-fullscreen") || sdl_sec->Get_bool("fullscreen")) { + SwitchFullScreen(); + } + /* Start up main machine */ + control->StartUp(); + /* Shutdown everything */ + } catch (char * error) { + LOG_MSG("Exit to error: %sPress enter to continue.",error); + fgetc(stdin); } -#endif - /* Start dosbox up */ - DOSBOX_StartUp(); - } - catch (Bitu e) { - LOG_MSG("Exit to error %d",e); - } - GFX_Stop(); - - - return 0; -}; \ No newline at end of file +}; diff --git a/src/hardware/adlib.cpp b/src/hardware/adlib.cpp index 171772d..87e3630 100644 --- a/src/hardware/adlib.cpp +++ b/src/hardware/adlib.cpp @@ -24,7 +24,7 @@ #include "mixer.h" #include "timer.h" #include "hardware.h" - +#include "setup.h" /* Thanks to vdmsound for nice simple way to implement this */ @@ -126,7 +126,6 @@ static void write_p389(Bit32u port,Bit8u val) { } -static HWBlock hw_adlib; static bool adlib_enabled; static void ADLIB_Enable(bool enable) { @@ -153,46 +152,9 @@ static void ADLIB_Enable(bool enable) { } -static void ADLIB_InputHandler(char * line) { - bool s_off=ScanCMDBool(line,"OFF"); - bool s_on=ScanCMDBool(line,"ON"); - char * rem=ScanCMDRemain(line); - if (rem) { - sprintf(line,"Illegal Switch"); - return; - } - if (s_on && s_off) { - sprintf(line,"Can't use /ON and /OFF at the same time"); - return; - } - if (s_on) { - ADLIB_Enable(true); - sprintf(line,"Adlib has been enabled"); - return; - } - if (s_off) { - ADLIB_Enable(false); - sprintf(line,"Adlib has been disabled"); - return; - } - return; -} - -static void ADLIB_OutputHandler (char * towrite) { - if(adlib_enabled) { - sprintf(towrite,"IO %X",0x388); - } else { - sprintf(towrite,"Disabled"); - } -}; - - - - - - - -void ADLIB_Init(void) { +void ADLIB_Init(Section* sec) { + Section_prop * section=static_cast(sec); + if(!section->Get_bool("adlib")) return; timer1.isMasked=true; timer1.base=0; @@ -211,14 +173,6 @@ void ADLIB_Init(void) { adlib_chan=MIXER_AddChannel(ADLIB_CallBack,ADLIB_FREQ,"ADLIB"); MIXER_SetMode(adlib_chan,MIXER_16MONO); - - hw_adlib.dev_name="ADLIB"; - hw_adlib.full_name="Adlib FM Synthesizer"; - hw_adlib.next=0; - hw_adlib.help="/ON Enables Adlib\n/OFF Disables Adlib\n"; - hw_adlib.get_input=ADLIB_InputHandler; - hw_adlib.show_status=ADLIB_OutputHandler; - HW_Register(&hw_adlib); ADLIB_Enable(true); }; diff --git a/src/hardware/dma.cpp b/src/hardware/dma.cpp index 2a50e17..eb317d4 100644 --- a/src/hardware/dma.cpp +++ b/src/hardware/dma.cpp @@ -70,6 +70,32 @@ struct DMA_CONTROLLER { }; static DMA_CONTROLLER dma[2]; +static Bit8u read_dma(Bit32u port) { + /* only use first dma for now */ + DMA_CONTROLLER * cont=&dma[0]; + DMA_CHANNEL * chan=&cont->chan[port>>1]; + Bit8u ret; + switch (port) { + case 0x00:case 0x02:case 0x04:case 0x06: + if (cont->flipflop) { + ret=chan->current_address & 0xff; + } else { + ret=(chan->current_address>>8)&0xff; + } + cont->flipflop=!cont->flipflop; + case 0x01:case 0x03:case 0x05:case 0x07: + if (cont->flipflop) { + ret=(chan->current_count-1) & 0xff; + } else { + ret=((chan->current_count-1)>>8)&0xff; + } + cont->flipflop=!cont->flipflop; + break; + default: + LOG_WARN("DMA:Unhandled read from %d",port); + } + return ret; +} static void write_dma(Bit32u port,Bit8u val) { @@ -203,9 +229,10 @@ Bit16u DMA_16_Write(Bit32u dmachan,Bit8u * buffer,Bit16u count) { -void DMA_Init(void) { +void DMA_Init(Section* sec) { for (Bit32u i=0;i<0x10;i++) { IO_RegisterWriteHandler(i,write_dma,"DMA1"); + IO_RegisterReadHandler(i,read_dma,"DMA1"); } IO_RegisterWriteHandler(0x81,write_dma_page,"DMA Pages"); IO_RegisterWriteHandler(0x82,write_dma_page,"DMA Pages"); diff --git a/src/hardware/gameblaster.cpp b/src/hardware/gameblaster.cpp index bcddec0..c6494f5 100644 --- a/src/hardware/gameblaster.cpp +++ b/src/hardware/gameblaster.cpp @@ -22,11 +22,11 @@ #include "mixer.h" #include "mem.h" #include "hardware.h" +#include "setup.h" #define CMS_RATE 22050 #define CMS_VOLUME 6000 - #define FREQ_SHIFT 16 #define SIN_ENT 1024 @@ -36,8 +36,6 @@ #define PI 3.14159265358979323846 #endif - - struct CMS { struct { Bit32u freq_pos; @@ -157,7 +155,6 @@ static void CMS_CallBack(Bit8u * stream,Bit32u len) { } -static HWBlock hw_cms; static bool cms_enabled; static void CMS_Enable(bool enable) { @@ -178,56 +175,14 @@ static void CMS_Enable(bool enable) { } } - -static void CMS_InputHandler(char * line) { - bool s_off=ScanCMDBool(line,"OFF"); - bool s_on=ScanCMDBool(line,"ON"); - char * rem=ScanCMDRemain(line); - if (rem) { - sprintf(line,"Illegal Switch"); - return; - } - if (s_on && s_off) { - sprintf(line,"Can't use /ON and /OFF at the same time"); - return; - } - if (s_on) { - CMS_Enable(true); - sprintf(line,"Creative Music System has been enabled"); - return; - } - if (s_off) { - CMS_Enable(false); - sprintf(line,"Creative Music System has been disabled"); - return; - } - return; -} - -static void CMS_OutputHandler (char * towrite) { - if(cms_enabled) { - sprintf(towrite,"IO %X",0x220); - } else { - sprintf(towrite,"Disabled"); - } -}; - - -void CMS_Init(void) { +void CMS_Init(Section* sec) { + Section_prop * section=static_cast(sec); + if(!section->Get_bool("cms")) return; Bits i; /* Register the Mixer CallBack */ cms_chan=MIXER_AddChannel(CMS_CallBack,CMS_RATE,"CMS"); MIXER_SetMode(cms_chan,MIXER_16STEREO); MIXER_Enable(cms_chan,false); -/* Register with the hardware setup tool */ - hw_cms.dev_name="CMS"; - hw_cms.full_name="Creative Music System"; - hw_cms.next=0; - hw_cms.help="/ON Enables CMS\n/OFF Disables CMS\n"; - hw_cms.get_input=CMS_InputHandler; - hw_cms.show_status=CMS_OutputHandler; - HW_Register(&hw_cms); - CMS_Enable(false); /* Make the frequency/octave table */ double log_start=log10(27.34375); double log_add=(log10(54.609375)-log10(27.34375))/256; @@ -250,7 +205,6 @@ void CMS_Init(void) { out /= 1.1; } } - - + CMS_Enable(true); } diff --git a/src/hardware/hardware.cpp b/src/hardware/hardware.cpp index ed73820..49cf722 100644 --- a/src/hardware/hardware.cpp +++ b/src/hardware/hardware.cpp @@ -24,94 +24,10 @@ #include "dosbox.h" #include "programs.h" #include "hardware.h" - -static HWBlock * firsthw=0; +#include "setup.h" -class HWSET : public Program { -public: - HWSET(PROGRAM_Info * program_info); - void Run(void); - -}; - - -HWSET::HWSET(PROGRAM_Info * info):Program(info) { +void HARDWARE_Init(Section * sec) { } -void HW_Register(HWBlock * block) { - block->next=firsthw; - firsthw=block; -} - - -void HWSET::Run(void) { - /* Hopefull enough space */ - char buf[1024]; - - HWBlock * loopblock; - if (!*prog_info->cmd_line) { - /* No command line given give overview of hardware */ - loopblock=firsthw; - WriteOut("ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"); - WriteOut("³Device ³Full Name ³Status ³"); - WriteOut("ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´"); - while (loopblock) { - if (loopblock->show_status) { - loopblock->show_status(buf); - } else { - strcpy(buf,"No Status Handler"); - } - WriteOut("³%-8s³%-25s³%-43s³",loopblock->dev_name,loopblock->full_name,buf); - loopblock=loopblock->next; - } - WriteOut("ÀÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ"); - WriteOut("If you want to setup specific hardware use \"HWSET Device\" for information.\n"); - return; - } - /* Command line given */ - if (strcmp(prog_info->cmd_line,"/?")==0) { - WriteOut("Hardware setup tool for DOSBox.\n"); - WriteOut("This program can be used to change the settings of internal hardware.\n\n" - "HWSET [device] [switches]\n\n" - "Using an empty command line gives you a list of hardware.\n" - "You can get list of switches for a device with HWSET device.\n" - ); - return; - } - char * rest=strchr(prog_info->cmd_line,' '); - if (rest) *rest++=0; - loopblock=firsthw; - while (loopblock) { - if (strcasecmp(loopblock->dev_name,prog_info->cmd_line)==0) goto founddev; - loopblock=loopblock->next; - } - WriteOut("Device %s not found\n",prog_info->cmd_line); - return; -founddev: -/* Check for rest of line */ - if (rest) { - strcpy(buf,rest); - loopblock->get_input(buf); - WriteOut(buf); - - } else { - WriteOut("Command overview for %s\n%s",loopblock->full_name,loopblock->help); - } - return; -} - -static void HWSET_ProgramStart(PROGRAM_Info * info) { - HWSET * tempHWSET=new HWSET(info); - tempHWSET->Run(); - delete tempHWSET; -} - - - -void HARDWARE_Init(void) { - PROGRAMS_MakeFile("HWSET.COM",HWSET_ProgramStart); - -}; - diff --git a/src/hardware/iohandler.cpp b/src/hardware/iohandler.cpp index 242f6f0..0a499c4 100644 --- a/src/hardware/iohandler.cpp +++ b/src/hardware/iohandler.cpp @@ -80,7 +80,7 @@ void IO_FreeWriteHandler(Bit32u port) { } -void IO_Init(void) { +void IO_Init(Section * sect) { for (Bitu i=0;i=KEYBUFSIZE) keyb.buf_pos=0; + } + if (keyb.buf_used) { + keyb.read_active=true; + PIC_ActivateIRQ(1); + } +} + +void KEYBOARD_AddCode(Bit8u code) { + if (keyb.buf_used=KEYBUFSIZE) start-=KEYBUFSIZE; + keyb.buf[start]=code; + keyb.read_active=true; + } + if (keyb.buf_used>0) PIC_ActivateIRQ(1); +} + static Bit8u read_p60(Bit32u port) { - if (kbuf_used>0) { - cur_scancode=kbuf[kbuf_pos]; - }; - return cur_scancode; + /* Reading this port signals that IRQ can be lowered */ + Bit8u val=keyb.buf[keyb.buf_pos]; + keyb.read_active=false; + return keyb.buf[keyb.buf_pos]; } static void write_p60(Bit32u port,Bit8u val) { -//TODO Work this out ;) - LOG_DEBUG("Port 60 write with val %d",val); + switch (keyb.command) { + case CMD_NONE: /* None */ + KEYBOARD_ClrBuffer(); + switch (val) { + case 0xed: /* Set Leds */ + keyb.command=CMD_SETLEDS; + KEYBOARD_AddCode(0xfa); /* Acknowledge */ + break; + case 0xee: /* Echo */ + KEYBOARD_AddCode(0xee); + break; + case 0xf2: /* Identify keyboard */ + /* AT's just send acknowledge */ + KEYBOARD_AddCode(0xfa); /* Acknowledge */ + break; + case 0xf3: /* Typematic rate programming */ + keyb.command=CMD_SETTYPERATE; + KEYBOARD_AddCode(0xfa); /* Acknowledge */ + break; + default: + LOG_DEBUG("KEYB:60:Unhandled command %X",val); + } + return; + case CMD_SETTYPERATE: + case CMD_SETLEDS: + keyb.command=CMD_NONE; + KEYBOARD_AddCode(0xfa); /* Acknowledge */ + break; + } } static Bit8u read_p61(Bit32u port) { + port_61_data^=0x20; return port_61_data; + }; +static void KEYBOARD_IRQHandler(void) { + if (!keyb.read_active) KEYBOARD_ReadBuffer(); +} + static void write_p61(Bit32u port,Bit8u val) { -//TODO Enable spreaker through here :) - if ((val&128)) { /* Keyboard acknowledge */ - if (kbuf_used) { - kbuf_used--; - kbuf_pos++; - if (kbuf_pos>=KEYBUFSIZE) kbuf_pos=0; - if (kbuf_used) PIC_ActivateIRQ(1); - } - } port_61_data=val; + if (val & 128) if (!keyb.read_active) KEYBOARD_ReadBuffer(); if ((val & 3)==3) { PCSPEAKER_Enable(true); } else { @@ -78,18 +149,17 @@ static void write_p61(Bit32u port,Bit8u val) { } } - - -void KEYBOARD_AddCode(Bit8u code) { - //Now Raise the keyboard IRQ - //If the buffer is full just drop the scancode :) - if (kbuf_used=KEYBUFSIZE) start-=KEYBUFSIZE; - kbuf[start]=code; +static void write_p64(Bit32u port,Bit8u val) { + switch (val) { + case 0: + default: + LOG_DEBUG("Port 64 write with val %d",val); + break; } - PIC_ActivateIRQ(1); +} + +static Bit8u read_p64(Bit32u port) { + return 0x1c | (keyb.read_active ? 0x1 : 0x0); } @@ -104,9 +174,7 @@ void KEYBOARD_AddEvent(Bitu keytype,Bitu state,KEYBOARD_EventHandler * handler) newevent->type=keytype; newevent->state=state; newevent->handler=handler; - - -}; +} void KEYBOARD_AddKey(Bitu keytype,bool pressed) { bool extend=false; @@ -217,9 +285,13 @@ void KEYBOARD_AddKey(Bitu keytype,bool pressed) { //The Extended keys case KBD_kpenter:extend=true;ret=28;break; - case KBD_rightctrl:extend=true;ret=29;break; + case KBD_rightctrl:extend=true;ret=29; + shift_state=(shift_state&~CTRL_PRESSED)|(pressed ? CTRL_PRESSED:0); + break; case KBD_kpslash:extend=true;ret=53;break; - case KBD_rightalt:extend=true;ret=56;break; + case KBD_rightalt:extend=true;ret=56; + shift_state=(shift_state&~ALT_PRESSED)|(pressed ? ALT_PRESSED:0); + break; case KBD_home:extend=true;ret=71;break; case KBD_up:extend=true;ret=72;break; case KBD_pageup:extend=true;ret=73;break; @@ -233,7 +305,7 @@ void KEYBOARD_AddKey(Bitu keytype,bool pressed) { default: E_Exit("Unsopperted key press"); break; - }; + } /* check for active key events */ KeyEvent * checkevent=event_handlers[keytype]; while (checkevent) { @@ -249,14 +321,21 @@ void KEYBOARD_AddKey(Bitu keytype,bool pressed) { if (extend) KEYBOARD_AddCode(224); if (!pressed) ret+=128; KEYBOARD_AddCode(ret); -}; +} -void KEYBOARD_Init(void) { - kbuf_used=0;kbuf_pos=0; +void KEYBOARD_Init(Section* sec) { IO_RegisterWriteHandler(0x60,write_p60,"Keyboard"); IO_RegisterReadHandler(0x60,read_p60,"Keyboard"); IO_RegisterWriteHandler(0x61,write_p61,"Keyboard"); IO_RegisterReadHandler(0x61,read_p61,"Keyboard"); + IO_RegisterWriteHandler(0x64,write_p64,"Keyboard"); + IO_RegisterReadHandler(0x64,read_p64,"Keyboard"); + port_61_data=1; /* Speaker control through PIT and speaker disabled */ // memset(&event_handlers,0,sizeof(event_handlers)); -}; + /* Clear the keyb struct */ + keyb.enabled=true; + keyb.command=CMD_NONE; + KEYBOARD_ClrBuffer(); + PIC_RegisterIRQ(1,KEYBOARD_IRQHandler,"KEYBOARD"); +} diff --git a/src/hardware/memory.cpp b/src/hardware/memory.cpp index 2616494..9ce74ac 100644 --- a/src/hardware/memory.cpp +++ b/src/hardware/memory.cpp @@ -34,28 +34,36 @@ MEMORY_WriteHandler WriteHandlerTable[MAX_PAGES]; #define MAX_PAGE_LIMIT PAGE_COUNT(C_MEM_MAX_SIZE*1024*1024) void MEM_BlockRead(PhysPt off,void * data,Bitu size) { - Bitu c; Bit8u * idata=(Bit8u *)data; - for (c=1;c<=(size>>2);c++) { - writed(idata,mem_readd(off)); - idata+=4;off+=4; - } - for (c=1;c<=(size&3);c++) { - writeb(idata,mem_readb(off)); - idata+=1;off+=1; + while (size>0) { + Bitu page=off >> PAGE_SHIFT; + Bitu start=off & (PAGE_SIZE-1); + Bitu tocopy=PAGE_SIZE-start; + if (tocopy>size) tocopy=size; + size-=tocopy; + if (ReadHostTable[page]) { + memcpy(idata,ReadHostTable[page]+off,tocopy); + idata+=tocopy;off+=tocopy; + } else { + for (;tocopy>0;tocopy--) *idata++=ReadHandlerTable[page](off++); + } } } void MEM_BlockWrite(PhysPt off,void * data,Bitu size) { - Bitu c; Bit8u * idata=(Bit8u *)data; - for (c=1;c<=(size>>2);c++) { - mem_writed(off,readd(idata)); - idata+=4;off+=4; - } - for (c=1;c<=(size&3);c++) { - mem_writeb(off,readb(idata)); - idata+=1;off+=1; + while (size>0) { + Bitu page=off >> PAGE_SHIFT; + Bitu start=off & (PAGE_SIZE-1); + Bitu tocopy=PAGE_SIZE-start; + if (tocopy>size) tocopy=size; + size-=tocopy; + if (WriteHostTable[page]) { + memcpy(WriteHostTable[page]+off,idata,tocopy); + idata+=tocopy;off+=tocopy; + } else { + for (;tocopy>0;tocopy--) WriteHandlerTable[page](off++,*idata++); + } } } @@ -222,7 +230,7 @@ Bit32u mem_readd(PhysPt pt){ -void MEM_Init(void) { +void MEM_Init(Section * sect) { /* Init all tables */ Bitu i; i=MAX_PAGES; @@ -235,8 +243,9 @@ void MEM_Init(void) { /* Allocate the first mb of memory */ memory=(Bit8u *)malloc(1024*1024); if (!memory) { - E_Exit("Can't allocate memory for memory"); + throw("Can't allocate memory for memory"); } + memset(memory,0xcd,1024*1024); /* Setup tables for first mb */ MEM_SetupMapping(0,PAGE_COUNT(1024*1024),memory); /* Setup tables for HMA Area */ diff --git a/src/hardware/mixer.cpp b/src/hardware/mixer.cpp index 8144e39..bbf00b3 100644 --- a/src/hardware/mixer.cpp +++ b/src/hardware/mixer.cpp @@ -22,7 +22,7 @@ */ #include -#include +#include #include "dosbox.h" #include "mixer.h" #include "timer.h" @@ -35,35 +35,69 @@ #define MIXER_REMAIN ((1<MAX_AUDIO) ? (Bit16s)MAX_AUDIO : (SAMPhandler)(((Bit8u*)&mix_temp)+sizeof(mix_temp.TYPE[0]),sample_toread); \ + Bitu sample_index=(1 << MIXER_SHIFT) - chan->sample_left; \ + Bit32s newsample; \ + for (Bitu mix=0;mix> MIXER_SHIFT;sample_index+=chan->sample_add; \ + newsample=mix_buftemp[mix][0]+MAKE_##TYPE( LCHAN ); \ + mix_buftemp[mix][0]=MIXER_CLIP(newsample); \ + newsample=mix_buftemp[mix][1]+MAKE_##TYPE( RCHAN ); \ + mix_buftemp[mix][1]=MIXER_CLIP(newsample); \ + } \ + chan->remain.TYPE[LCHAN]=mix_temp.TYPE[sample_index>>MIXER_SHIFT][LCHAN]; \ + if (RCHAN) chan->remain.TYPE[RCHAN]=mix_temp.TYPE[sample_index>>MIXER_SHIFT][RCHAN];\ + chan->sample_left=sample_total-sample_index; \ + break; \ +} + +union Sample { + Bit16s m16[1]; + Bit16s s16[2]; + Bit8u m8[1]; + Bit8u s8[2]; + Bit32u full; +}; struct MIXER_Channel { Bit8u volume; Bit8u mode; - Bit32u freq; + Bitu freq; char * name; MIXER_MixHandler handler; - Bit32u sample_add; - Bit32u sample_remain; - Bit16s sample_data[2]; + Bitu sample_add; + Bitu sample_left; + Sample remain; bool playing; MIXER_Channel * next; }; + static MIXER_Channel * first_channel; static union { - Bit16s temp_m16[MIXER_BUFSIZE][1]; - Bit16s temp_s16[MIXER_BUFSIZE][2]; - Bit8u temp_m8[MIXER_BUFSIZE][1]; - Bit8u temp_s8[MIXER_BUFSIZE][2]; -}; + Bit16s m16[MIXER_BUFSIZE][1]; + Bit16s s16[MIXER_BUFSIZE][2]; + Bit8u m8[MIXER_BUFSIZE][1]; + Bit8u s8[MIXER_BUFSIZE][2]; + Bit32u full[MIXER_BUFSIZE]; +} mix_temp; + static Bit16s mix_bufout[MIXER_BUFSIZE][2]; static Bit16s mix_buftemp[MIXER_BUFSIZE][2]; static Bit32s mix_bufextra; -static Bit32u mix_writepos; -static Bit32u mix_readpos; -static Bit32u mix_ticks; -static Bit32u mix_add; -static Bit32u mix_remain; +static Bitu mix_writepos; +static Bitu mix_readpos; +static Bitu mix_ticks; +static Bitu mix_add; +static Bitu mix_remain; MIXER_Channel * MIXER_AddChannel(MIXER_MixHandler handler,Bit32u freq,char * name) { //TODO Find a free channel @@ -75,6 +109,7 @@ MIXER_Channel * MIXER_AddChannel(MIXER_MixHandler handler,Bit32u freq,char * nam chan->handler=handler; chan->name=name; chan->sample_add=(freq<sample_left=0; chan->next=first_channel; first_channel=chan; return chan; @@ -112,69 +147,28 @@ static void MIXER_MixData(Bit32u samples) { MIXER_Channel * chan=first_channel; while (chan) { if (chan->playing) { - Bit32u chan_samples=samples*chan->sample_add; - Bit32u real_samples=chan_samples>>MIXER_SHIFT; - if (chan_samples & MIXER_REMAIN) real_samples++; - (chan->handler)((Bit8u*)&temp_m8,real_samples); + /* This should always allocate 1 extra sample */ + Bitu sample_total=(samples*chan->sample_add)-chan->sample_left; + Bitu sample_toread=sample_total >> MIXER_SHIFT; + if (sample_total & MIXER_REMAIN) sample_toread++; + sample_total=(sample_toread+1)<remain.full; switch (chan->mode) { case MIXER_8MONO: - /* Mix a 8 bit mono stream into the final 16 bit stereo output stream */ - { - /* Mix the data with output buffer */ - Bit32s newsample;Bit32u sample_read=0;Bit32u sample_add=chan->sample_add; - for (Bit32u mix=0;mix> MIXER_SHIFT; - sample_read+=sample_add; - newsample=mix_buftemp[mix][0]+((Bit8s)(temp_m8[pos][0]^0x80) << 8); - if (newsample>MAX_AUDIO) mix_buftemp[mix][0]=MAX_AUDIO; - else if (newsampleMAX_AUDIO) mix_buftemp[mix][1]=MAX_AUDIO; - else if (newsamplesample_add; - for (Bit32u mix=0;mix> MIXER_SHIFT; - sample_read+=sample_add; - newsample=mix_buftemp[mix][0]+temp_m16[pos][0]; - if (newsample>MAX_AUDIO) mix_buftemp[mix][0]=MAX_AUDIO; - else if (newsampleMAX_AUDIO) mix_buftemp[mix][1]=MAX_AUDIO; - else if (newsamplesample_add; - for (Bit32u mix=0;mix> MIXER_SHIFT; - sample_read+=sample_add; - newsample=mix_buftemp[mix][0]+temp_s16[pos][0]; - if (newsample>MAX_AUDIO) mix_buftemp[mix][0]=MAX_AUDIO; - else if (newsampleMAX_AUDIO) mix_buftemp[mix][1]=MAX_AUDIO; - else if (newsamplemode); + break; } } chan=chan->next; @@ -210,7 +204,7 @@ static void MIXER_CallBack(void * userdata, Uint8 *stream, int len) { /* Copy data from buf_out to the stream */ Bit32u remain=MIXER_BUFSIZE-mix_readpos; - if (remain>=len/MIXER_SSIZE) { + if (remain>=(Bit32u)len/MIXER_SSIZE) { memcpy((void *)stream,(void *)&mix_bufout[mix_readpos][0],len); } else { memcpy((void *)stream,(void *)&mix_bufout[mix_readpos][0],remain*MIXER_SSIZE); @@ -223,7 +217,8 @@ static void MIXER_CallBack(void * userdata, Uint8 *stream, int len) { -void MIXER_Init(void) { +void MIXER_Init(Section* sec) { + MSG_Add("MIXER_CONFIGFILE_HELP","Nothing to setup yet!\n"); /* Initialize the internal stuff */ first_channel=0; mix_ticks=GetTicks(); diff --git a/src/hardware/pcspeaker.cpp b/src/hardware/pcspeaker.cpp index c8aabb1..5043df4 100644 --- a/src/hardware/pcspeaker.cpp +++ b/src/hardware/pcspeaker.cpp @@ -16,16 +16,17 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include -#include #include +#include "dosbox.h" +#include "mixer.h" +#include "timer.h" #ifndef PI #define PI 3.14159265358979323846 #endif +#define SPKR_BUF 4096 #define SPKR_RATE 22050 #define SPKR_VOLUME 5000 @@ -41,15 +42,26 @@ struct Speaker { Bit16s volume; MIXER_Channel * chan; bool enabled; + bool realsound; + Bit16u buffer[SPKR_BUF]; + Bitu buf_pos; }; static Speaker spkr; -void PCSPEAKER_SetFreq(Bit32u freq) { - spkr.freq_add=(Bit32u)(FREQ_MAX/((float)SPKR_RATE/(float)freq)); - spkr.freq_pos=0; +void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) { + switch (mode) { + case 0: + if (cntr>72) cntr=72; + spkr.realsound=true; + if (spkr.buf_pos=FREQ_MAX) spkr.freq_pos-=FREQ_MAX; - if (spkr.freq_pos>=FREQ_HALF) { - *(Bit16s*)(stream)=spkr.volume; - } else { - *(Bit16s*)(stream)=-spkr.volume; + if (spkr.realsound) { + /* Generate the "RealSound" */ + Bitu buf_add=(spkr.buf_pos<<16)/len; + Bitu buf_pos=0; + spkr.buf_pos=0;spkr.realsound=0; + while (len-->0) { + *(Bit16s*)(stream)=spkr.buffer[buf_pos >> 16]; + buf_pos+=buf_add; + stream+=2; + } + } else { + /* Generate a square wave */ + while (len-->0) { + spkr.freq_pos+=spkr.freq_add; + if (spkr.freq_pos>=FREQ_MAX) spkr.freq_pos-=FREQ_MAX; + if (spkr.freq_pos>=FREQ_HALF) { + *(Bit16s*)(stream)=spkr.volume; + } else { + *(Bit16s*)(stream)=-spkr.volume; + } + stream+=2; } -/* - if (spkr.freq_pos>=FREQ_HALF) { - spkr.freq_pos-=FREQ_HALF; - spkr.volume=-spkr.volume; - }; - *(Bit16s*)(stream)=spkr.volume; -*/ - stream+=2; } - } -void PCSPEAKER_Init(void) { +void PCSPEAKER_Init(Section* sec) { + MSG_Add("SPEAKER_CONFIGFILE_HELP","pcspeaker related options.\n"); spkr.chan=MIXER_AddChannel(&PCSPEAKER_CallBack,SPKR_RATE,"PC-SPEAKER"); MIXER_Enable(spkr.chan,false); MIXER_SetMode(spkr.chan,MIXER_16MONO); spkr.volume=SPKR_VOLUME; spkr.enabled=false; + spkr.realsound=false; + spkr.buf_pos=0; } diff --git a/src/hardware/pic.cpp b/src/hardware/pic.cpp index b21bd49..68ad22d 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -31,7 +31,9 @@ struct IRQ_Block { PIC_EOIHandler * handler; }; -Bit32u PIC_IRQCheck; +Bitu PIC_IRQCheck; +Bitu PIC_IRQActive; +bool PIC_IRQAgain; static IRQ_Block irqs[16]; static Bit8u pic0_icws=0; @@ -45,7 +47,6 @@ static bool pic1_request_iisr=0; //Pic 0 command port static void write_p20(Bit32u port,Bit8u val) { - Bit32u i; switch (val) { case 0x0A: /* select read interrupt request register */ pic0_request_iisr=false; @@ -56,7 +57,6 @@ static void write_p20(Bit32u port,Bit8u val) { case 0x10: /* ICW1 */ pic0_icws=2; pic0_icw_state=1; - break; case 0x11: /* ICW1 + need for ICW4 */ pic0_icws=3; @@ -64,13 +64,11 @@ static void write_p20(Bit32u port,Bit8u val) { break; case 0x20: /* end of interrupt command */ /* clear highest current in service bit */ - for (i=0;i<=7;i++) { - if (irqs[i].inservice) { - irqs[i].inservice=false; - if (irqs[i].handler!=0) irqs[i].handler(); - break; - }; - }; + if (PIC_IRQActive<8) { + irqs[PIC_IRQActive].inservice=false; + if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); + PIC_IRQActive=PIC_NOIRQ; + } break; case 0x60: /* specific EOI 0 */ case 0x61: /* specific EOI 1 */ @@ -80,10 +78,11 @@ static void write_p20(Bit32u port,Bit8u val) { case 0x65: /* specific EOI 5 */ case 0x66: /* specific EOI 6 */ case 0x67: /* specific EOI 7 */ - if (irqs[val-0x60].inservice) { - irqs[val-0x60].inservice=false; - if (irqs[val-0x60].handler!=0) irqs[val-0x60].handler(); - }; + if (PIC_IRQActive==(val-0x60U)) { + irqs[PIC_IRQActive].inservice=false; + if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); + PIC_IRQActive=PIC_NOIRQ; + } break; // IRQ lowest priority commands case 0xC0: // 0 7 6 5 4 3 2 1 @@ -176,13 +175,11 @@ static void write_pa0(Bit32u port,Bit8u val) { break; case 0x20: /* end of interrupt command */ /* clear highest current in service bit */ - for (i=8;i<=15;i++) { - if (irqs[i].inservice) { - irqs[i].inservice=false; - if (irqs[i].handler!=0) irqs[i].handler(); - break; - }; - }; + if (PIC_IRQActive>7 && PIC_IRQActive <16) { + irqs[PIC_IRQActive].inservice=false; + if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); + PIC_IRQActive=PIC_NOIRQ; + } break; case 0x60: /* specific EOI 0 */ case 0x61: /* specific EOI 1 */ @@ -192,9 +189,10 @@ static void write_pa0(Bit32u port,Bit8u val) { case 0x65: /* specific EOI 5 */ case 0x66: /* specific EOI 6 */ case 0x67: /* specific EOI 7 */ - if (irqs[val-0x60+8].inservice) { - irqs[val-0x60+8].inservice=false; - if (irqs[val-0x60+8].handler!=0) irqs[val-0x60+8].handler(); + if (PIC_IRQActive==(8+val-0x60U)) { + irqs[PIC_IRQActive].inservice=false; + if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); + PIC_IRQActive=PIC_NOIRQ; }; break; // IRQ lowest priority commands @@ -220,6 +218,7 @@ static void write_pa1(Bit32u port,Bit8u val) { case 0: /* mask register */ for (i=0;i<=7;i++) { irqs[i+8].masked=(val&1 <0; + if (!irqs[8].masked) LOG_DEBUG("Someone unmasked RTC irq"); }; break; case 1: /* icw2 */ @@ -245,7 +244,7 @@ static Bit8u read_pa0(Bit32u port) { if (irqs[i+8].active) ret|=b; b <<= 1; } - }; + } return ret; } @@ -292,55 +291,31 @@ void PIC_DeActivateIRQ(Bit32u irq) { } } -bool PIC_IRQActive(Bit32u irq) { - if (irq<16) { - return irqs[irq].active; - } - return true; -} - - -#define PIC_MAXQUEUE 16 -static PIC_Function * pic_queue[PIC_MAXQUEUE]; -static Bit32u pic_queuesize; - -void PIC_QueueFunction(PIC_Function * function) { - if (pic_queuesize0;) { - (*pic_queue[--pic_queuesize])(); + PIC_IRQActive=i; + PIC_IRQAgain=true; + return; + } + } } -}; +} -void PIC_Init(void) { +void PIC_Init(Section* sec) { /* Setup pic0 and pic1 with initial values like DOS has normally */ PIC_IRQCheck=0; + PIC_IRQActive=PIC_NOIRQ; Bit8u i; for (i=0;i<=7;i++) { irqs[i].active=false; @@ -351,11 +326,10 @@ void PIC_Init(void) { irqs[i+8].inservice=false; irqs[i].vector=0x8+i; irqs[i+8].vector=0x70+i; - }; + } irqs[0].masked=false; /* Enable system timer */ irqs[1].masked=false; /* Enable Keyboard IRQ */ - irqs[2].masked=false; /* Enable 2nd PIC Although i can't care if this is masked */ - irqs[12].masked=false; + irqs[12].masked=false; /* Enable Mouse IRQ */ IO_RegisterReadHandler(0x20,read_p20,"Master PIC Command"); IO_RegisterReadHandler(0x21,read_p21,"Master PIC Data"); IO_RegisterWriteHandler(0x20,write_p20,"Master PIC Command"); @@ -364,6 +338,6 @@ void PIC_Init(void) { IO_RegisterReadHandler(0xa1,read_pa1,"Slave PIC Data"); IO_RegisterWriteHandler(0xa0,write_pa0,"Slave PIC Command"); IO_RegisterWriteHandler(0xa1,write_pa1,"Slave PIC Data"); -}; +} diff --git a/src/hardware/sblaster.cpp b/src/hardware/sblaster.cpp index 6962c39..fd9564f 100644 --- a/src/hardware/sblaster.cpp +++ b/src/hardware/sblaster.cpp @@ -23,6 +23,8 @@ #include "dma.h" #include "pic.h" #include "hardware.h" +#include "setup.h" +#include "programs.h" #define SB_BASE 0x220 #define SB_IRQ 5 @@ -44,7 +46,7 @@ enum {DSP_S_RESET,DSP_S_NORMAL,DSP_S_HIGHSPEED}; enum { - MODE_NONE,MODE_DAC, + MODE_NONE,MODE_DAC,MODE_SILENCE, MODE_PCM_8S,MODE_PCM_8A, MODE_ADPCM_4S }; @@ -90,7 +92,6 @@ struct SB_INFO { Bit8u irq; Bit8u dma; bool enabled; - HWBlock hwblock; MIXER_Channel * chan; }; @@ -143,7 +144,7 @@ static void DSP_SetSpeaker(bool how) { } static void DSP_HaltDMA(void) { - + } static INLINE void DSP_FlushData(void) { @@ -151,15 +152,8 @@ static INLINE void DSP_FlushData(void) { sb.data_out_pos=0; } -static void DSP_SetSampleRate(Bit32u rate) { -/* This directly changes the mixer */ - - -} static void DSP_StopDMA(void) { sb.mode=MODE_NONE; -// MIXER_SetMode(sb.chan,MIXER_8MONO); -// MIXER_SetFreq(sb.chan,22050); } static void DSP_StartDMATranfser(Bit8u mode) { @@ -168,6 +162,10 @@ static void DSP_StartDMATranfser(Bit8u mode) { sb.freq=(1000000 / (256 - sb.time_constant)); }; switch (mode) { + case MODE_SILENCE: + MIXER_SetFreq(sb.chan,sb.freq); + SB_DEBUG("DSP:PCM 8 bit single cycle rate %d size %d",sb.freq,sb.samples_total); + break; case MODE_PCM_8S: MIXER_SetFreq(sb.chan,sb.freq); SB_DEBUG("DSP:PCM 8 bit single cycle rate %d size %d",sb.freq,sb.samples_total); @@ -175,13 +173,11 @@ static void DSP_StartDMATranfser(Bit8u mode) { case MODE_PCM_8A: MIXER_SetFreq(sb.chan,sb.freq); SB_DEBUG("DSP:PCM 8 bit auto init rate %d size %d",sb.freq,sb.samples_total); - break; case MODE_ADPCM_4S: MIXER_SetFreq(sb.chan,sb.freq); SB_DEBUG("DSP:ADPCM 4 bit single cycle rate %d size %X",sb.freq,sb.samples_total); break; - default: LOG_ERROR("DSP:Illegal transfer mode %d",mode); return; @@ -206,6 +202,9 @@ static void DSP_Reset(void) { sb.mode=MODE_NONE; sb.cmd_len=0; sb.cmd_in_pos=0; + sb.samples_left=0; + sb.samples_total=0; + sb.freq=22050; sb.use_time_constant=false; sb.dac.used=0; sb.dac.last=0x80; @@ -260,6 +259,10 @@ static void DSP_DoCommand(void) { sb.samples_total=1+sb.cmd_in[0]+(sb.cmd_in[1] << 8); DSP_StartDMATranfser(MODE_ADPCM_4S); break; + case 0x80: /* Silence DAC */ + sb.samples_total=1+sb.cmd_in[0]+(sb.cmd_in[1] << 8); + DSP_StartDMATranfser(MODE_SILENCE); + break; case 0xd0: /* Halt 8-bit DMA */ DSP_HaltDMA(); break; @@ -289,7 +292,6 @@ static void DSP_DoCommand(void) { */ //TODO Ofcourse :) } - break; case 0xe3: /* DSP Copyright */ { @@ -444,6 +446,16 @@ static void SBLASTER_CallBack(Bit8u * stream,Bit32u len) { } } break; + case MODE_SILENCE: + memset(stream,0x80,len); + if (sb.samples_left>len) { + sb.samples_left-=len; + } else { + sb.samples_left=0; + sb.mode=MODE_NONE; + PIC_ActivateIRQ(sb.irq); + } + break; case MODE_PCM_8A: { Bit16u read=DMA_8_Read(sb.dma,stream,(Bit16u)len); @@ -524,8 +536,6 @@ static void SBLASTER_CallBack(Bit8u * stream,Bit32u len) { -static bool SB_enabled; - static void SB_Enable(bool enable) { Bitu i; if (enable) { @@ -542,90 +552,22 @@ static void SB_Enable(bool enable) { for (i=sb.base+4;i(sec); + if(!section->Get_bool("enabled")) return; sb.chan=MIXER_AddChannel(&SBLASTER_CallBack,22050,"SBLASTER"); MIXER_Enable(sb.chan,false); - sb.state=DSP_S_NORMAL; -/* Setup the hardware handler part */ - sb.base=SB_BASE; - sb.irq=SB_IRQ; - sb.dma=SB_DMA; - SB_Enable(true); - sb.hwblock.dev_name="SB"; - sb.hwblock.full_name="Sound Blaster 1.5"; - sb.hwblock.next=0; - sb.hwblock.help= - "/ON Enables SB\n" - "/OFF Disables SB\n" - "/BASE XXX Set Base Addres 200-260\n" - "/IRQ X Set IRQ 1-9\n" - "/DMA X Set 8-Bit DMA Channel 0-3\n"; - sb.hwblock.get_input=SB_InputHandler; - sb.hwblock.show_status=SB_OutputHandler; - HW_Register(&sb.hwblock); - + sb.state=DSP_S_NORMAL; + sb.base=section->Get_hex("base"); + sb.irq=section->Get_int("irq"); + sb.dma=section->Get_int("dma"); + SB_Enable(true); SHELL_AddAutoexec("SET BLASTER=A%3X I%d D%d T3",sb.base,sb.irq,sb.dma); } diff --git a/src/hardware/tandy_sound.cpp b/src/hardware/tandy_sound.cpp index 357a338..9e5727d 100644 --- a/src/hardware/tandy_sound.cpp +++ b/src/hardware/tandy_sound.cpp @@ -25,6 +25,7 @@ #include "inout.h" #include "mixer.h" #include "mem.h" +#include "setup.h" #define TANDY_DIV 111860 #define TANDY_RATE 22050 @@ -125,7 +126,9 @@ static void TANDYSOUND_CallBack(Bit8u * stream,Bit32u len) { } }; -void TANDY_Init(void) { +void TANDYSOUND_Init(Section* sec) { + Section_prop * section=static_cast(sec); + if(!section->Get_bool("tandy")) return; IO_RegisterWriteHandler(0xc0,write_pc0,"Tandy Sound"); tandy_chan=MIXER_AddChannel(&TANDYSOUND_CallBack,TANDY_RATE,"TANDY"); MIXER_Enable(tandy_chan,false); diff --git a/src/hardware/timer.cpp b/src/hardware/timer.cpp index 0b256bf..758a8a0 100644 --- a/src/hardware/timer.cpp +++ b/src/hardware/timer.cpp @@ -42,12 +42,22 @@ struct PIT_Block { Bit32u last_ticks; }; - +bool TimerAgain; +Bit32u LastTicks; static PIT_Block pit[3]; static Bit32u pit_ticks; /* The amount of pit ticks one host tick is bit shifted */ static Bit32u timer_ticks; /* The amount of pit ticks bitshifted one timer cycle needs */ -static Bit32u timer_buildup; /* The amount of pit ticks waiting */ -#define PIT_TICK_RATE 1193182 +static Bit32u timer_buildup; /* The amount of pit ticks waiting */ + +#define TIMER_AVERAGE 5 +static struct TimerBlock { + float req[TIMER_AVERAGE]; + Bitu req_index; + Bitu req_count; + float req_average; + Bitu ticks; +} timer; + #define PIT_SHIFT 9 #define MAX_PASSED ((PIT_TICK_RATE/4) << PIT_SHIFT) /* Alow 1/4 second of timer build up */ @@ -55,8 +65,9 @@ static Bit32u timer_buildup; /* The amount of pit ticks waiting */ static void counter_latch(Bitu counter) { /* Fill the read_latch of the selected counter with current count */ PIT_Block * p=&pit[counter]; -//TODO Perhaps make it a bit64u for accuracy :) - Bit32u ticks=(((LastTicks - p->last_ticks) * pit_ticks) >> PIT_SHIFT) % p->cntr ; + timer.req_count++; + float pos=timer.req_average*timer.req_count; + Bit16u ticks=pos*p->cntr; switch (p->mode) { case 2: case 3: @@ -102,7 +113,7 @@ static void write_latch(Bit32u port,Bit8u val) { LOG_DEBUG("PIT 0 Timer at %.3g Hz mode %d",PIT_TICK_RATE/(double)p->cntr,p->mode); break; case 0x02: /* Timer hooked to PC-Speaker */ - PCSPEAKER_SetFreq(PIT_TICK_RATE/p->cntr); + PCSPEAKER_SetCounter(p->cntr,p->mode); break; default: LOG_ERROR("PIT:Illegal timer selected for writing"); @@ -233,29 +244,30 @@ void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro) { } void TIMER_AddTicks(Bit32u ticks) { -/* This will run through registered handlers and handle the PIT ticks */ +/* Add pit ticks to the counter */ timer_buildup+=ticks*pit_ticks; if (timer_buildup>MAX_PASSED) timer_buildup=MAX_PASSED; - Bitu add_micro=ticks*1000; + /* Check if there are timer handlers that need to be called */ + Bitu add_micro=timer.ticks*1000; std::list::iterator i; for(i=Timers.begin(); i != Timers.end(); ++i) { - Timer * timer=(*i); - switch (timer->type) { + Timer * timers=(*i); + switch (timers->type) { case T_TICK: - timer->tick.handler(ticks); + if (timer.ticks) timers->tick.handler(timer.ticks); break; case T_MICRO: - timer->micro.count+=add_micro; - if (timer->micro.count>=timer->micro.total) { - timer->micro.count-=timer->micro.total; - timer->micro.handler(); + timers->micro.count+=add_micro; + if (timers->micro.count>=timers->micro.total) { + timers->micro.count-=timers->micro.total; + timers->micro.handler(); } break; case T_DELAY: /* Also unregister the timer handler from the list */ - if (LastTicks>timer->delay.end) { + if (LastTicks>timers->delay.end) { std::list::iterator remove; - timer->delay.handler(); + timers->delay.handler(); remove=i++; Timers.erase(remove); } @@ -265,19 +277,28 @@ void TIMER_AddTicks(Bit32u ticks) { }; }; + timer.ticks=ticks; } void TIMER_CheckPIT(void) { if (timer_buildup>timer_ticks) { timer_buildup-=timer_ticks; + /* Calculate amount of times the time index was requested */ + timer.req[timer.req_index]=timer.req_count; + timer.req_index++;if (timer.req_index>=TIMER_AVERAGE) timer.req_index=0; + timer.req_count=0; + Bitu l;float total=0; + for (l=0;l=vga.draw.width) return; - if ((vga.draw.cursor_row*16)>=vga.draw.height) return; + if (((Bitu)vga.draw.cursor_col*8)>=vga.draw.width) return; + if (((Bitu)vga.draw.cursor_row*16)>=vga.draw.height) return; Bit8u * cursor_draw=bitdata+(vga.draw.cursor_row*16+15)*pitch+vga.draw.cursor_col*8; if (vga.draw.cursor_count>8) { for (Bit8u loop=0;loop<8;loop++) *cursor_draw++=15; diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index 57466e7..64c8020 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -22,7 +22,7 @@ #include "callback.h" #include "inout.h" #include "mem.h" - +#include "timer.h" static Bitu call_int1a,call_int11,call_int8,call_int17,call_int12,call_int15,call_int1c; @@ -136,6 +136,12 @@ static Bitu INT17_Handler(void) { return CBRET_NONE; }; +static void WaitFlagEvent(void) { + PhysPt where=Real2Phys(mem_readd(BIOS_WAIT_FLAG_POINTER)); + mem_writeb(where,mem_readb(where)|0x80); + mem_writeb(BIOS_WAIT_FLAG_ACTIVE,0); +} + static Bitu INT15_Handler(void) { switch (reg_ah) { case 0x06: @@ -149,6 +155,12 @@ static Bitu INT15_Handler(void) { /* Carry should be set but let's just set it just in case */ CALLBACK_SCF(true); break; + case 0x83: /* BIOS - SET EVENT WAIT INTERVAL */ + mem_writed(BIOS_WAIT_FLAG_POINTER,RealMake(SegValue(es),reg_bx)); + mem_writed(BIOS_WAIT_FLAG_COUNT,reg_cx<<16|reg_dx); + mem_writeb(BIOS_WAIT_FLAG_ACTIVE,1); + TIMER_RegisterDelayHandler(&WaitFlagEvent,reg_cx<<16|reg_dx); + break; case 0x84: /* BIOS - JOYSTICK SUPPORT (XT after 11/8/82,AT,XT286,PS) */ //Does anyone even use this? LOG_WARN("INT15:84:Bios Joystick functionality not done"); @@ -181,6 +193,8 @@ static Bitu INT15_Handler(void) { break; default: LOG_WARN("INT15:Unknown call %2X",reg_ah); + reg_ah=0x86; + CALLBACK_SCF(false); } return CBRET_NONE; }; @@ -193,7 +207,8 @@ static void INT15_StartUp(void) { void BIOS_SetupKeyboard(void); void BIOS_SetupDisks(void); -void BIOS_Init(void) { +void BIOS_Init(Section* sec) { + MSG_Add("BIOS_CONFIGFILE_HELP","Nothing to setup yet!\n"); /* Clear the Bios Data Area */ for (Bit16u i=0;i<1024;i++) real_writeb(0x40,i,0); /* Setup all the interrupt handlers the bios controls */ @@ -205,7 +220,7 @@ void BIOS_Init(void) { mem_writed(BIOS_TIMER,0); //Calculate the correct time RealSetVec(0x8,CALLBACK_RealPointer(call_int8)); /* INT10 Video Bios */ - INT10_StartUp(); + /* INT 11 Get equipment list */ call_int11=CALLBACK_Allocate(); CALLBACK_Setup(call_int11,&INT11_Handler,CB_IRET); diff --git a/src/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index 428a592..3fcc447 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -329,7 +329,7 @@ static Bitu INT16_Handler(void) { LOG_DEBUG("INT16:55:Word TSR compatible call"); break; default: - E_Exit("INT16:Unhandled call %02X",reg_ah); + LOG_ERROR("INT16:Unhandled call %02X",reg_ah); break; }; diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index d3b694d..0a8cb52 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -27,7 +27,9 @@ #include "regs.h" #include "inout.h" #include "dos_inc.h" +#include "setup.h" +#define EMM_USEHANDLER 1 #define EMM_PAGEFRAME 0xE000 #define EMM_MAX_HANDLES 50 /* 255 Max */ @@ -97,8 +99,23 @@ struct EMM_Handle { static EMM_Handle emm_handles[EMM_MAX_HANDLES]; static EMM_Page emm_pages[EMM_MAX_PAGES]; static EMM_Mapping emm_mappings[EMM_MAX_PHYS]; +static HostPt emm_pagebase[EMM_MAX_PHYS]; Bitu call_int67; +#if EMM_USEHANDLER +Bit8u EMM_ReadHandler(PhysPt start) { + start-=EMM_PAGEFRAME * 16; + Bitu page=start>>14; + return readb(emm_pagebase[page]+(start&0x3fff)); +} + +void EMM_WriteHandler(PhysPt start,Bit8u val) { + start-=EMM_PAGEFRAME * 16; + Bitu page=start>>14; + writeb(emm_pagebase[page]+(start&0x3fff),val); +} +#endif + static Bit16u EMM_GetFreePages(void) { Bit16u count=0; for (Bitu index=0;index=EMM_MAX_HANDLES) {handle=NULL_HANDLE;return EMM_OUT_OF_HANDLES;} } /* Allocate the pages */ @@ -138,7 +155,7 @@ static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) { static Bit8u EMM_ReallocatePages(Bit16u handle,Bit16u & pages) { /* Check for valid handle */ - if (handle>=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE; /* Check for enough pages */ if ((emm_handles[handle].pages+EMM_GetFreePages())=EMM_MAX_PHYS) return EMM_ILL_PHYS; /* Check for valid handle */ - if (handle>=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE; /* Check to do unmapping or mappning */ if (log_page=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE; Bit16u page=emm_handles[handle].first_page; Bit16u pages=emm_handles[handle].pages; while (pages) { @@ -235,7 +262,7 @@ static Bit8u EMM_ReleaseMemory(Bit16u handle) { } /* Reset handle */ emm_handles[handle].first_page=NULL_PAGE; - emm_handles[handle].pages=0; + emm_handles[handle].pages=NULL_HANDLE; emm_handles[handle].saved_page_map=false; memset(&emm_handles[handle].name,0,9); return EMM_NO_ERROR; @@ -243,7 +270,7 @@ static Bit8u EMM_ReleaseMemory(Bit16u handle) { static Bit8u EMM_SavePageMap(Bit16u handle) { /* Check for valid handle */ - if (handle>=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE; /* Check for previous save */ if (emm_handles[handle].saved_page_map) return EMM_PAGE_MAP_SAVED; /* Copy the mappings over */ @@ -255,7 +282,7 @@ static Bit8u EMM_SavePageMap(Bit16u handle) { return EMM_NO_ERROR; } -static Bitu EMM_RestoreMappingTable(void) { +static Bit8u EMM_RestoreMappingTable(void) { Bit8u result; /* Move through the mappings table and setup mapping accordingly */ for (Bitu i=0;i=EMM_MAX_HANDLES || emm_handles[handle].first_page==NULL_PAGE) return EMM_INVALID_HANDLE; + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE; /* Check for previous save */ if (!emm_handles[handle].saved_page_map) return EMM_INVALID_HANDLE; /* Restore the mappings */ @@ -280,7 +307,7 @@ static Bit8u EMM_RestorePageMap(Bit16u handle) { static Bit8u EMM_GetPagesForAllHandles(PhysPt table,Bit16u & handles) { handles=0; for (Bit16u i=0;i0;count--) { + Bit16u page=mem_readw(list);list+=2; + if (page>=EMM_MAX_PHYS) return EMM_ILL_PHYS; + mem_writew(data,page);data+=2; + MEM_BlockWrite(data,&emm_mappings[page],sizeof(EMM_Mapping)); + data+=sizeof(EMM_Mapping); + } + break; + case 0x01: /* Restore Partial Page Map */ + data = SegPhys(ds)+reg_si; + count= mem_readw(data);data+=2; + for (;count>0;count--) { + Bit16u page=mem_readw(data);data+=2; + if (page>=EMM_MAX_PHYS) return EMM_ILL_PHYS; + MEM_BlockRead(data,&emm_mappings[page],sizeof(EMM_Mapping)); + data+=sizeof(EMM_Mapping); + } + return EMM_RestoreMappingTable(); + break; + case 0x02: /* Get Partial Page Map Array Size */ + reg_al=2+reg_bx*(2+sizeof(EMM_Mapping)); + break; + default: + LOG_ERROR("EMS:Call %2X Subfunction %2X not supported",reg_ah,reg_al); + return EMM_FUNC_NOSUP; + } + return 0; +} + + static Bitu INT67_Handler(void) { Bitu i; switch (reg_ah) { @@ -326,12 +391,12 @@ static Bitu INT67_Handler(void) { break; case 0x4b: /* Get Handle Count */ reg_bx=0; - for (i=0;i=EMM_MAX_HANDLES || emm_handles[reg_bx].first_page==NULL_PAGE) {reg_ah=EMM_INVALID_HANDLE;break;} + if (reg_bx>=EMM_MAX_HANDLES || emm_handles[reg_bx].pages==NULL_HANDLE) {reg_ah=EMM_INVALID_HANDLE;break;} reg_bx=emm_handles[reg_dx].pages; reg_ah=EMM_NO_ERROR; break; @@ -339,7 +404,6 @@ static Bitu INT67_Handler(void) { reg_ah=EMM_GetPagesForAllHandles(SegPhys(es)+reg_di,reg_bx); break; case 0x4e: /*Save/Restore Page Map */ - LOG_WARN("Save/resetore %d",reg_al); switch (reg_al) { case 0x00: /* Save Page Map */ MEM_BlockWrite(SegPhys(es)+reg_di,emm_mappings,sizeof(emm_mappings)); @@ -364,7 +428,11 @@ static Bitu INT67_Handler(void) { break; } break; - case 0x50: // Map/Unmap multiple handle pages + case 0x4f: /* Save/Restore Partial Page Map */ + reg_ah=EMM_PartialPageMapping(); + break; + + case 0x50: /* Map/Unmap multiple handle pages */ reg_ah = EMM_NO_ERROR; switch (reg_al) { case 0x00: // use physical page numbers @@ -413,7 +481,7 @@ static Bitu INT67_Handler(void) { reg_ah = EMM_NO_ERROR; break; case 0xDE: /* VCPI Functions */ - LOG_ERROR("VCPI Functions not supported"); + LOG_ERROR("VCPI Functions %X not supported",reg_al); reg_ah=EMM_FUNC_NOSUP; break; default: @@ -426,14 +494,16 @@ static Bitu INT67_Handler(void) { -void EMS_Init(void) { +void EMS_Init(Section* sec) { + Section_prop * section=static_cast(sec); + Bitu size=section->Get_int("emssize"); + if (!size) return; call_int67=CALLBACK_Allocate(); CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET); /* Register the ems device */ DOS_Device * newdev = new device_EMM(); DOS_AddDevice(newdev); - /* Add a little hack so it appears that there is an actual ems device installed */ char * emsname="EMMXXXX0"; Bit16u seg=DOS_GetMemory(2); //We have 32 bytes @@ -452,12 +522,20 @@ void EMS_Init(void) { } for (i=0;itwidth*row)*curmode->cheight+cleft; @@ -104,8 +103,8 @@ void INT10_ScrollWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8s nlines,Bit end=cul; next=-1; } else if (nlines<0) { - start=cul-nlines-1; - end=clr; + start=rul-nlines-1; + end=rlr; next=1; } else { nlines=rlr-rul+1; @@ -127,8 +126,8 @@ filling: if (nlines>0) { start=rul; } else { - nlines-=nlines; - start=rlr-nlines; + nlines=-nlines; + start=rlr-nlines+1; } for (;nlines>0;nlines--) { switch (curmode->memmodel) { diff --git a/src/ints/int10_misc.cpp b/src/ints/int10_misc.cpp index 953b16b..2ec9f01 100644 --- a/src/ints/int10_misc.cpp +++ b/src/ints/int10_misc.cpp @@ -23,9 +23,7 @@ -#if defined (_MSC_VER) #pragma pack(1) -#endif struct Dynamic_Functionality { RealPt static_table; /* 00h DWORD address of static functionality table */ Bit8u cur_mode; /* 04h BYTE video mode in effect */ @@ -70,19 +68,10 @@ struct Dynamic_Functionality { 7 reserved */ Bit8u reserved2[13]; /* 33h 13 BYTEs reserved (00h) */ -} -#if defined (_MSC_VER) -; +} GCC_ATTRIBUTE(packed); #pragma pack() -#else -__attribute__ ((packed)); -#endif - - void INT10_GetFuncStateInformation(PhysPt save) { - - /* set static state pointer */ mem_writed(save,int10_romarea.static_state); /* Copy BIOS Segment areas */ diff --git a/src/ints/int10_modes.cpp b/src/ints/int10_modes.cpp index 0419ba9..7932d2b 100644 --- a/src/ints/int10_modes.cpp +++ b/src/ints/int10_modes.cpp @@ -274,6 +274,44 @@ void INT10_SetVideoMode(Bit8u mode) { modeset_ctl=real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL); + + /* Reset Attribute ctl into address mode just to be safe */ + + IO_Read(VGAREG_ACTL_RESET); + // Set the High Attribute Ctl + for(i=0x10;i<=ACTL_MAX_REG;i++) { + IO_Write(VGAREG_ACTL_ADDRESS,(Bit8u)i); + IO_Write(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]); + } + // Set Sequencer Ctl + for(i=0;i<=SEQU_MAX_REG;i++) { + IO_Write(VGAREG_SEQU_ADDRESS,(Bit8u)i); + IO_Write(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]); + } + + // Set Grafx Ctl + for(i=0;i<=GRDC_MAX_REG;i++) { + IO_Write(VGAREG_GRDC_ADDRESS,(Bit8u)i); + IO_Write(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]); + } + + // Set CRTC address VGA or MDA + crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS; + // Set CRTC regs + for(i=0;i<=CRTC_MAX_REG;i++) { + IO_Write(crtc_addr,(Bit8u)i); + IO_Write(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]); + } + + // Set the misc register + IO_Write(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg); + + // Enable video + IO_Write(VGAREG_ACTL_ADDRESS,0x20); + IO_Read(VGAREG_ACTL_RESET); + + //Set the palette + if ((modeset_ctl&0x08)==0x8) LOG_DEBUG("INT10:Mode set without palette"); if((modeset_ctl&0x08)==0) { // Set the PEL mask IO_Write(VGAREG_PEL_MASK,vga_modes[line].pelmask); @@ -312,40 +350,13 @@ void INT10_SetVideoMode(Bit8u mode) { } } - /* Reset Attribute ctl into address mode just to be safe */ - IO_Read(VGAREG_ACTL_RESET); - // Set Attribute Ctl - for(i=0;i<=ACTL_MAX_REG;i++) { + // Set the Low Attribute Ctl + for(i=0;i<=0xf;i++) { IO_Write(VGAREG_ACTL_ADDRESS,(Bit8u)i); IO_Write(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]); } - // Set Sequencer Ctl - for(i=0;i<=SEQU_MAX_REG;i++) { - IO_Write(VGAREG_SEQU_ADDRESS,(Bit8u)i); - IO_Write(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]); - } - - // Set Grafx Ctl - for(i=0;i<=GRDC_MAX_REG;i++) { - IO_Write(VGAREG_GRDC_ADDRESS,(Bit8u)i); - IO_Write(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]); - } - - // Set CRTC address VGA or MDA - crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS; - // Set CRTC regs - for(i=0;i<=CRTC_MAX_REG;i++) { - IO_Write(crtc_addr,(Bit8u)i); - IO_Write(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]); - } - - // Set the misc register - IO_Write(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg); - - // Enable video - IO_Write(VGAREG_ACTL_ADDRESS,0x20); - IO_Read(VGAREG_ACTL_RESET); + Bit32u tel; if(clearmem) { if(vga_modes[line].type==TEXT) { @@ -377,6 +388,7 @@ void INT10_SetVideoMode(Bit8u mode) { real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight); real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem << 7))); real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9); + real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0); real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f); // FIXME We nearly have the good tables. to be reworked diff --git a/src/ints/int10_put_pixel.cpp b/src/ints/int10_put_pixel.cpp index 74fd6fd..eb425c0 100644 --- a/src/ints/int10_put_pixel.cpp +++ b/src/ints/int10_put_pixel.cpp @@ -21,12 +21,6 @@ #include "inout.h" #include "int10.h" -union VGA_Memory { - Bit8u linear[64*1024*4]; - Bit8u paged[64*1024][4]; -}; -extern VGA_Memory vga_mem; - static Bit8u cga_masks[4]={~192,~48,~12,~3}; void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { @@ -39,7 +33,12 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { Bit16u off=(y>>1)*80+(x>>2); if (y&1) off+=8*1024; Bit8u old=real_readb(0xb800,off); - old=old&cga_masks[x&3]|((color&3) << (2*(3-(x&3)))); + if (color & 0x80) { + color&=3; + old^=color << (2*(3-(x&3))); + } else { + old=old&cga_masks[x&3]|((color&3) << (2*(3-(x&3)))); + } real_writeb(0xb800,off,old); } break; @@ -51,20 +50,27 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { IO_Write(0x3ce,0x0);IO_Write(0x3cf,color); /* Enable all the set/resets */ IO_Write(0x3ce,0x1);IO_Write(0x3cf,0xf); + /* test for xorring */ + if (color & 0x80) { IO_Write(0x3ce,0x3);IO_Write(0x3cf,0x18); } //Perhaps also set mode 1 /* Calculate where the pixel is in video memory */ - Bit16u base_address=((((curmode->sheight*curmode->swidth)>>3)|0xff)+1)*page; - PhysPt off=0xa0000+base_address+((y*curmode->swidth+x)>>3); + PhysPt off=0xa0000+curmode->slength*page+((y*curmode->swidth+x)>>3); /* Bitmask and set/reset should do the rest */ mem_readb(off); mem_writeb(off,0xff); + /* Restore bitmask */ + IO_Write(0x3ce,0x8);IO_Write(0x3cf,0xff); + /* Restore write operating if changed */ + if (color & 0x80) { IO_Write(0x3ce,0x3);IO_Write(0x3cf,0x0); } break; } - case CTEXT: - case MTEXT: + case LINEAR8: + mem_writeb(Real2Phys(RealMake(0xa000,y*320+x)),color); + break; case PLANAR1: case PLANAR2: - case LINEAR8: + case CTEXT: + case MTEXT: default: LOG_WARN("INT10:PutPixel Unhanled memory model"); break; @@ -72,7 +78,6 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { } void INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color) { - VGAMODES * curmode=GetCurrentMode(); switch (curmode->memmodel) { case CGA: @@ -83,6 +88,30 @@ void INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color) { *color=val<<((x&3)*2); } break; + case PLANAR4: + { + /* Calculate where the pixel is in video memory */ + PhysPt off=0xa0000+curmode->slength*page+((y*curmode->swidth+x)>>3); + Bitu shift=7-(x & 7); + /* Set the read map */ + *color=0; + IO_Write(0x3ce,0x4);IO_Write(0x3cf,0); + *color|=((mem_readb(off)>>shift) & 1) << 0; + IO_Write(0x3ce,0x4);IO_Write(0x3cf,1); + *color|=((mem_readb(off)>>shift) & 1) << 1; + IO_Write(0x3ce,0x4);IO_Write(0x3cf,2); + *color|=((mem_readb(off)>>shift) & 1) << 2; + IO_Write(0x3ce,0x4);IO_Write(0x3cf,3); + *color|=((mem_readb(off)>>shift) & 1) << 3; + break; + } + case LINEAR8: + *color=mem_readb(PhysMake(0xa000,320*y+x)); + break; + case PLANAR1: + case PLANAR2: + case CTEXT: + case MTEXT: default: LOG_WARN("INT10:GetPixel Unhanled memory model"); break; diff --git a/src/ints/mouse.cpp b/src/ints/mouse.cpp index 23c95fe..ad3a084 100644 --- a/src/ints/mouse.cpp +++ b/src/ints/mouse.cpp @@ -25,7 +25,7 @@ #include "mouse.h" #include "pic.h" #include "inout.h" - +#include "int10.h" static Bitu call_int33,call_int74; @@ -35,24 +35,22 @@ struct button_event { }; #define QUEUE_SIZE 32 -//TODO Maybe use :) +#define MOUSE_BUTTONS 3 #define MOUSE_IRQ 12 -#define POS_X (Bit16s)(mouse.x*mouse.range_x) -#define POS_Y (Bit16s)(mouse.y*mouse.range_y) - +#define POS_X (Bit16s)(mouse.x) +#define POS_Y (Bit16s)(mouse.y) static struct { Bit16u buttons; - Bit16u times_pressed[3]; - Bit16u times_released[3]; - Bit16u last_released_x[3]; - Bit16u last_released_y[3]; - Bit16u last_pressed_x[3]; - Bit16u last_pressed_y[3]; + Bit16u times_pressed[MOUSE_BUTTONS]; + Bit16u times_released[MOUSE_BUTTONS]; + Bit16u last_released_x[MOUSE_BUTTONS]; + Bit16u last_released_y[MOUSE_BUTTONS]; + Bit16u last_pressed_x[MOUSE_BUTTONS]; + Bit16u last_pressed_y[MOUSE_BUTTONS]; Bit16s shown; float add_x,add_y; Bit16u min_x,max_x,min_y,max_y; - float range_x,range_y; float mickey_x,mickey_y; float x,y; button_event event_queue[QUEUE_SIZE]; @@ -61,8 +59,8 @@ static struct { Bit16u sub_mask; } mouse; -#define X_MICKEY 500 -#define Y_MICKEY 500 +#define X_MICKEY 8 +#define Y_MICKEY 8 #define MOUSE_MOVED 1 #define MOUSE_LEFT_PRESSED 2 @@ -72,7 +70,7 @@ static struct { #define MOUSE_MIDDLE_PRESSED 32 #define MOUSE_MIDDLE_RELEASED 64 -inline void Mouse_AddEvent(Bit16u type) { +INLINE void Mouse_AddEvent(Bit16u type) { if (mouse.events1) mouse.x=1; - if (mouse.x<0) mouse.x=0; + if (mouse.x>mouse.max_x) mouse.x=mouse.max_x;; + if (mouse.x1) mouse.y=1; - if (mouse.y<0) mouse.y=0; + if (mouse.y>mouse.max_y) mouse.y=mouse.max_y;; + if (mouse.y=MOUSE_BUTTONS) break; reg_ax=mouse.buttons; reg_cx=mouse.last_pressed_x[but]; mouse.last_pressed_x[but]=0; @@ -199,6 +201,7 @@ static Bitu INT33_Handler(void) { case 0x06: /* Return Button Release Data */ { Bit16u but=reg_bx; + if (but>=MOUSE_BUTTONS) break; reg_ax=mouse.buttons; reg_cx=mouse.last_released_x[but]; mouse.last_released_x[but]=0; @@ -211,13 +214,10 @@ static Bitu INT33_Handler(void) { case 0x07: /* Define horizontal cursor range */ mouse.min_x=reg_cx; mouse.max_x=reg_dx; - mouse.range_x=mouse.max_x-mouse.min_x; -//TODO Check for range start 0 break; case 0x08: /* Define vertical cursor range */ mouse.min_y=reg_cx; mouse.max_y=reg_dx; - mouse.range_y=mouse.max_y-mouse.min_y; break; case 0x09: /* Define GFX Cursor */ LOG_WARN("MOUSE:Define gfx cursor not supported"); @@ -240,7 +240,8 @@ static Bitu INT33_Handler(void) { mouse.mickey_y=0; break; case 0x14: /* Exchange event-handler */ - { Bit16u oldSeg = mouse.sub_seg; + { + Bit16u oldSeg = mouse.sub_seg; Bit16u oldOfs = mouse.sub_ofs; Bit16u oldMask= mouse.sub_mask; // Set new values @@ -251,7 +252,8 @@ static Bitu INT33_Handler(void) { reg_cx = oldMask; reg_dx = oldOfs; SegSet16(es,oldSeg); - }; break; + } + break; case 0x1c: /* Set interrupt rate */ /* Can't really set a rate this is host determined */ break; @@ -267,9 +269,9 @@ static Bitu INT33_Handler(void) { break; default: LOG_ERROR("Mouse Function %2X",reg_ax); - }; + } return CBRET_NONE; -}; +} static Bitu INT74_Handler(void) { if (mouse.events>0) { @@ -301,16 +303,13 @@ static Bitu INT74_Handler(void) { } IO_Write(0xa0,0x20); /* Check for more Events if so reactivate IRQ */ - if (mouse.events) { PIC_ActivateIRQ(12); } - return CBRET_NONE; -}; +} - -void MOUSE_Init(void) { +void MOUSE_Init(Section* sec) { call_int33=CALLBACK_Allocate(); CALLBACK_Setup(call_int33,&INT33_Handler,CB_IRET); real_writed(0,(0x33<<2),CALLBACK_RealPointer(call_int33)); @@ -319,7 +318,7 @@ void MOUSE_Init(void) { CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRET); real_writed(0,(0x74<<2),CALLBACK_RealPointer(call_int74)); - memset((void *)&mouse,0,sizeof(mouse)); + memset(&mouse,0,sizeof(mouse)); mouse_reset(); -}; +} diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index d08bd65..d369d35 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -23,6 +23,7 @@ #include "mem.h" #include "regs.h" #include "dos_system.h" +#include "setup.h" #define XMS_HANDLES 50 /* 50 XMS Memory Blocks */ @@ -53,6 +54,8 @@ #define XMS_OUT_OF_SPACE 0xa0 #define XMS_OUT_OF_HANDLES 0xa1 #define XMS_INVALID_HANDLE 0xa2 +#define XMS_BLOCK_NOT_LOCKED 0xaa +#define XMS_BLOCK_LOCKED 0xab struct XMS_Block { Bit16u prev,next; @@ -291,8 +294,13 @@ foundnew: reg_bl=XMS_INVALID_HANDLE; return CBRET_NONE; } - if (xms_handles[reg_dx].locked) xms_handles[reg_dx].locked--; - reg_ax=1;reg_bl=0; + if (xms_handles[reg_dx].locked) { + xms_handles[reg_dx].locked--; + reg_ax=1;reg_bl=0; + } else { + reg_ax=0; + reg_bl=XMS_BLOCK_NOT_LOCKED; + } break; case XMS_GET_EMB_HANDLE_INFORMATION: /* 0e */ /* Check for a valid handle */ @@ -324,7 +332,11 @@ foundnew: -void XMS_Init(void) { +void XMS_Init(Section* sec) { + Section_prop * section=static_cast(sec); + Bitu size=section->Get_int("xmssize"); + if (!size) return; + if (size>C_MEM_MAX_SIZE-1) size=C_MEM_MAX_SIZE-1; DOS_AddMultiplexHandler(multiplex_xms); call_xms=CALLBACK_Allocate(); CALLBACK_Setup(call_xms,&XMS_Handler,CB_RETF); @@ -345,6 +357,6 @@ void XMS_Init(void) { /* Setup the 1st handle */ xms_handles[1].active=true; xms_handles[1].phys=1088*1024; /* right behind the hma area */ - xms_handles[1].size=C_MEM_XMS_SIZE*1024-64; + xms_handles[1].size=size*1024-64; } diff --git a/src/misc/Makefile.am b/src/misc/Makefile.am index 3d9eff2..2cea9df 100644 --- a/src/misc/Makefile.am +++ b/src/misc/Makefile.am @@ -1,4 +1,4 @@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libmisc.a -libmisc_a_SOURCES = plugins.cpp programs.cpp messages.cpp support.cpp setup.cpp +libmisc_a_SOURCES = programs.cpp messages.cpp support.cpp setup.cpp diff --git a/src/misc/Makefile.in b/src/misc/Makefile.in index 46f958a..d5ae517 100644 --- a/src/misc/Makefile.in +++ b/src/misc/Makefile.in @@ -84,7 +84,7 @@ install_sh = @install_sh@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libmisc.a -libmisc_a_SOURCES = plugins.cpp programs.cpp messages.cpp support.cpp setup.cpp +libmisc_a_SOURCES = programs.cpp messages.cpp support.cpp setup.cpp subdir = src/misc mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h @@ -93,8 +93,8 @@ LIBRARIES = $(noinst_LIBRARIES) libmisc_a_AR = $(AR) cru libmisc_a_LIBADD = -am_libmisc_a_OBJECTS = plugins.$(OBJEXT) programs.$(OBJEXT) \ - messages.$(OBJEXT) support.$(OBJEXT) setup.$(OBJEXT) +am_libmisc_a_OBJECTS = programs.$(OBJEXT) messages.$(OBJEXT) \ + support.$(OBJEXT) setup.$(OBJEXT) libmisc_a_OBJECTS = $(am_libmisc_a_OBJECTS) DEFS = @DEFS@ @@ -104,9 +104,8 @@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles -@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/messages.Po ./$(DEPDIR)/plugins.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/programs.Po ./$(DEPDIR)/setup.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/support.Po +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/messages.Po ./$(DEPDIR)/programs.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/setup.Po ./$(DEPDIR)/support.Po CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) @@ -143,7 +142,6 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/messages.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugins.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/programs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/support.Po@am__quote@ diff --git a/src/misc/messages.cpp b/src/misc/messages.cpp index d7e05b2..4b5e5af 100644 --- a/src/misc/messages.cpp +++ b/src/misc/messages.cpp @@ -23,24 +23,54 @@ #include "cross.h" #include "support.h" #include "setup.h" +#include +#include +using namespace std; #define LINE_IN_MAXLEN 1024 -struct MessageBlock -{ - char * name; - char * string; - MessageBlock * next; +struct MessageBlock { + string name; + string val; + MessageBlock(const char* _name, const char* _val): + name(_name),val(_val){} }; -static MessageBlock * first_message; +static list Lang; +typedef list::iterator itmb; +void MSG_Add(const char * _name, const char* _val) { + /* Find the message */ + for(itmb tel=Lang.begin();tel!=Lang.end();tel++) { + if((*tel).name==_name) { + return; + } + } + /* Even if the message doesn't exist add it */ + Lang.push_back(MessageBlock(_name,_val)); +} -static void LoadMessageFile(char * fname) { +void MSG_Replace(const char * _name, const char* _val) { + /* Find the message */ + for(itmb tel=Lang.begin();tel!=Lang.end();tel++) { + if((*tel).name==_name) { + itmb teln=tel; + teln++; + Lang.erase(tel,teln); + break; + } + } + /* Even if the message doesn't exist add it */ + Lang.push_back(MessageBlock(_name,_val)); +} + +static void LoadMessageFile(const char * fname) { + if (!fname) return; + if(*fname=='\0') return;//empty string=no languagefile FILE * mfile=fopen(fname,"rb"); -/* This should never happen and since other modules depend on this use a normal printf */ + /* This should never happen and since other modules depend on this use a normal printf */ if (!mfile) { E_Exit("MSG:Can't load messages: %s",fname); } @@ -67,15 +97,8 @@ static void LoadMessageFile(char * fname) { strcpy(name,linein+1); /* End of string marker */ } else if (linein[0]=='.') { - /* Save the string internally */ - size_t total=sizeof(MessageBlock)+strlen(name)+1+strlen(string)+1; - MessageBlock * newblock=(MessageBlock *)malloc(total); - newblock->name=((char *)newblock)+sizeof(MessageBlock); - newblock->string=newblock->name+strlen(name)+1; - strcpy(newblock->name,name); - strcpy(newblock->string,string); - newblock->next=first_message; - first_message=newblock; + /* Replace/Add the string to the internal langaugefile */ + MSG_Replace(name,string); } else { /* Normal string to be added */ strcat(string,linein); @@ -85,23 +108,29 @@ static void LoadMessageFile(char * fname) { fclose(mfile); } - -char * MSG_Get(char * msg) { - MessageBlock * index=first_message; - while (index) { - if (!strcmp(msg,index->name)) return index->string; - index=index->next; +const char * MSG_Get(char const * msg) { + for(itmb tel=Lang.begin();tel!=Lang.end();tel++){ + if((*tel).name==msg) + { + return (*tel).val.c_str(); + } } - return "Message not found"; + return "Message not Found!\n"; } - -void MSG_Init(void) { - /* Load the messages from "dosbox.lang file" */ - first_message=0; - char filein[CROSS_LEN]; - strcpy(filein,dosbox_basedir); - strcat(filein,"dosbox.lang"); - LoadMessageFile(filein); +void MSG_Write(const char * location) { + FILE* out=fopen(location,"w+b"); + if(out==NULL) return;//maybe an error? + for(itmb tel=Lang.begin();tel!=Lang.end();tel++){ + fprintf(out,":%s\n%s.\n",(*tel).name.c_str(),(*tel).val.c_str()); + } + fclose(out); +} + +void MSG_Init(Section_prop * section) { + std::string file_name; + if (control->cmdline->FindString("-lang",file_name)) { + LoadMessageFile(file_name.c_str()); + } else LoadMessageFile(section->Get_string("language")); } diff --git a/src/misc/plugins.cpp b/src/misc/plugins.cpp deleted file mode 100644 index 35cfe94..0000000 --- a/src/misc/plugins.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2002 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include - -#ifdef WIN32 -#include -#endif - -#include "dosbox.h" -#include "regs.h" -#include "mem.h" -#include "inout.h" -#include "pic.h" -#include "modules.h" -#include "programs.h" -#include "timer.h" -#include "dma.h" -#include "mixer.h" - - -struct PLUGIN_Function { - char * name; - void * function; -}; - -struct PLUGIN_Module { -#ifdef WIN32 - HINSTANCE handle; -#endif - - PLUGIN_Module * next; -}; - - -static PLUGIN_Function functions[]={ -"IO_RegisterReadHandler", (void *)IO_RegisterReadHandler, -"IO_RegisterWriteHandler", (void *)IO_RegisterWriteHandler, -"IO_FreeReadHandler", (void *)IO_FreeReadHandler, -"IO_FreeWriteHandler", (void *)IO_FreeWriteHandler, - -"IRQ_RegisterEOIHandler", (void *)PIC_RegisterIRQ, -"IRQ_FreeEOIHandler", (void *)PIC_FreeIRQ, -"IRQ_Activate", (void *)PIC_ActivateIRQ, -"IRQ_Deactivate", (void *)PIC_DeActivateIRQ, - -"TIMER_RegisterMicroHandler", (void *)TIMER_RegisterMicroHandler, -"TIMER_RegisterTickHandler", (void *)TIMER_RegisterTickHandler, - -"DMA_8_Read", (void *)DMA_8_Read, -"DMA_16_Read", (void *)DMA_16_Read, - -"DMA_8_Write", (void *)DMA_8_Write, -"DMA_16_Write", (void *)DMA_16_Write, - -"MIXER_AddChannel", (void *)MIXER_AddChannel, -"MIXER_SetVolume", (void *)MIXER_SetVolume, -"MIXER_SetFreq", (void *)MIXER_SetFreq, -"MIXER_SetMode", (void *)MIXER_SetMode, -"MIXER_Enable", (void *)MIXER_Enable, - -0,0 -}; - - -class PLUGIN : public Program { -public: - PLUGIN(PROGRAM_Info * program_info); - void Run(void); -}; - -PLUGIN::PLUGIN(PROGRAM_Info * info):Program(info) { - -} - - -void PLUGIN::Run(void) { - -} - - - -static void PLUGIN_ProgramStart(PROGRAM_Info * info) { - PLUGIN * tempPLUGIN=new PLUGIN(info); - tempPLUGIN->Run(); - delete tempPLUGIN; -} - - - -bool PLUGIN_FindFunction(char * name,void * * function) { -/* Run through table and hope to find a match */ - Bitu index=0; - while (functions[index].name) { - if (strcmp(functions[index].name,name)==0) { - *function=functions[index].function; - return true; - }; - index++; - } - return false; -} - - -bool PLUGIN_LoadModule(char * name) { - MODULE_StartHandler starter; - -#ifdef WIN32 - HMODULE module; - module=LoadLibrary(name); - if (!module) return false; -/* Look for the module start functions */ - FARPROC address; - address=GetProcAddress(module,MODULE_START_PROC); - starter=(MODULE_StartHandler)address; -#else -//TODO LINUX - - - - -#endif - starter(PLUGIN_FindFunction); -return false; - -} - - - -void PLUGIN_Init(void) { - PROGRAMS_MakeFile("PLUGIN.COM",PLUGIN_ProgramStart); -// PLUGIN_LoadModule("c:\\dosbox\\testmod.dll"); -}; - - - - - - - - - - diff --git a/src/misc/programs.cpp b/src/misc/programs.cpp index 6b66f00..2a9c93d 100644 --- a/src/misc/programs.cpp +++ b/src/misc/programs.cpp @@ -25,6 +25,7 @@ #include "regs.h" #include "support.h" #include "cross.h" +#include "setup.h" Bitu call_program; @@ -55,30 +56,19 @@ void PROGRAMS_MakeFile(char * name,PROGRAMS_Main * main) { } + static Bitu PROGRAMS_Handler(void) { /* This sets up everything for a program start up call */ - /* First get the current psp */ - PROGRAM_Info * info=new PROGRAM_Info; - info->psp_seg=dos.psp; - MEM_BlockRead(PhysMake(dos.psp,0),&info->psp_copy,sizeof(PSP)); - /* Get the file name cmd_line 0 */ - PhysPt envblock=PhysMake(info->psp_copy.environment,0); - do {} while (mem_readw(envblock++)); - envblock+=3; - MEM_StrCopy(envblock,info->full_name,32); - info->psp_copy.cmdtail.buffer[info->psp_copy.cmdtail.count]=0; - info->cmd_line=info->psp_copy.cmdtail.buffer; - /* Find the program handler somewhere reference in the file */ - Bit16u handle; - DOS_OpenFile(info->full_name,0,&handle); - Bit32u pos=sizeof(PROGRAMS_Main *); - DOS_SeekFile(handle,&pos,DOS_SEEK_END); - PROGRAMS_Main * handler; - Bit16u size=sizeof(PROGRAMS_Main *); - DOS_ReadFile(handle,(Bit8u *)&handler,&size); - DOS_CloseFile(handle); - (*handler)(info); - free(info); + PROGRAMS_Main * handler=0; //It will get sneakily itinialized + Bitu size=sizeof(PROGRAMS_Main *); + /* Read the handler from program code in memory */ + PhysPt reader=PhysMake(dos.psp,256+sizeof(exe_block)); + HostPt writer=(HostPt)&handler; + for (;size>0;size--) *writer++=mem_readb(reader++); + Program * new_program; + (*handler)(&new_program); + new_program->Run(); + delete new_program; return CBRET_NONE; }; @@ -86,11 +76,21 @@ static Bitu PROGRAMS_Handler(void) { /* Main functions used in all program */ -Program::Program(PROGRAM_Info * program_info) { - prog_info=program_info; +Program::Program() { + /* Find the command line and setup the PSP */ + psp = new DOS_PSP(dos.psp); + /* Scan environment for filename */ + char * envscan=(char *)HostMake(psp->GetEnvironment(),0); + while (*envscan) envscan+=strlen(envscan)+1; + envscan+=3; + CommandTail tail; + MEM_BlockRead(PhysMake(dos.psp,128),&tail,128); + if (tail.count<127) tail.buffer[tail.count]=0; + else tail.buffer[126]=0; + cmd = new CommandLine(envscan,tail.buffer); } -void Program::WriteOut(char * format,...) { +void Program::WriteOut(const char * format,...) { char buf[1024]; va_list msg; @@ -103,72 +103,118 @@ void Program::WriteOut(char * format,...) { } -char * Program::GetEnvStr(char * env_str) { +bool Program::GetEnvStr(const char * entry,std::string & result) { /* Walk through the internal environment and see for a match */ -/* Taking some short cuts here to not fuck around with memory structure */ - - char * envstart=(char *)HostMake(prog_info->psp_copy.environment,0); - size_t len=strlen(env_str); - while (*envstart) { - if (strncasecmp(env_str,envstart,len)==0 && envstart[len]=='=') { - return envstart; - } - envstart+=strlen(envstart)+1; - } - return 0; + PhysPt env_read=PhysMake(psp->GetEnvironment(),0); + char env_string[1024]; + result.erase(); + if (!entry[0]) return false; + do { + MEM_StrCopy(env_read,env_string,1024); + if (!env_string[0]) return false; + env_read+=strlen(env_string)+1; + if (!strchr(env_string,'=')) continue; + if (strncasecmp(entry,env_string,strlen(entry))!=0) continue; + result=env_string; + return true; + } while (1); + return false; }; -char * Program::GetEnvNum(Bit32u num) { - char * envstart=(char *)HostMake(prog_info->psp_copy.environment,0); - while (*envstart) { - if (!num) return envstart; - envstart+=strlen(envstart)+1; +bool Program::GetEnvNum(Bitu num,std::string & result) { + char env_string[1024]; + PhysPt env_read=PhysMake(psp->GetEnvironment(),0); + do { + MEM_StrCopy(env_read,env_string,1024); + if (!env_string[0]) break; + if (!num) { result=env_string;return true;} + env_read+=strlen(env_string)+1; num--; - } - return 0; + } while (1); + return false; } -Bit32u Program::GetEnvCount(void) { - char * envstart=(char *)HostMake(prog_info->psp_copy.environment,0); - Bit32u num=0; - while (*envstart) { - envstart+=strlen(envstart)+1; +Bitu Program::GetEnvCount(void) { + PhysPt env_read=PhysMake(psp->GetEnvironment(),0); + Bitu num=0; + while (mem_readb(env_read)!=0) { + for (;mem_readb(env_read);env_read++) {}; + env_read++; num++; } return num; } -bool Program::SetEnv(char * env_entry,char * new_string) { - MCB * env_mcb=(MCB *)HostMake(prog_info->psp_copy.environment-1,0); - upcase(env_entry); - Bit32u env_size=env_mcb->size*16; - if (!env_size) E_Exit("SHELL:Illegal environment size"); - /* First try to find the old entry */ - size_t len=strlen(env_entry); - char * envstart=(char *)HostMake(prog_info->psp_copy.environment,0); - while (*envstart) { - if (strncasecmp(env_entry,envstart,len)==0 && envstart[len]=='=') { - /* Now remove this entry */ - memmove(envstart,envstart+strlen(envstart)+1,env_size); - } else { - envstart+=strlen(envstart)+1; - env_size-=(strlen(envstart)+1); - } +bool Program::SetEnv(const char * entry,const char * new_string) { + PhysPt env_read=PhysMake(psp->GetEnvironment(),0); + PhysPt env_write=env_read; + char env_string[1024]; + do { + MEM_StrCopy(env_read,env_string,1024); + if (!env_string[0]) break; + env_read+=strlen(env_string)+1; + if (!strchr(env_string,'=')) continue; /* Remove corrupt entry? */ + if ((strncasecmp(entry,env_string,strlen(entry))==0) && + env_string[strlen(entry)]=='=') continue; + MEM_BlockWrite(env_write,env_string,strlen(env_string)+1); + env_write+=strlen(env_string)+1; + } while (1); +/* TODO Maybe save the program name sometime. not really needed though */ + /* Save the new entry */ + if (new_string[0]) { + sprintf(env_string,"%s=%s",entry,new_string); + MEM_BlockWrite(env_write,env_string,strlen(env_string)+1); + env_write+=strlen(env_string)+1; } - /* Now add the string if there is space available */ - if (env_size<(strlen(env_entry)+strlen(new_string)+2)) return false; - if (!*new_string) return true; - sprintf(envstart,"%s=%s",env_entry,new_string); - envstart+=strlen(envstart)+1; - *envstart++=0;*envstart++=0;*envstart++=0; + /* Clear out the final piece of the environment */ + mem_writed(env_write,0); return true; } -//TODO Hash table :) +class CONFIG : public Program { +public: + void Run(void); +}; + +void MSG_Write(const char *); + +void CONFIG::Run(void) { + FILE * f; + if (cmd->FindString("-writeconf",temp_line,true)) { + f=fopen(temp_line.c_str(),"wb+"); + if (!f) { + WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),temp_line.c_str()); + return; + } + fclose(f); + control->PrintConfig(temp_line.c_str()); + return; + } + if (cmd->FindString("-writelang",temp_line,true)) { + f=fopen(temp_line.c_str(),"wb+"); + if (!f) { + WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),temp_line.c_str()); + return; + } + fclose(f); + MSG_Write(temp_line.c_str()); + return; + } + WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); +} -void PROGRAMS_Init(void) { +static void CONFIG_ProgramStart(Program * * make) { + *make=new CONFIG; +} + + +void PROGRAMS_Init(Section* sec) { /* Setup a special callback to start virtual programs */ call_program=CALLBACK_Allocate(); CALLBACK_Setup(call_program,&PROGRAMS_Handler,CB_RETF); + PROGRAMS_MakeFile("CONFIG.COM",CONFIG_ProgramStart); + + MSG_Add("PROGRAM_CONFIG_FILE_ERROR","Can't open file %s\n"); + MSG_Add("PROGRAM_CONFIG_USAGE","Config tool:\nUse -writeconf filename to write the current config.\nUse -writelang filename to write the current language strings.\n"); } diff --git a/src/misc/setup.cpp b/src/misc/setup.cpp index 69d47cb..8846a6c 100644 --- a/src/misc/setup.cpp +++ b/src/misc/setup.cpp @@ -19,11 +19,353 @@ #include "dosbox.h" #include "cross.h" #include "setup.h" +#include +#include +#include +#include +#include +#include "support.h" -void SETUP_AddBoolHandler() { +using namespace std; -}; +void Prop_int::SetValue(char* input){ + input=trim(input); + __value._int= atoi(input); +} + +void Prop_string::SetValue(char* input){ + input=trim(input); + __value._string->assign(input); +} + +void Prop_bool::SetValue(char* input){ + input=trim(input); + if((input[0]=='0') ||(input[0]=='D')||( (input[0]=='O') && (input[0]=='F'))||(input[0]=='f')){ + __value._bool=false; + }else{ + __value._bool=true; + } +} +void Prop_hex::SetValue(char* input){ + input=trim(input); + if(!sscanf(input,"%X",&(__value._hex))) __value._hex=0; +} + +void Prop_int::GetValuestring(char* str){ + sprintf(str,"%d",__value._int); +} + +void Prop_string::GetValuestring(char* str){ + sprintf(str,"%s",__value._string->c_str()); +} + +void Prop_bool::GetValuestring(char* str){ + sprintf(str,"%s",__value._bool?"true":"false"); +} + +void Prop_hex::GetValuestring(char* str){ + sprintf(str,"%X",__value._hex); +} + +void Section_prop::Add_int(const char* _propname, int _value) { + Property* test=new Prop_int(_propname,_value); + properties.push_back(test); +} + +void Section_prop::Add_string(const char* _propname, char* _value) { + Property* test=new Prop_string(_propname,_value); + properties.push_back(test); +} + +void Section_prop::Add_bool(const char* _propname, bool _value) { + Property* test=new Prop_bool(_propname,_value); + properties.push_back(test); +} +void Section_prop::Add_hex(const char* _propname, int _value) { + Property* test=new Prop_hex(_propname,_value); + properties.push_back(test); +} +int Section_prop::Get_int(const char* _propname){ + for(it tel=properties.begin();tel!=properties.end();tel++){ + if((*tel)->propname==_propname){ + return ((*tel)->GetValue())._int; + } + } + return 0; +} + +bool Section_prop::Get_bool(const char* _propname){ + for(it tel=properties.begin();tel!=properties.end();tel++){ + if((*tel)->propname==_propname){ + return ((*tel)->GetValue())._bool; + } + } + return false; +} +const char* Section_prop::Get_string(const char* _propname){ + for(it tel=properties.begin();tel!=properties.end();tel++){ + if((*tel)->propname==_propname){ + return ((*tel)->GetValue())._string->c_str(); + } + } + return NULL; +} +int Section_prop::Get_hex(const char* _propname){ + for(it tel=properties.begin();tel!=properties.end();tel++){ + if((*tel)->propname==_propname){ + return ((*tel)->GetValue())._hex; + } + } + return 0; +} +void Section_prop::HandleInputline(char *gegevens){ + char * rest=strrchr(gegevens,'='); + *rest=0; + gegevens=trim(gegevens); + for(it tel=properties.begin();tel!=properties.end();tel++){ + if(!strcasecmp((*tel)->propname.c_str(),gegevens)){ + (*tel)->SetValue(rest+1); + return; + } + } +} + + +void Section_prop::PrintData(FILE* outfile){ + char temp[1000]; /* Should be enough for the properties */ + /* Now print out the individual section entries */ + for(it tel=properties.begin();tel!=properties.end();tel++){ + (*tel)->GetValuestring(temp); + fprintf(outfile,"%s=%s\n",(*tel)->propname.c_str(),temp); + } +} + + +void Section_line::HandleInputline(char* line){ + data+=line; + data+="\n"; +} + +void Section_line::PrintData(FILE* outfile) { + fprintf(outfile,"%s",data.c_str()); +} + +void Config::PrintConfig(const char* configfilename){ + char temp[50]; + FILE* outfile=fopen(configfilename,"w+b"); + if(outfile==NULL) return; + for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ + /* Print out the Section header */ + strcpy(temp,(*tel)->sectionname.c_str()); + lowcase(temp); + fprintf(outfile,"[%s]\n",temp); + upcase(temp); + strcat(temp,"_CONFIGFILE_HELP"); + fprintf(outfile,"# %s",MSG_Get(temp)); + (*tel)->PrintData(outfile); + fprintf(outfile,"\n"); /* Always an empty line between sections */ + } + fclose(outfile); +} + +Section* Config::AddSection(const char* _name,void (*_initfunction)(Section*)){ + Section* blah = new Section(_name); + blah->AddInitFunction(_initfunction); + sectionlist.push_back(blah); + return blah; +} + +Section_prop* Config::AddSection_prop(const char* _name,void (*_initfunction)(Section*)){ + Section_prop* blah = new Section_prop(_name); + blah->AddInitFunction(_initfunction); + sectionlist.push_back(blah); + return blah; +} + +Section_line* Config::AddSection_line(const char* _name,void (*_initfunction)(Section*)){ + Section_line* blah = new Section_line(_name); + blah->AddInitFunction(_initfunction); + sectionlist.push_back(blah); + return blah; +} + + +void Config::Init(){ + for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ + (*tel)->ExecuteInit(); + } +} + +Config::~Config() { + reverse_it cnt=sectionlist.rbegin(); + while (cnt!=sectionlist.rend()) { + delete (*cnt); + cnt++; + } +} + +Section* Config::GetSection(const char* _sectionname){ + for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ + if (!strcasecmp((*tel)->sectionname.c_str(),_sectionname)) return (*tel); + } + return NULL; +} + +void Config::ParseConfigFile(const char* configfilename){ + ifstream in(configfilename); + if (!in) { + LOG_MSG("CONFIG:Can't find config file %s, using default settings",configfilename); + return; + } + char gegevens[150]; + Section* currentsection; + while (in) { + in.getline(gegevens,150); + char* temp; + switch(gegevens[0]){ + case '%': + case '\0': + case '\n': + case '#': + case ' ': + continue; + break; + case '[': + temp = strrchr(gegevens,']'); + *temp=0; + currentsection=GetSection(&gegevens[1]); + break; + default: + try{ + currentsection->HandleInputline(gegevens); + }catch(const char* message){ + message=0; + //EXIT with message + } + break; + } + } +} + +void Config::SetStartUp(void (*_function)(void)) { + _start_function=_function; +} + + +void Config::StartUp(void) { + (*_start_function)(); +} + +bool CommandLine::FindExist(char * name,bool remove) { + cmd_it it; + if (!(FindEntry(name,it,false))) return false; + if (remove) cmds.erase(it); + return true; +} + +bool CommandLine::FindHex(char * name,int & value,bool remove) { + cmd_it it,it_next; + if (!(FindEntry(name,it,true))) return false; + it_next=it;it_next++; + sscanf((*it_next).c_str(),"%X",&value); + if (remove) cmds.erase(it,++it_next); + return true; +} + +bool CommandLine::FindInt(char * name,int & value,bool remove) { + cmd_it it,it_next; + if (!(FindEntry(name,it,true))) return false; + it_next=it;it_next++; + value=atoi((*it_next).c_str()); + if (remove) cmds.erase(it,++it_next); + return true; +} + +bool CommandLine::FindString(char * name,std::string & value,bool remove) { + cmd_it it,it_next; + if (!(FindEntry(name,it,true))) return false; + it_next=it;it_next++; + value=*it_next; + if (remove) cmds.erase(it,++it_next); + return true; +} + +bool CommandLine::FindCommand(int which,std::string & value) { + if (which<1) return false; + if (which>cmds.size()) return false; + cmd_it it=cmds.begin(); + for (;which>1;which--) it++; + value=(*it); + return true; +} + +bool CommandLine::FindEntry(char * name,cmd_it & it,bool neednext) { + for (it=cmds.begin();it!=cmds.end();it++) { + if (!strcasecmp((*it).c_str(),name)) { + cmd_it itnext=it;itnext++; + if (neednext && (itnext==cmds.end())) return false; + return true; + } + } + return false; +} + +bool CommandLine::FindStringBegin(char * begin,std::string & value, bool remove) { + cmd_it it; + for (it=cmds.begin();it!=cmds.end();it++) { + if (strncmp(begin,(*it).c_str(),strlen(begin))==0) { + value=((*it).c_str()+strlen(begin)); + return true; + } + } + return false; +} + +int CommandLine::GetCount(void) { + return cmds.size(); +} + +CommandLine::CommandLine(int argc,char * argv[]) { + if (argc>0) { + file_name=argv[0]; + } + int i=1; + while (i=1) { + va_list msg; + va_start(msg,format); + vsprintf(buf,format,msg); + va_end(msg); + + strcat(buf,"\n"); + } else { + strcpy(buf,"an unsupported feature\n"); + } + throw(buf); +} diff --git a/src/platform/visualc/config.h b/src/platform/visualc/config.h index 114b25b..043d02b 100644 --- a/src/platform/visualc/config.h +++ b/src/platform/visualc/config.h @@ -1,6 +1,6 @@ #define INLINE __forceinline -#define VERSION "0.55" +#define VERSION "0.56" #define GCC_ATTRIBUTE(x) /* attribute not supported */ diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index 2020d9b..1f7bed1 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -19,7 +19,7 @@ #include #include - +#include "setup.h" #include "shell_inc.h" Bitu call_shellstop; @@ -28,10 +28,8 @@ static Bitu shellstop_handler(void) { return CBRET_STOP; } -static void SHELL_ProgramStart(PROGRAM_Info * info) { - DOS_Shell * tempshell=new DOS_Shell(info); - tempshell->Run(); - delete tempshell; +static void SHELL_ProgramStart(Program * * make) { + *make=new DOS_Shell; } #define AUTOEXEC_SIZE 4096 @@ -53,7 +51,7 @@ void SHELL_AddAutoexec(char * line,...) { } -DOS_Shell::DOS_Shell(PROGRAM_Info * info):Program(info) { +DOS_Shell::DOS_Shell():Program(){ input_handle=STDIN; echo=true; exit=false; @@ -96,16 +94,19 @@ void DOS_Shell::ParseLine(char * line) { void DOS_Shell::Run(void) { - /* Check for a direct Command */ - if (strncasecmp(prog_info->cmd_line,"/C ",3)==0) { - ParseLine(prog_info->cmd_line+3); + char input_line[CMD_MAXLINE]; + std::string line; + if (cmd->FindString("/C",line,true)) { + strcpy(input_line,line.c_str()); + line.erase(); return; } /* Start a normal shell and check for a first command init */ WriteOut(MSG_Get("SHELL_STARTUP")); - char input_line[CMD_MAXLINE]; - if (strncasecmp(prog_info->cmd_line,"/INIT ",6)==0) { - ParseLine(prog_info->cmd_line+6); + if (cmd->FindString("/INIT",line,true)) { + strcpy(input_line,line.c_str()); + line.erase(); + ParseLine(input_line); } do { if (bf && bf->ReadLine(input_line)) { @@ -132,51 +133,138 @@ void DOS_Shell::SyntaxError(void) { +void AUTOEXEC_Init(Section * sec) { + MSG_Add("AUTOEXEC_CONFIGFILE_HELP","Add here the lines you want to execute on startup.\n"); + /* Register a virtual AUOEXEC.BAT file */ + + Section_line * section=static_cast(sec); + char * extra=(char *)section->data.c_str(); + if (extra) SHELL_AddAutoexec(extra); + /* Check to see for extra command line options to be added */ + std::string line; + while (control->cmdline->FindString("-c",line,true)) { + SHELL_AddAutoexec((char *)line.c_str()); + } + /* Check for first command being a directory or file */ + char buffer[CROSS_LEN]; + if (control->cmdline->FindCommand(1,line)) { + struct stat test; + strcpy(buffer,line.c_str()); + if (stat(buffer,&test)) { + getcwd(buffer,CROSS_LEN); + strcat(buffer,line.c_str()); + if (stat(buffer,&test)) goto nomount; + } + if (test.st_mode & S_IFDIR) { + SHELL_AddAutoexec("MOUNT C %s",buffer); + SHELL_AddAutoexec("C:"); + } else { + char * name=strrchr(buffer,CROSS_FILESPLIT); + if (!name) goto nomount; + *name++=0; + if (access(buffer,F_OK)) goto nomount; + SHELL_AddAutoexec("MOUNT C %s",buffer); + SHELL_AddAutoexec("C:"); + SHELL_AddAutoexec(name); + } + } +nomount: + VFILE_Register("AUTOEXEC.BAT",(Bit8u *)autoexec_data,strlen(autoexec_data)); +} + +static char * path_string="PATH=Z:\\"; +static char * comspec_string="COMSPEC=Z:\\COMMAND.COM"; +static char * full_name="Z:\\COMMAND.COM"; +static char * init_line="/INIT AUTOEXEC.BAT"; void SHELL_Init() { + /* Add messages */ + MSG_Add("SHELL_CMD_HELP","supported commands are:\n"); + MSG_Add("SHELL_CMD_ECHO_ON","ECHO is on\n"); + MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off\n"); + MSG_Add("SHELL_ILLEGAL_SWITCH","Illegal switch: %s\n"); + MSG_Add("SHELL_CMD_CHDIR_ERROR","Unable to change to: %s\n"); + MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %s\n"); + MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %\n"); + MSG_Add("SHELL_SYNTAXERROR","The syntax of the command is incorrect.\n"); + MSG_Add("SHELL_CMD_SET_NOT_SET","Environment variable %s not defined\n"); + MSG_Add("SHELL_CMD_SET_OUT_OF_SPACE","Not enough environment space left.\n"); + MSG_Add("SHELL_CMD_IF_EXIST_MISSING_FILENAME","IF EXIST: Missing filename.\n"); + MSG_Add("SHELL_CMD_IF_ERRORLEVEL_MISSING_NUMBER","IF ERRORLEVEL: Missing number.\n"); + MSG_Add("SHELL_CMD_IF_ERRORLEVEL_INVALID_NUMBER","IF ERRORLEVEL: Invalid number.\n"); + MSG_Add("SHELL_CMD_GOTO_MISSING_LABEL","No label supplied to GOTO command.\n"); + MSG_Add("SHELL_CMD_GOTO_LABEL_NOT_FOUND","GOTO: Label %s not found.\n"); + MSG_Add("SHELL_CMD_FILE_NOT_FOUND","File %s not found.\n"); + MSG_Add("SHELL_CMD_FILE_EXISTS","File %s already exists.\n"); + MSG_Add("SHELL_CMD_DIR_INTRO","Directory of %s.\n"); + MSG_Add("SHELL_CMD_DIR_PATH_ERROR","Illegal Path\n"); + MSG_Add("SHELL_CMD_DIR_BYTES_USED","%5d File(s) %17s Bytes\n"); + MSG_Add("SHELL_CMD_DIR_BYTES_FREE","%5d Dir(s) %17s Bytes free\n"); + MSG_Add("SHELL_EXECUTE_DRIVE_NOT_FOUND","Drive %c does not exist!\n"); + MSG_Add("SHELL_EXECUTE_ILLEGAL_COMMAND","Illegal command: %s.\n"); + MSG_Add("SHELL_STARTUP","DOSBox Shell v" VERSION "\nFor Help and supported commands type: HELP\n\nHAVE FUN!\nThe DOSBox Team\n\n"); + MSG_Add("SHELL_CMD_CHDIR_HELP","Change Directory.\n"); + MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n"); + MSG_Add("SHELL_CMD_DIR_HELP","Directory View.\n"); + MSG_Add("SHELL_CMD_ECHO_HELP","Display messages and enable/disable command echoing.\n"); + MSG_Add("SHELL_CMD_EXIT_HELP","Exit from the shell.\n"); + MSG_Add("SHELL_CMD_HELP_HELP","Show help.\n"); + MSG_Add("SHELL_CMD_MKDIR_HELP","Make Directory.\n"); + MSG_Add("SHELL_CMD_RMDIR_HELP","Remove Directory.\n"); + MSG_Add("SHELL_CMD_SET_HELP","Change environment variables.\n"); + MSG_Add("SHELL_CMD_IF_HELP","Performs conditional processing in batch programs.\n"); + MSG_Add("SHELL_CMD_GOTO_HELP","Jump to a labeled line in a batch script.\n"); + MSG_Add("SHELL_CMD_TYPE_HELP","Display the contents of a text-file.\n"); + MSG_Add("SHELL_CMD_REM_HELP","Add comments in a batch file.\n"); + + /* Regular startup */ call_shellstop=CALLBACK_Allocate(); + CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET); PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart); + /* Now call up the shell for the first time */ - Bit16u psp_seg=DOS_GetMemory(16); - Bit16u env_seg=DOS_GetMemory(1+(4096/16)); + Bit16u psp_seg=DOS_GetMemory(16+1)+1; + Bit16u env_seg=DOS_GetMemory(1+(4096/16))+1; Bit16u stack_seg=DOS_GetMemory(2048/16); SegSet16(ss,stack_seg); reg_sp=2046; - /* Setup a fake MCB for the environment */ - MCB * env_mcb=(MCB *)HostMake(env_seg,0); + /* Setup MCB and the environment */ + MCB * env_mcb=(MCB *)HostMake(env_seg-1,0); env_mcb->psp_segment=psp_seg; env_mcb->size=4096/16; - real_writed(env_seg+1,0,0); + PhysPt env_write=PhysMake(env_seg,0); + MEM_BlockWrite(env_write,path_string,strlen(path_string)+1); + env_write+=strlen(path_string)+1; + MEM_BlockWrite(env_write,comspec_string,strlen(comspec_string)+1); + env_write+=strlen(comspec_string)+1; + mem_writeb(env_write++,0); + mem_writew(env_write,1); + env_write+=2; + MEM_BlockWrite(env_write,full_name,strlen(full_name)+1); - PSP * psp=(PSP *)HostMake(psp_seg,0); - Bit32u i; - for (i=0;i<20;i++) psp->files[i]=0xff; - psp->files[STDIN]=DOS_FindDevice("CON"); - psp->files[STDOUT]=DOS_FindDevice("CON"); - psp->files[STDERR]=DOS_FindDevice("CON"); - psp->files[STDAUX]=DOS_FindDevice("CON"); - psp->files[STDNUL]=DOS_FindDevice("CON"); - psp->files[STDPRN]=DOS_FindDevice("CON"); - psp->max_files=20; - psp->file_table=RealMake(psp_seg,offsetof(PSP,files)); - /* Save old DTA in psp */ - psp->dta=dos.dta; - /* Set the environment and clear it */ - psp->environment=env_seg+1; - mem_writew(Real2Phys(RealMake(env_seg+1,0)),0); + DOS_PSP psp(psp_seg); + psp.MakeNew(0); + psp.SetFileHandle(STDIN ,DOS_FindDevice("CON")); + psp.SetFileHandle(STDOUT,DOS_FindDevice("CON")); + psp.SetFileHandle(STDERR,DOS_FindDevice("CON")); + psp.SetFileHandle(STDAUX,DOS_FindDevice("CON")); + psp.SetFileHandle(STDNUL,DOS_FindDevice("CON")); + psp.SetFileHandle(STDPRN,DOS_FindDevice("CON")); + psp.SetParent(psp_seg); + /* Set the environment */ + psp.SetEnvironment(env_seg); + /* Set the command line for the shell start up */ + CommandTail tail; + tail.count=strlen(init_line); + strcpy(tail.buffer,init_line); + MEM_BlockWrite(PhysMake(psp_seg,128),&tail,128); /* Setup internal DOS Variables */ - dos.dta=RealMake(psp_seg,0x80); + dos.dta=psp.GetDTA(); dos.psp=psp_seg; - PROGRAM_Info info; - strcpy(info.full_name,"Z:\\COMMAND.COM"); - info.psp_seg=psp_seg; - MEM_BlockRead(PhysMake(dos.psp,0),&info.psp_copy,sizeof(PSP)); - char line[256]; - strcpy(line,"/INIT Z:\\AUTOEXEC.BAT"); - info.cmd_line=line; -/* Handle the last AUTOEXEC.BAT Setup stuff */ - VFILE_Register("AUTOEXEC.BAT",(Bit8u *)autoexec_data,strlen(autoexec_data)); - SHELL_ProgramStart(&info); + Program * new_program; + SHELL_ProgramStart(&new_program); + new_program->Run(); + delete new_program; } diff --git a/src/shell/shell_batch.cpp b/src/shell/shell_batch.cpp index 499a875..fdec91b 100644 --- a/src/shell/shell_batch.cpp +++ b/src/shell/shell_batch.cpp @@ -24,27 +24,18 @@ BatchFile::BatchFile(DOS_Shell * host,char * name, char * cmd_line) { - /* Go through the command line */ - char * cmd_write=cmd_buffer; prev=host->bf; echo=host->echo; shell=host; - cmd_count=0; - while (*cmd_line || (cmd_countbf=prev; shell->echo=echo; @@ -63,8 +54,8 @@ emptyline: *cmd_write++=c; } } while (c!='\n' && n); - *cmd_write++=0; - if (!n) { + *cmd_write=0; + if (!n && cmd_write==temp) { delete this; return false; } @@ -77,29 +68,51 @@ emptyline: while (*cmd_read) { env_write=env_name; if (*cmd_read=='%') { - cmd_read++; - /* Find the fullstring of this */ - - - continue; - + cmd_read++; + if (cmd_read[0]=='%') { + cmd_read++; + *cmd_write++='%'; + } + size_t len=strspn(cmd_read,"0123456789"); + if (len) { + memcpy(env_name,cmd_read,len); + env_name[len]=0;cmd_read+=len; + len=atoi(env_name); + if (cmd->GetCount()FindCommand(len,word)) continue; + strcpy(cmd_write,word.c_str()); + cmd_write+=strlen(word.c_str()); + continue; + } else { + /* Not a command line number has to be an environment */ + char * first=strchr(cmd_read,'%'); + if (!first) continue; *first++=0; + std::string temp; + if (shell->GetEnvStr(cmd_read,temp)) { + char * equals=strchr(temp.c_str(),'='); + if (!equals) continue; + equals++; + strcpy(cmd_write,equals); + cmd_write+=strlen(equals); + } + cmd_read=first; + } } else { *cmd_write++=*cmd_read++; } - *cmd_write=0; } - return true; - + *cmd_write=0; + return true; } - bool BatchFile::Goto(char * where) { Bit32u pos=0; char cmd[CMD_MAXLINE]; char * cmd_write; DOS_SeekFile(file_handle,&pos,DOS_SEEK_SET); - /* Scan till we have a match or return false*/ + /* Scan till we have a match or return false */ Bit8u c;Bit16u n; again: cmd_write=cmd; diff --git a/src/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index 1dcec3b..fee0e18 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -24,19 +24,21 @@ static SHELL_Cmd cmd_list[]={ - "CD", 0, &DOS_Shell::CMD_CHDIR, "Change Directory.", - "CLS", 0, &DOS_Shell::CMD_CLS, "Clear screen.", + "CD", 0, &DOS_Shell::CMD_CHDIR, "SHELL_CMD_CHDIR_HELP", + "CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP", // "COPY", 0, &DOS_Shell::CMD_COPY, "Copy Files.", - "DIR", 0, &DOS_Shell::CMD_DIR, "Directory View.", - "ECHO", 0, &DOS_Shell::CMD_ECHO, "Display messages and enable/disable command echoing.", - "EXIT", 0, &DOS_Shell::CMD_EXIT, "Exit from the shell.", - "HELP", 0, &DOS_Shell::CMD_HELP, "Show help.", - "MD", 0, &DOS_Shell::CMD_MKDIR, "Make Directory.", - "RD", 0, &DOS_Shell::CMD_RMDIR, "Remove Directory.", - "SET", 0, &DOS_Shell::CMD_SET, "Change environment variables.", - "IF", 0, &DOS_Shell::CMD_IF, "Performs conditional processing in batch programs.", - "GOTO", 0, &DOS_Shell::CMD_GOTO, "Jump to a labeled line in a batch script.", - "TYPE", 0, &DOS_Shell::CMD_TYPE, "Display the contents of a text-file.", + "DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP", + "ECHO", 0, &DOS_Shell::CMD_ECHO, "SHELL_CMD_ECHO_HELP", + "EXIT", 0, &DOS_Shell::CMD_EXIT, "SHELL_CMD_EXIT_HELP", + "HELP", 0, &DOS_Shell::CMD_HELP, "SHELL_CMD_HELP_HELP", + "MD", 0, &DOS_Shell::CMD_MKDIR, "SHELL_CMD_MKDIR_HELP", + "RD", 0, &DOS_Shell::CMD_RMDIR, "SHELL_CMD_RMDIR_HELP", + "SET", 0, &DOS_Shell::CMD_SET, "SHELL_CMD_SET_HELP", + "IF", 0, &DOS_Shell::CMD_IF, "SHELL_CMD_IF_HELP", + "GOTO", 0, &DOS_Shell::CMD_GOTO, "SHELL_CMD_GOTO_HELP", + "TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP", + "REM", 0, &DOS_Shell::CMD_REM, "SHELL_CMD_REM_HELP", + /* "CHDIR", 0, &DOS_Shell::CMD_CHDIR, "Change Directory", "MKDIR", 0, &DOS_Shell::CMD_MKDIR, "Make Directory", @@ -63,9 +65,8 @@ void DOS_Shell::DoCommand(char * line) { Bit32u cmd_index=0; while (cmd_list[cmd_index].name) { if (strcasecmp(cmd_list[cmd_index].name,cmd)==0) { -//TODO CHECK Flags (this->*(cmd_list[cmd_index].handler))(line); - return; + return; } cmd_index++; } @@ -84,7 +85,7 @@ void DOS_Shell::CMD_HELP(char * args){ WriteOut(MSG_Get("SHELL_CMD_HELP")); Bit32u cmd_index=0; while (cmd_list[cmd_index].name) { - if (!cmd_list[cmd_index].flags) WriteOut("%-8s %s\n",cmd_list[cmd_index].name,cmd_list[cmd_index].help); + if (!cmd_list[cmd_index].flags) WriteOut("%-8s %s",cmd_list[cmd_index].name,MSG_Get(cmd_list[cmd_index].help)); cmd_index++; } @@ -148,8 +149,8 @@ void DOS_Shell::CMD_RMDIR(char * args) { } }; -static void FormatNumber(Bit32u num,char * buf) { - Bit32u numm,numk,numb; +static void FormatNumber(Bitu num,char * buf) { + Bitu numm,numk,numb; numb=num % 1000; num/=1000; numk=num % 1000; @@ -178,7 +179,6 @@ void DOS_Shell::CMD_DIR(char * args) { WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem); return; } - Bit32u byte_count,file_count,dir_count; Bit32u w_count=0; byte_count=file_count=dir_count=0; @@ -193,48 +193,47 @@ void DOS_Shell::CMD_DIR(char * args) { *(strrchr(path,'\\')+1)=0; WriteOut(MSG_Get("SHELL_CMD_DIR_INTRO"),path); - DTA_FindBlock * dta; - dta=(DTA_FindBlock *)Real2Host(dos.dta); + DOS_DTA dta(dos.dta); bool ret=DOS_FindFirst(args,0xffff); if (!ret) { WriteOut(MSG_Get("SHELL_CMD_FILE_NOT_FOUND"),args); return; } - while (ret) { - /* File name and extension */ + char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u date;Bit16u time;Bit8u attr; + dta.GetResult(name,size,date,time,attr); + char * ext=""; - if (!optW && (*dta->name != '.')) { - ext = strrchr(dta->name, '.'); + if (!optW && (name[0] != '.')) { + ext = strrchr(name, '.'); if (!ext) ext = ""; else *ext++ = '\0'; - }; - - Bit8u day = dta->date & 0x001f; - Bit8u month = (dta->date >> 5) & 0x000f; - Bit8u hour = dta->time >> 5 >> 6; - Bit8u minute = (dta->time >> 5) & 0x003f; - Bit16u year = (dta->date >> 9) + 1980; + } + Bit8u day = date & 0x001f; + Bit8u month = (date >> 5) & 0x000f; + Bit16u year = (date >> 9) + 1980; + Bit8u hour = (time >> 5 ) >> 6; + Bit8u minute = (time >> 5) & 0x003f; /* output the file */ - if (dta->attr & DOS_ATTR_DIRECTORY) { + if (attr & DOS_ATTR_DIRECTORY) { if (optW) { - WriteOut("[%s]",dta->name); - for (Bitu i=14-strlen(dta->name);i>0;i--) WriteOut(" "); + WriteOut("[%s]",name); + for (Bitu i=14-strlen(name);i>0;i--) WriteOut(" "); } else { - WriteOut("%-8s %-3s %-16s %02d-%02d-%04d %2d:%02d\n",dta->name,ext,"",day,month,year,hour,minute); + WriteOut("%-8s %-3s %-16s %02d-%02d-%04d %2d:%02d\n",name,ext,"",day,month,year,hour,minute); } dir_count++; } else { if (optW) { - WriteOut("%-16s",dta->name); + WriteOut("%-16s",name); } else { - FormatNumber(dta->size,numformat); - WriteOut("%-8s %-3s %16s %02d-%02d-%04d %2d:%02d\n",dta->name,ext,numformat,day,month,year,hour,minute); + FormatNumber(size,numformat); + WriteOut("%-8s %-3s %16s %02d-%02d-%04d %2d:%02d\n",name,ext,numformat,day,month,year,hour,minute); } file_count++; - byte_count+=dta->size; + byte_count+=size; } if (optW) { w_count++; @@ -247,8 +246,15 @@ void DOS_Shell::CMD_DIR(char * args) { /* Show the summary of results */ FormatNumber(byte_count,numformat); WriteOut(MSG_Get("SHELL_CMD_DIR_BYTES_USED"),file_count,numformat); + Bit8u drive=dta.GetSearchDrive(); //TODO Free Space - FormatNumber(1024*1024*100,numformat); + Bitu free_space=1024*1024*100; + if (Drives[drive]) { + Bit16u bytes_sector;Bit16u sectors_cluster;Bit16u total_clusters;Bit16u free_clusters; + Drives[drive]->AllocationInfo(&bytes_sector,§ors_cluster,&total_clusters,&free_clusters); + free_space=bytes_sector*sectors_cluster*free_clusters; + } + FormatNumber(free_space,numformat); WriteOut(MSG_Get("SHELL_CMD_DIR_BYTES_FREE"),dir_count,numformat); } @@ -258,23 +264,22 @@ void DOS_Shell::CMD_COPY(char * args) { WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem); return; } - } void DOS_Shell::CMD_SET(char * args) { + std::string line; if (!*args) { /* No command line show all environment lines */ - Bit32u count=GetEnvCount(); - for (Bit32u a=0;a",drive,dir); } - static void outc(Bit8u c) { Bit16u n=1; DOS_WriteFile(STDOUT,&c,&n); @@ -119,14 +118,17 @@ void DOS_Shell::InputCommand(char * line) { size_t first_len=strlen(old.buffer)+1; memmove(&old.buffer[first_len],&old.buffer[0],CMD_OLDSIZE-first_len); strcpy(old.buffer,line); - - - } void DOS_Shell::Execute(char * name,char * args) { char * fullname; - + char line[255]; + if(strlen(args)!=0){ + line[0]=' ';line[1]=0; + strcat(line,args); + }else{ + line[0]=0; + }; /* check for a drive change */ if ((strcmp(name + 1, ":") == 0) && isalpha(*name)) { @@ -143,28 +145,30 @@ void DOS_Shell::Execute(char * name,char * args) { } if (strcasecmp(strrchr(fullname, '.'), ".bat") == 0) { /* Run the .bat file */ - bf=new BatchFile(this,fullname,args); + bf=new BatchFile(this,fullname,line); } else { /* Run the .exe or .com file from the shell */ /* Allocate some stack space for tables in physical memory */ reg_sp-=0x200; //Add Parameter block DOS_ParamBlock block(SegPhys(ss)+reg_sp); + block.Clear(); //Add a filename RealPt file_name=RealMakeSeg(ss,reg_sp+0x20); MEM_BlockWrite(Real2Phys(file_name),fullname,strlen(fullname)+1); /* Fill the command line */ CommandTail cmd; - if (strlen(args)>126) args[126]=0; - cmd.count=strlen(args); - memcpy(cmd.buffer,args,strlen(args)); - cmd.buffer[strlen(args)]=0xd; - MEM_BlockWrite(PhysMake(prog_info->psp_seg,128),&cmd,128); - - block.InitExec(RealMake(prog_info->psp_seg,128)); + if (strlen(line)>126) line[126]=0; + cmd.count=strlen(line); + memcpy(cmd.buffer,line,strlen(line)); + cmd.buffer[strlen(line)]=0xd; + /* Copy command line in stack block too */ + MEM_BlockWrite(SegPhys(ss)+reg_sp+0x100,&cmd,128); + /* Set the command line in the block and save it */ + block.exec.cmdtail=RealMakeSeg(ss,reg_sp+0x100); + block.SaveData(); /* Save CS:IP to some point where i can return them from */ - RealPt newcsip; - newcsip=CALLBACK_RealPointer(call_shellstop); + RealPt newcsip=CALLBACK_RealPointer(call_shellstop); SegSet16(cs,RealSeg(newcsip)); reg_ip=RealOff(newcsip); /* Start up a dos execute interrupt */ @@ -179,8 +183,6 @@ void DOS_Shell::Execute(char * name,char * args) { CALLBACK_RunRealInt(0x21); reg_sp+=0x200; } - - } @@ -193,34 +195,28 @@ static char which_ret[DOS_PATHLENGTH]; char * DOS_Shell::Which(char * name) { /* Parse through the Path to find the correct entry */ - -// if (which_result) free(which_result); - /* Check for extension */ - - - /* Check if name is already ok but just misses an extension */ char * ext=strrchr(name,'.'); if (ext) if (strlen(ext)>4) ext=0; if (ext) { if (DOS_FileExists(name)) return name; } else { - /* try to find .exe .com .bat */ - strcpy(which_ret,name); - strcat(which_ret,bat_ext); - if (DOS_FileExists(which_ret)) return which_ret; + /* try to find .com .exe .bat */ strcpy(which_ret,name); strcat(which_ret,com_ext); if (DOS_FileExists(which_ret)) return which_ret; strcpy(which_ret,name); strcat(which_ret,exe_ext); if (DOS_FileExists(which_ret)) return which_ret; + strcpy(which_ret,name); + strcat(which_ret,bat_ext); + if (DOS_FileExists(which_ret)) return which_ret; } - /* No Path in filename look through %path% */ - - static char path[DOS_PATHLENGTH]; - char * pathenv=GetEnvStr("PATH"); + /* No Path in filename look through path environment string */ + static char path[DOS_PATHLENGTH];std::string temp; + if (!GetEnvStr("PATH",temp)) return 0; + const char * pathenv=temp.c_str(); if (!pathenv) return 0; pathenv=strchr(pathenv,'='); if (!pathenv) return 0; @@ -238,17 +234,16 @@ char * DOS_Shell::Which(char * name) { if (ext) { if (DOS_FileExists(which_ret)) return which_ret; } else { - strcpy(which_ret,path); - strcat(which_ret,bat_ext); - if (DOS_FileExists(which_ret)) return which_ret; strcpy(which_ret,path); strcat(which_ret,com_ext); if (DOS_FileExists(which_ret)) return which_ret; strcpy(which_ret,path); strcat(which_ret,exe_ext); if (DOS_FileExists(which_ret)) return which_ret; + strcpy(which_ret,path); + strcat(which_ret,bat_ext); + if (DOS_FileExists(which_ret)) return which_ret; } - path_write=path; if (*pathenv) pathenv++; } diff --git a/visualc/dosbox.dsp b/visualc/dosbox.dsp index b963277..e4d31a7 100644 --- a/visualc/dosbox.dsp +++ b/visualc/dosbox.dsp @@ -50,7 +50,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 sdlmain.lib sdl.lib curses.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 zlib.lib libpng.lib sdlmain.lib sdl.lib curses.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "dosbox - Win32 Debug" @@ -75,7 +75,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 sdlmain.lib sdl.lib curses.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 zlib.lib libpng.lib sdlmain.lib sdl.lib curses.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF @@ -459,10 +459,6 @@ SOURCE=..\src\misc\messages.cpp # End Source File # Begin Source File -SOURCE=..\src\misc\plugins.cpp -# End Source File -# Begin Source File - SOURCE=..\src\misc\programs.cpp # End Source File # Begin Source File