From 0e247f1518a3a1895f14d24718697ca2615405ab Mon Sep 17 00:00:00 2001 From: "Carl.Kenner" Date: Sat, 2 May 2009 21:27:47 +0000 Subject: [PATCH] DOSBox 0.57 --- ChangeLog | 41 + NEWS | 96 +- README | 3 +- THANKS | 1 + configure | 20 +- configure.in | 2 +- include/callback.h | 2 +- include/cpu.h | 18 +- include/debug.h | 3 +- include/dos_inc.h | 17 +- include/dos_system.h | 2 +- include/mouse.h | 1 + include/pic.h | 24 +- include/render.h | 19 +- include/setup.h | 3 +- include/support.h | 10 +- include/timer.h | 13 +- include/video.h | 21 +- settings.h | 13 +- src/cpu/callback.cpp | 21 +- src/cpu/core_16/instructions.h | 4 +- src/cpu/core_16/main.h | 65 +- src/cpu/core_16/prefix_66.h | 74 +- src/cpu/core_16/prefix_66_of.h | 62 +- src/cpu/core_16/prefix_of.h | 14 +- src/cpu/core_16/stop.h | 2 + src/cpu/core_16/support.h | 160 ++-- src/cpu/core_16/table_ea.h | 98 +-- src/cpu/cpu.cpp | 39 +- src/cpu/flags.cpp | 34 +- src/cpu/slow_16.cpp | 50 +- src/debug/debug.cpp | 318 +++++-- src/debug/debug_disasm.cpp | 15 +- src/debug/debug_gui.cpp | 4 + src/dos/dev_con.h | 295 ++++++- src/dos/dos.cpp | 157 ++-- src/dos/dos_classes.cpp | 2 +- src/dos/dos_execute.cpp | 20 +- src/dos/dos_files.cpp | 57 +- src/dos/dos_ioctl.cpp | 10 +- src/dos/dos_memory.cpp | 46 +- src/dos/dos_misc.cpp | 4 +- src/dos/dos_programs.cpp | 73 +- src/dos/drive_local.cpp | 14 +- src/dos/drive_virtual.cpp | 2 +- src/dos/drives.cpp | 1 + src/dos/drives.h | 8 +- src/dosbox.cpp | 66 +- src/gui/Makefile.am | 2 +- src/gui/Makefile.in | 7 +- src/gui/render.cpp | 211 +++-- src/gui/render_support.h | 228 +++++ src/gui/sdlmain.cpp | 172 ++-- src/hardware/Makefile.am | 3 +- src/hardware/Makefile.in | 34 +- src/hardware/adlib.cpp | 90 +- src/hardware/cmos.cpp | 118 +++ src/hardware/disney.cpp | 102 +++ src/hardware/dma.cpp | 68 +- src/hardware/fmopl.c | 1499 ++++++++++++++++++++++---------- src/hardware/fmopl.h | 196 ++--- src/hardware/gus.cpp | 23 + src/hardware/joystick.cpp | 8 +- src/hardware/keyboard.cpp | 10 +- src/hardware/pcspeaker.cpp | 78 +- src/hardware/pic.cpp | 212 ++++- src/hardware/timer.cpp | 149 ++-- src/hardware/vga.cpp | 160 +++- src/hardware/vga.h | 51 +- src/hardware/vga_attr.cpp | 11 +- src/hardware/vga_crtc.cpp | 58 +- src/hardware/vga_dac.cpp | 47 +- src/hardware/vga_draw.cpp | 103 +-- src/hardware/vga_gfx.cpp | 1 + src/hardware/vga_memory.cpp | 19 +- src/hardware/vga_misc.cpp | 42 +- src/hardware/vga_seq.cpp | 7 +- src/ints/bios.cpp | 49 +- src/ints/bios_disk.cpp | 21 +- src/ints/bios_keyboard.cpp | 4 +- src/ints/ems.cpp | 196 ++++- src/ints/int10.cpp | 10 +- src/ints/int10.h | 2 + src/ints/int10_char.cpp | 35 +- src/ints/int10_modes.cpp | 18 +- src/ints/mouse.cpp | 381 +++++++- src/ints/xms.cpp | 7 +- src/misc/messages.cpp | 4 +- src/misc/programs.cpp | 6 +- src/misc/setup.cpp | 15 +- src/platform/visualc/config.h | 2 +- src/platform/visualc/dirent.c | 10 +- src/shell/shell.cpp | 33 +- src/shell/shell_batch.cpp | 3 +- src/shell/shell_cmds.cpp | 49 +- src/shell/shell_inc.h | 2 + src/shell/shell_misc.cpp | 12 + visualc/dosbox.dsp | 16 + 98 files changed, 4761 insertions(+), 1847 deletions(-) create mode 100644 src/gui/render_support.h create mode 100644 src/hardware/cmos.cpp create mode 100644 src/hardware/disney.cpp create mode 100644 src/hardware/gus.cpp diff --git a/ChangeLog b/ChangeLog index d91901c..dc4db42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,44 @@ +0.57 + - added support for command /C + - fixed all fcb-write functions + - fixed fcb-parseline + - added debugger under linux/freebsd + - added debugger memory breakpoints and autolog function (heavy debug) + - added loadfix.com program that eats up memory (default 64kb) + Usage : loadfix [-option] [programname] [parameters]... + Example: loadfix mm2 (Allocates 64kb and starts executable mm2) + loadfix -32 mm2 (Allocates 32kb and starts executable mm2) + loadfix -128 (Allocates 128kb) + loadfix -f (frees all previous allocated memory) + - added echoing of characters for input function + - added support for backspace for input function + - added partial support for int10:01 set cursortype + - fixed most of the problems/bugs with character input. + - fixed allocationinfo call.(darksun series) + - improved dos support for non-existant functions + - Split screen support + - prefix 66 67 support + - rewrote timingscheme so 1000 hz timers don't cause problems anymore + - update adlib emulation + - fixed some isues with the mouse (double clicks and visible when it shouldn't be) + - improved mouse behaviour (mickey/pixel rate) and detection routines. + - basic ansi.sys support + - Disney sound system emulation + - rewrote upcase/lowcase functions so they work fine with gcc3.2 + - SHELL: added rename and delete + - added support for command /C. Fixed crashes in the shell + - fixed various bugs when exiting dosbox + - fixed a bug in XMS + - fixed a bug with the joystick when pressing a button + - create nicer configfiles. + - bios_disk function improved. + - trapflag support + - improved vertical retrace timing. + - PIT Timer improvements and many bug fixes + - Many many bug fixes to the DOS subsystem + - Support for memory allocation strategy + - rewrote cpu mainloop to act more like a real cpu + 0.56 - added support for a configclass/configfile - added support for writing out the configclass into a configfile diff --git a/NEWS b/NEWS index c39c56c..037b060 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,45 @@ -0.56: +0.57 + - added support for command /C + - fixed all fcb-write functions + - fixed fcb-parseline + - added debugger under linux/freebsd + - added debugger memory breakpoints and autolog function (heavy debug) + - added loadfix.com program that eats up memory (default 64kb) + Usage : loadfix [-option] [programname] [parameters]... + Example: loadfix mm2 (Allocates 64kb and starts executable mm2) + loadfix -32 mm2 (Allocates 32kb and starts executable mm2) + loadfix -128 (Allocates 128kb) + loadfix -f (frees all previous allocated memory) + - added echoing of characters for input function + - added support for backspace for input function + - added partial support for int10:01 set cursortype + - fixed most of the problems/bugs with character input. + - fixed allocationinfo call.(darksun series) + - improved dos support for non-existant functions + - Split screen support + - prefix 66 67 support + - rewrote timingscheme so 1000 hz timers don't cause problems anymore + - update adlib emulation + - fixed some isues with the mouse (double clicks and visible when it shouldn't be) + - improved mouse behaviour (mickey/pixel rate) and detection routines. + - basic ansi.sys support + - Disney sound system emulation + - rewrote upcase/lowcase functions so they work fine with gcc3.2 + - SHELL: added rename and delete + - added support for command /C. Fixed crashes in the shell + - fixed various bugs when exiting dosbox + - fixed a bug in XMS + - fixed a bug with the joystick when pressing a button + - create nicer configfiles. + - bios_disk function improved. + - trapflag support + - improved vertical retrace timing. + - PIT Timer improvements and many bug fixes + - Many many bug fixes to the DOS subsystem + - Support for memory allocation strategy + - rewrote cpu mainloop to act more like a real cpu + +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 @@ -18,31 +59,34 @@ - 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 - - improved support for user mousehandlers - - fixed EGA graphics - - fixed VGA graphics - - fixed the displaying of text in some graphics modes - - fixed write with size 0 - - changed memory management. - - added full emm 3.2 support. - - fixed and cleaned up the cpu flags. - changed interrupt handler. - - speeded up the graphics. - - speeded up the cpu-core - - added new features to the debugger: breakpoint support / data view / command line - - partial support of list of lists (dos info block) - - partial emm 4.0 support - - fixes to graphics core fonts (text in sierra games is now correct) - - changed dma - - improved dma streams from emm memory - - added some cga videomodes - - added more funtions to the keyboard handler + +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. + - changed the basedir routines to use the current working dir instead of argv[0]. This will fix and brake things :) + - illegal command, now displays the command + - wildcmp updated to be case insensitive + - added fcb:open,close,findfirst, findnext. + - fixed rename in drive_local + - added new features to the debugger: breakpoint support / data view / command line + - partial support of list of lists (dos info block) + - full emm 3.2 support + - partial emm 4.0 support + - fixes to graphics core fonts (text in sierra games is now correct) + - improved support for user mousehandlers + - fixed EGA graphics + - fixed VGA graphics + - fixed write with size 0 + - changed memory management. + - fixed and cleaned up the cpu flags. + - changed interrupt handler. + - speeded up the graphics. + - speeded up the cpu-core + - changed dma + - improved dma streams from emm memory + - added some cga videomodes + - added more funtions to the keyboard handler 0.50: -added F3 to repeat the last typed command. diff --git a/README b/README index 7dbc7cc..391b1d5 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -DOSBox v0.56 +DOSBox v0.57 Usage: ====== @@ -122,6 +122,7 @@ Vlad R. of the vdmsound project for excellent sound blaster info. Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator. The Bochs and DOSemu projects which I used for information. Freedos for ideas in making my shell. +The Beta Testers. Contact: ======== diff --git a/THANKS b/THANKS index fdc282e..6e7ae90 100644 --- a/THANKS +++ b/THANKS @@ -6,3 +6,4 @@ Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator. The Bochs and DOSemu projects which I used for information. Freedos for ideas in making my shell. All the people who submitted a bug. +The Beta Testers. diff --git a/configure b/configure index a37a463..d6e06a8 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.56. +# Generated by GNU Autoconf 2.53a for dosbox 0.57. # # 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.56' -PACKAGE_STRING='dosbox 0.56' +PACKAGE_VERSION='0.57' +PACKAGE_STRING='dosbox 0.57' 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.56 to adapt to many kinds of systems. +\`configure' configures dosbox 0.57 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.56:";; + short | recursive ) echo "Configuration of dosbox 0.57:";; 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.56 +dosbox configure 0.57 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.56, which was +It was created by dosbox $as_me 0.57, 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.56 + VERSION=0.57 cat >>confdefs.h <<_ACEOF @@ -4706,7 +4706,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by dosbox $as_me 0.56, which was +This file was extended by dosbox $as_me 0.57, which was generated by GNU Autoconf 2.53a. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4768,7 +4768,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -dosbox config.status 0.56 +dosbox config.status 0.57 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 4fa3482..9417a9d 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Init. -AC_INIT(dosbox,0.56) +AC_INIT(dosbox,0.57) AC_CONFIG_SRCDIR(README) dnl Detect the canonical host and target build environment diff --git a/include/callback.h b/include/callback.h index 00a6745..065dd9b 100644 --- a/include/callback.h +++ b/include/callback.h @@ -24,7 +24,7 @@ typedef Bitu (*CallBack_Handler)(void); extern CallBack_Handler CallBack_Handlers[]; -enum { CB_RETF,CB_IRET }; +enum { CB_RETF,CB_IRET,CB_IRET_STI }; #define CB_MAX 1024 #define CB_SEG 0xC800 diff --git a/include/cpu.h b/include/cpu.h index ca64958..f6f2281 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -19,20 +19,23 @@ #ifndef __CPU_H #define __CPU_H -#include -#include -#include +#include "dosbox.h" +#include "regs.h" +#include "mem.h" /* Some common Defines */ /* A CPU Handler */ -typedef Bitu (CPU_Decoder)(Bits count); +typedef Bitu (CPU_Decoder)(void); extern CPU_Decoder * cpudecoder; -extern Bitu cpu_cycles; + +/* CPU Cycle Timing */ +extern Bits CPU_Cycles; +extern Bits CPU_CycleLeft; +extern Bits CPU_CycleMax; //CPU Stuff void SetCPU16bit(); - //Types of Flag changing instructions enum { t_ADDb=0,t_ADDw,t_ADDd, @@ -63,9 +66,6 @@ enum { t_NOTDONE, }; -enum { rep_NONE,rep_Z,rep_NZ }; - - void Interrupt(Bit8u num); //Flag Handling diff --git a/include/debug.h b/include/debug.h index 2dfa9c6..de1d460 100644 --- a/include/debug.h +++ b/include/debug.h @@ -27,5 +27,6 @@ bool DEBUG_ExitLoop(void); extern Bitu cycle_count; #ifdef C_HEAVY_DEBUG -bool DEBUG_HeavyIsBreakpoint(); +bool DEBUG_HeavyIsBreakpoint(void); +void DEBUG_HeavyWriteLogInstruction(void); #endif diff --git a/include/dos_inc.h b/include/dos_inc.h index 48bc6ab..2a039bd 100644 --- a/include/dos_inc.h +++ b/include/dos_inc.h @@ -63,6 +63,7 @@ struct DOS_Block { Bit8u current_drive; bool verify; bool breakcheck; + bool echo; // if set to true dev_con::read will echo input struct { RealPt indosflag; RealPt mediaid; @@ -119,7 +120,7 @@ bool DOS_ChangeDir(char * dir); bool DOS_MakeDir(char * dir); 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_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free); bool DOS_GetFileAttr(char * name,Bit16u * attr); /* IOCTL Stuff */ @@ -140,22 +141,25 @@ bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks); bool DOS_FreeMemory(Bit16u segment); void DOS_FreeProcessMemory(Bit16u pspseg); Bit16u DOS_GetMemory(Bit16u pages); +void DOS_SetMemAllocStrategy(Bit16u strat); +Bit16u DOS_GetMemAllocStrategy(void); /* FCB stuff */ -bool DOS_FCBOpenCreate(Bit16u seg,Bit16u offset); +bool DOS_FCBOpen(Bit16u seg,Bit16u offset); +bool DOS_FCBCreate(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_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); +Bit8u 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); +bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters); /* Extra DOS Interrupts */ void DOS_SetupMisc(void); @@ -418,8 +422,9 @@ private: extern DOS_InfoBlock dos_infoblock;; INLINE Bit8u RealHandle(Bit16u handle) { + DOS_PSP psp(dos.psp); - return psp.GetFileHandle((Bit8u)handle); + return psp.GetFileHandle(handle); } #endif diff --git a/include/dos_system.h b/include/dos_system.h index 0223a9a..545f661 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -84,7 +84,7 @@ public: 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 AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters)=0; + virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _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; diff --git a/include/mouse.h b/include/mouse.h index 764d550..0123ecb 100644 --- a/include/mouse.h +++ b/include/mouse.h @@ -26,4 +26,5 @@ void Mouse_ButtonPressed(Bit8u button); void Mouse_ButtonReleased(Bit8u button); void Mouse_AutoLock(bool enable); +void Mouse_SetResolution(Bit16u width, Bit16u height); diff --git a/include/pic.h b/include/pic.h index e7b41be..947166b 100644 --- a/include/pic.h +++ b/include/pic.h @@ -19,7 +19,12 @@ #ifndef __PIC_H #define __PIC_H + +#include "cpu.h" + typedef void (PIC_EOIHandler) (void); +typedef void (* PIC_EventHandler)(void); + #define PIC_MAXIRQ 15 #define PIC_NOIRQ 0xFF @@ -27,7 +32,20 @@ typedef void (PIC_EOIHandler) (void); extern Bitu PIC_IRQCheck; extern Bitu PIC_IRQActive; -extern bool PIC_IRQAgain; + +extern Bitu PIC_Ticks; + +INLINE Bitu PIC_Index(void) { + return ((CPU_CycleMax-CPU_CycleLeft-CPU_Cycles)*1000)/CPU_CycleMax; +} + +INLINE Bits PIC_MakeCycles(Bitu amount) { + return (CPU_CycleMax*amount)/1000; +} + +INLINE Bit64u PIC_MicroCount(void) { + return PIC_Ticks*1000+PIC_Index(); +} void PIC_ActivateIRQ(Bit32u irq); @@ -37,8 +55,12 @@ void PIC_runIRQs(void); void PIC_RegisterIRQ(Bit32u irq,PIC_EOIHandler handler,char * name); void PIC_FreeIRQ(Bit32u irq); +Bitu PIC_RunQueue(void); +void PIC_AddIRQ(Bitu irq,Bitu delay); +void PIC_AddEvent(PIC_EventHandler handler,Bitu delay); +void PIC_RemoveEvents(PIC_EventHandler handler); #endif diff --git a/include/render.h b/include/render.h index 74b8aa1..e7a0b84 100644 --- a/include/render.h +++ b/include/render.h @@ -17,9 +17,24 @@ */ -typedef void RENDER_Handler(Bit8u * * data); +enum RENDER_Operation { + OP_None,OP_2xSai,OP_Scale2x +}; -void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu flags, RENDER_Handler * handler); +enum { + DoubleNone= 0x00, + DoubleWidth= 0x01, + DoubleHeight= 0x02, + DoubleBoth= 0x03 +}; + +bool RENDER_StartUpdate(void); + +void RENDER_EndUpdate(void); + +void RENDER_Part(Bit8u * data,Bitu x,Bitu y,Bitu dx,Bitu dy); + +void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu flags); void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue); diff --git a/include/setup.h b/include/setup.h index 865165f..248acf7 100644 --- a/include/setup.h +++ b/include/setup.h @@ -30,13 +30,14 @@ 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); + bool FindStringRemain(char * name,std::string & value); int GetCount(void); private: typedef std::list::iterator cmd_it; diff --git a/include/support.h b/include/support.h index 8857469..8e26058 100644 --- a/include/support.h +++ b/include/support.h @@ -45,15 +45,13 @@ bool ScanCMDHex(char * cmd,char * check,Bits * result); char * StripWord(char * cmd); INLINE char * upcase(char * str) { - char * oldstr=str; - while (*str) *str++=toupper(*str); - return oldstr; + for (char* idx = str; *idx ; idx++) *idx = toupper(*idx); + return str; } INLINE char * lowcase(char * str) { - char * oldstr=str; - while (*str) *str++=tolower(*str); - return oldstr; + for(char* idx = str; *idx ; idx++) *idx = tolower(*idx); + return str; } diff --git a/include/timer.h b/include/timer.h index 9c07747..6511f93 100644 --- a/include/timer.h +++ b/include/timer.h @@ -21,15 +21,12 @@ /* underlying clock rate in HZ */ #include -extern Bit32u LastTicks; - #define PIT_TICK_RATE 1193182 #define GetTicks() SDL_GetTicks() typedef void (*TIMER_TickHandler)(Bitu ticks); typedef void (*TIMER_MicroHandler)(void); -typedef void (*TIMER_DelayHandler)(void); typedef void TIMER_Block; @@ -38,18 +35,12 @@ typedef void TIMER_Block; TIMER_Block * TIMER_RegisterTickHandler(TIMER_TickHandler handler); /* Register a function to be called every x microseconds */ TIMER_Block * TIMER_RegisterMicroHandler(TIMER_MicroHandler handler,Bitu micro); -/* Register a function to be called once after x microseconds */ -TIMER_Block * TIMER_RegisterDelayHandler(TIMER_DelayHandler handler,Bitu delay); /* Set the microseconds value to a new value */ void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro); - -/* This function should be called very often to support very high res timers - Although with the new timer code it doesn't matter that much */ -void TIMER_CheckPIT(void); -/* This will add ms ticks to support the timer handlers */ -void TIMER_AddTicks(Bit32u ticks); +/* This will add 1 milliscond to all timers */ +void TIMER_AddTick(void); #endif diff --git a/include/video.h b/include/video.h index f59d8ec..d642412 100644 --- a/include/video.h +++ b/include/video.h @@ -20,9 +20,7 @@ #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); +typedef void (* GFX_ModeCallBack)(Bitu width,Bitu height,Bitu bpp,Bitu pitch,Bitu flags); struct GFX_PalEntry { Bit8u r; @@ -31,20 +29,25 @@ struct GFX_PalEntry { Bit8u unused; }; -struct GFX_Info { - Bitu width,height,bpp,pitch; -}; +#define GFX_FIXED_BPP 0x01 +#define GFX_RESIZEABLE 0x02 -extern GFX_Info gfx_info; +#define MODE_SET 0x01 +#define MODE_FULLSCREEN 0x02 +#define MODE_RESIZE 0x04 void GFX_Events(void); void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries); -void GFX_SetDrawHandler(GFX_DrawHandler * handler); -void GFX_Resize(Bitu width,Bitu height,Bitu bpp,GFX_ResizeHandler * resize); + +Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue); +void GFX_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu flags,GFX_ModeCallBack callback); void GFX_Start(void); void GFX_Stop(void); void GFX_SwitchFullScreen(void); +void * GFX_StartUpdate(void); +void GFX_EndUpdate(void); + #endif diff --git a/settings.h b/settings.h index 81f3ec2..f0580eb 100644 --- a/settings.h +++ b/settings.h @@ -17,18 +17,15 @@ */ #ifndef _SETTINGS_H_ -#define _SETTINSG_H_ +#define _SETTINGS_H_ -/* Enable the debugger, this only seems to work in win32 for now. */ +/* Enable the debugger, under linux/freebsd dosbox must be started in an xterm under X */ #define C_DEBUG 0 #define C_HEAVY_DEBUG 0 /* Enable the logging of extra information for debugging to the console */ #define C_LOGGING 0 -/* Use multi threading to speed up things on multi cpu's, also gives a nice frame-skipping effect :) */ -#define C_THREADED 1 - /* Enable some big compile-time increasing inlines, great for speed though */ #define C_EXTRAINLINE 0 @@ -38,12 +35,6 @@ /* Maximum memory range in megabytes */ #define C_MEM_MAX_SIZE 12 -/* Maximum memory available for xms, should be lower than maxsize-1 */ -#define C_MEM_XMS_SIZE 8 - -/* Maximum memory available for ems, should be lower than 32 */ -#define C_MEM_EMS_SIZE 4 - /* Enable debug messages for several modules, requires C_LOGGING */ #define DEBUG_SBLASTER 0 /* SoundBlaster Debugging*/ #define DEBUG_DMA 0 /* DMA Debugging */ diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index e583dc0..7d5efa5 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -23,7 +23,7 @@ #include "callback.h" #include "mem.h" #include "cpu.h" - +#include "pic.h" /* CallBack are located at 0xC800:0 And they are 16 bytes each and you can define them to behave in certain ways like a @@ -52,6 +52,8 @@ Bitu CALLBACK_Allocate(void) { void CALLBACK_Idle(void) { /* this makes the cpu execute instructions to handle irq's and then come back */ + bool oldintf=flags.intf; + flags.intf=true; Bit16u oldcs=SegValue(cs); Bit32u oldeip=reg_eip; SegSet16(cs,CB_SEG); @@ -59,10 +61,13 @@ void CALLBACK_Idle(void) { DOSBOX_RunMachine(); reg_eip=oldeip; SegSet16(cs,oldcs); + flags.intf=oldintf; + if (CPU_CycleLeft<300) CPU_CycleLeft=1; + else CPU_CycleLeft-=300; } static Bitu default_handler(void) { - LOG_WARN("Illegal Unhandled Interrupt Called %d",lastint); + LOG_WARN("Illegal Unhandled Interrupt Called %X",lastint); return CBRET_NONE; }; @@ -116,17 +121,25 @@ bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type) { if (callback>=CB_MAX) return false; switch (type) { case CB_RETF: - real_writeb((Bit16u)CB_SEG,(callback<<4),(Bit8u)0xFE); //GRP 4 + real_writeb((Bit16u)CB_SEG,(callback<<4)+0,(Bit8u)0xFE); //GRP 4 real_writeb((Bit16u)CB_SEG,(callback<<4)+1,(Bit8u)0x38); //Extra Callback instruction real_writew((Bit16u)CB_SEG,(callback<<4)+2,callback); //The immediate word real_writeb((Bit16u)CB_SEG,(callback<<4)+4,(Bit8u)0xCB); //A RETF Instruction break; case CB_IRET: - real_writeb((Bit16u)CB_SEG,(callback<<4),(Bit8u)0xFE); //GRP 4 + real_writeb((Bit16u)CB_SEG,(callback<<4)+0,(Bit8u)0xFE); //GRP 4 real_writeb((Bit16u)CB_SEG,(callback<<4)+1,(Bit8u)0x38); //Extra Callback instruction real_writew((Bit16u)CB_SEG,(callback<<4)+2,callback); //The immediate word real_writeb((Bit16u)CB_SEG,(callback<<4)+4,(Bit8u)0xCF); //An IRET Instruction break; + case CB_IRET_STI: + real_writeb((Bit16u)CB_SEG,(callback<<4)+0,(Bit8u)0xFB); //STI + real_writeb((Bit16u)CB_SEG,(callback<<4)+1,(Bit8u)0xFE); //GRP 4 + real_writeb((Bit16u)CB_SEG,(callback<<4)+2,(Bit8u)0x38); //Extra Callback instruction + real_writew((Bit16u)CB_SEG,(callback<<4)+3,callback); //The immediate word + real_writeb((Bit16u)CB_SEG,(callback<<4)+5,(Bit8u)0xCF); //An IRET Instruction + break; + default: E_Exit("CALLBACK:Setup:Illegal type %d",type); diff --git a/src/cpu/core_16/instructions.h b/src/cpu/core_16/instructions.h index 8bd1901..b43405d 100644 --- a/src/cpu/core_16/instructions.h +++ b/src/cpu/core_16/instructions.h @@ -375,10 +375,10 @@ flags.cf=get_CF();flags.type=t_RCLd; \ flags.var2.b=op2;flags.var1.d=load(op1); \ if (flags.var2.b==1) { \ - flags.result.d=flags.var1.d << 1 | flags.cf; \ + flags.result.d=(flags.var1.d << 1) | flags.cf; \ } else { \ flags.result.d=(flags.var1.d << flags.var2.b) | \ - (flags.cf << (flags.var2.b-1)) | \ + (flags.cf << (flags.var2.b-1)) | \ (flags.var1.d >> (33-flags.var2.b)); \ } \ flags.cf=((flags.var1.d >> (32-flags.var2.b)) & 1); \ diff --git a/src/cpu/core_16/main.h b/src/cpu/core_16/main.h index 1495e42..4926826 100644 --- a/src/cpu/core_16/main.h +++ b/src/cpu/core_16/main.h @@ -66,7 +66,8 @@ restart: case 0x16: /* PUSH SS */ Push_16(SegValue(ss));break; case 0x17: /* POP SS */ - SegSet16(ss,Pop_16());break; + SegSet16(ss,Pop_16()); + goto restart; case 0x18: /* SBB Eb,Gb */ RMEbGb(SBBB);break; case 0x19: /* SBB Ew,Gw */ @@ -292,7 +293,16 @@ restart: #include "prefix_66.h" break; case 0x67: /* Address Size Prefix */ +#ifdef CPU_PREFIX_67 + prefix.mark|=PREFIX_ADDR; +#ifdef CPU_PREFIX_COUNT + prefix.count++; +#endif + lookupEATable=EAPrefixTable[prefix.mark]; + goto restart; +#else NOTDONE; +#endif break; #endif case 0x68: /* PUSH Iw */ @@ -538,7 +548,7 @@ restart: case 0x28: /* MOV Ew,GS */ val=SegValue(gs);break; default: - val=0; + val=0; E_Exit("CPU:8c:Illegal RM Byte"); } if (rm >= 0xc0 ) {GetEArw;*earw=val;} @@ -566,7 +576,9 @@ restart: E_Exit("CPU:Illegal MOV CS Call"); break; case 0x10: /* MOV SS,Ew */ - SegSet16(ss,val);break; + SegSet16(ss,val); + goto restart; + break; case 0x18: /* MOV DS,Ew */ SegSet16(ds,val);break; case 0x20: /* MOV FS,Ew */ @@ -654,26 +666,22 @@ restart: } case 0xa0: /* MOV AL,Ob */ { - GetEADirect; - reg_al=LoadMb(eaa); + reg_al=LoadMb(GetEADirect[prefix.mark]()); } break; case 0xa1: /* MOV AX,Ow */ { - GetEADirect; - reg_ax=LoadMw(eaa); + reg_ax=LoadMw(GetEADirect[prefix.mark]()); } break; case 0xa2: /* MOV Ob,AL */ { - GetEADirect; - SaveMb(eaa,reg_al); + SaveMb(GetEADirect[prefix.mark](),reg_al); } break; case 0xa3: /* MOV Ow,AX */ { - GetEADirect; - SaveMw(eaa,reg_ax); + SaveMw(GetEADirect[prefix.mark](),reg_ax); } break; case 0xa4: /* MOVSB */ @@ -856,10 +864,15 @@ restart: } break; case 0xcc: /* INT3 */ +#if C_DEBUG + SAVEIP; + if (DEBUG_Breakpoint()) { + LOADIP; + return 1; + } + LOADIP; +#endif INTERRUPT(3); -#if C_DEBUG - return 1; -#endif break; case 0xcd: /* INT Ib */ { @@ -948,6 +961,7 @@ restart: case 0xde: /* FPU ESC 6 */ case 0xdf: /* FPU ESC 7 */ { + LOG_WARN("FPU used"); Bit8u rm=Fetchb(); if (rm<0xc0) GetEAa; } @@ -966,9 +980,15 @@ restart: else ADDIPFAST(1); break; case 0xe3: /* JCXZ */ - if (!reg_cx) ADDIPFAST(Fetchbs()); - else ADDIPFAST(1); - break; + { + Bitu test; + if (prefix.mark & PREFIX_ADDR) { + test=reg_ecx;PrefixReset; + } else test=reg_cx; + if (!test) ADDIPFAST(Fetchbs()); + else ADDIPFAST(1); + break; + } case 0xe4: /* IN AL,Ib */ { Bit16u port=Fetchb();reg_al=IO_Read(port);} break; @@ -1024,11 +1044,11 @@ restart: E_Exit("CPU:F1:Not Handled"); break; case 0xf2: /* REPNZ */ - count-=Repeat_Normal(false,false,count); - break; + Repeat_Normal(false,false); + continue; case 0xf3: /* REPZ */ - count-=Repeat_Normal(true,false,count); - break; + Repeat_Normal(true,false); + continue; case 0xf4: /* HLT */ break; case 0xf5: /* CMC */ @@ -1318,6 +1338,5 @@ restart: default: NOTDONE; break; - } - + diff --git a/src/cpu/core_16/prefix_66.h b/src/cpu/core_16/prefix_66.h index 33c2aa5..340be2d 100644 --- a/src/cpu/core_16/prefix_66.h +++ b/src/cpu/core_16/prefix_66.h @@ -149,12 +149,23 @@ switch(Fetchb()) { reg_edi=Pop_32();reg_edi=Pop_32();reg_ebp=Pop_32();Pop_32();//Don't save ESP reg_ebx=Pop_32();reg_edx=Pop_32();reg_ecx=Pop_32();reg_eax=Pop_32(); 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 0x67: /* Address Size Prefix */ +#ifdef CPU_PREFIX_67 + prefix.mark|=PREFIX_ADDR; +#ifdef CPU_PREFIX_COUNT + prefix.count++; +#endif + lookupEATable=EAPrefixTable[prefix.mark]; + goto restart_66; +#else + NOTDONE; +#endif + case 0x68: /* PUSH Id */ + Push_32(Fetchd());break; case 0x69: /* IMUL Gd,Ed,Id */ { GetRMrd; @@ -267,6 +278,15 @@ switch(Fetchb()) { case 0x8c: LOG_WARN("CPU:66:8c looped back"); break; + case 0x8d: /* LEA */ + { + prefix.segbase=0; + prefix.mark|=PREFIX_SEG; + lookupEATable=EAPrefixTable[prefix.mark]; + GetRMrd;GetEAa; + *rmrd=(Bit32u)eaa; + break; + } case 0x8f: /* POP Ed */ { GetRM; @@ -276,25 +296,25 @@ switch(Fetchb()) { } case 0x90: /* NOP */ break; - case 0x91: /* XCHG CX,AX */ + case 0x91: /* XCHG ECX,EAX */ { Bit32u temp=reg_eax;reg_eax=reg_ecx;reg_ecx=temp; } break; - case 0x92: /* XCHG DX,AX */ + case 0x92: /* XCHG EDX,EAX */ { Bit32u temp=reg_eax;reg_eax=reg_edx;reg_edx=temp; } break; - case 0x93: /* XCHG BX,AX */ + case 0x93: /* XCHG EBX,EAX */ { Bit32u temp=reg_eax;reg_eax=reg_ebx;reg_ebx=temp; } break; - case 0x94: /* XCHG SP,AX */ + case 0x94: /* XCHG ESP,EAX */ { Bit32u temp=reg_eax;reg_eax=reg_esp;reg_esp=temp; } break; - case 0x95: /* XCHG BP,AX */ + case 0x95: /* XCHG EBP,EAX */ { Bit32u temp=reg_eax;reg_eax=reg_ebp;reg_ebp=temp; } break; - case 0x96: /* XCHG SI,AX */ + case 0x96: /* XCHG ESI,EAX */ { Bit32u temp=reg_eax;reg_eax=reg_esi;reg_esi=temp; } break; - case 0x97: /* XCHG DI,AX */ + case 0x97: /* XCHG EDI,EAX */ { Bit32u temp=reg_eax;reg_eax=reg_edi;reg_edi=temp; } break; case 0x98: /* CWD */ @@ -321,14 +341,12 @@ switch(Fetchb()) { } case 0xa1: /* MOV EAX,Ow */ { - GetEADirect; - reg_eax=LoadMd(eaa); + reg_eax=LoadMd(GetEADirect[prefix.mark]()); } break; case 0xa3: /* MOV Ow,EAX */ { - GetEADirect; - SaveMd(eaa,reg_eax); + SaveMd(GetEADirect[prefix.mark](),reg_eax); } break; case 0xa5: /* MOVSD */ @@ -383,6 +401,18 @@ switch(Fetchb()) { reg_edi=Fetchd();break; case 0xc1: /* GRP2 Ed,Ib */ GRP2D(Fetchb());break; + case 0xc4: /* LES */ + { + GetRMrd;GetEAa; + *rmrd=LoadMd(eaa);SegSet16(es,LoadMw(eaa+4)); + break; + } + case 0xc5: /* LDS */ + { + GetRMrd;GetEAa; + *rmrd=LoadMd(eaa);SegSet16(ds,LoadMw(eaa+4)); + break; + } case 0xc7: /* MOV Ed,Id */ { GetRM; @@ -396,12 +426,12 @@ switch(Fetchb()) { GRP2D(reg_cl);break; case 0xf2: /* REPNZ */ prefix.count++; - count-=Repeat_Normal(false,true,count); - break; + Repeat_Normal(false,true); + continue; case 0xf3: /* REPZ */ prefix.count++; - count-=Repeat_Normal(true,true,count); - break; + Repeat_Normal(true,true); + continue; case 0xf7: /* GRP3 Ed(,Id) */ { union { Bit64u u;Bit64s s;} temp; @@ -436,18 +466,18 @@ switch(Fetchb()) { case 0x20: /* MUL EAX,Ed */ { flags.type=t_MUL; - if (rm >= 0xc0 ) {GetEArd;temp.u=(Bit64s)reg_eax * (Bit64u)(*eard);} + if (rm >= 0xc0 ) {GetEArd;temp.u=(Bit64u)reg_eax * (Bit64u)(*eard);} else {GetEAa;temp.u=(Bit64u)reg_eax * (Bit64u)LoadMd(eaa);} - reg_eax=(Bit32u)(temp.u & 0xffffffff);reg_eax=(Bit32u)(temp.u >> 32); + reg_eax=(Bit32u)(temp.u & 0xffffffff);reg_edx=(Bit32u)(temp.u >> 32); flags.cf=flags.of=(reg_edx !=0); break; } case 0x28: /* IMUL EAX,Ed */ { flags.type=t_MUL; - if (rm >= 0xc0 ) {GetEArd;temp.s=(Bit64s)reg_eax * (Bit64s)(*eards);} - else {GetEAa;temp.s=(Bit64s)reg_eax * (Bit64s)LoadMds(eaa);} - reg_eax=Bit32u(temp.u & 0xffffffff);reg_edx=(Bit32u)(temp.u >> 32); + if (rm >= 0xc0 ) {GetEArd;temp.s=((Bit64s)((Bit32s)reg_eax) * (Bit64s)(*eards));} + else {GetEAa;temp.s=((Bit64s)((Bit32s)reg_eax) * (Bit64s)(LoadMds(eaa)));} + reg_eax=Bit32u(temp.s & 0xffffffff);reg_edx=(Bit32u)(temp.s >> 32); if ( (reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) { flags.cf=flags.of=false; } else if ( (reg_edx==0x00000000) && (reg_eax<0x80000000) ) { diff --git a/src/cpu/core_16/prefix_66_of.h b/src/cpu/core_16/prefix_66_of.h index c7b0f81..fa972dc 100644 --- a/src/cpu/core_16/prefix_66_of.h +++ b/src/cpu/core_16/prefix_66_of.h @@ -33,6 +33,14 @@ switch (Fetchb()) { else {GetEAa;DSHRD(eaa,*rmrd,Fetchb(),LoadMd,SaveMd);} break; } + case 0xad: /* SHRD Ed,Gd,Cl */ + { + GetRMrd; + if (rm >= 0xc0 ) {GetEArd;DSHRD(*eard,*rmrd,reg_cl,LoadRd,SaveRd);} + else {GetEAa;DSHRD(eaa,*rmrd,reg_cl,LoadMd,SaveMd);} + break; + } + case 0xb6: /* MOVZX Gd,Eb */ { GetRMrd; @@ -44,8 +52,8 @@ switch (Fetchb()) { { GetRMrd; Bit64s res; - if (rm >= 0xc0 ) {GetEArd;res=(Bit64s)(*rmrd) * (Bit64s)(*eards);} - else {GetEAa;res=(Bit64s)(*rmrd) * (Bit64s)LoadMds(eaa);} + if (rm >= 0xc0 ) {GetEArd;res=((Bit64s)((Bit32s)*rmrd) * (Bit64s)((Bit32s)*eards));} + else {GetEAa;res=((Bit64s)((Bit32s)*rmrd) * (Bit64s)LoadMds(eaa));} *rmrd=(Bit32s)(res); flags.type=t_MUL; if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {flags.cf=false;flags.of=false;} @@ -108,6 +116,56 @@ switch (Fetchb()) { flags.type=t_CF; break; } + case 0xbb: /* BTC Ed,Gd */ + { + GetRMrd; + Bit32u mask=1 << (*rmrd & 31); + if (rm >= 0xc0 ) { + GetEArd; + flags.cf=(*eard & mask)>0; + *eard^=mask; + } else { + GetEAa;Bit32u old=LoadMd(eaa); + flags.cf=(old & mask)>0; + SaveMd(eaa,old ^ mask); + } + if (flags.type!=t_CF) { flags.prev_type=flags.type;flags.type=t_CF; } + break; + } + case 0xbc: /* BSF Gd,Ed */ + { + GetRMrd; + Bit32u result,value; + if (rm >= 0xc0) { GetEArd; value=*eard; } + else { GetEAa; value=LoadMd(eaa); } + if (value==0) { + flags.zf = true; + } else { + result = 0; + while ((value & 0x01)==0) { result++; value>>=1; } + flags.zf = false; + *rmrd = result; + } + flags.type=t_UNKNOWN; + break; + } + case 0xbd: /* BSR Gd,Ed */ + { + GetRMrd; + Bit32u result,value; + if (rm >= 0xc0) { GetEArd; value=*eard; } + else { GetEAa; value=LoadMd(eaa); } + if (value==0) { + flags.zf = true; + } else { + result = 35; // Operandsize-1 + while ((value & 0x80000000)==0) { result--; value<<=1; } + flags.zf = false; + *rmrd = result; + } + flags.type=t_UNKNOWN; + break; + } case 0xbe: /* MOVSX Gd,Eb */ { GetRMrd; diff --git a/src/cpu/core_16/prefix_of.h b/src/cpu/core_16/prefix_of.h index 3e3a4b4..ebac6f2 100644 --- a/src/cpu/core_16/prefix_of.h +++ b/src/cpu/core_16/prefix_of.h @@ -59,6 +59,12 @@ switch(Fetchb()) { /* 0x21 MOV Rd,DRx (386) */ /* 0x22 MOV CRx,Rd (386) */ /* 0x23 MOV DRx,Rd (386) */ + case 0x23: /* MOV DRx,Rd */ + { + GetRM; + LOG_DEBUG("CPU:0F:23 does nothing"); + } + break; /* 0x24 MOV Rd,TRx (386) */ /* 0x26 MOV TRx,Rd (386) */ /* 0x30 WRMSR (P5) */ @@ -251,7 +257,12 @@ switch(Fetchb()) { } /* 0xb0 CMPXCHG Eb,Gb */ /* 0xb1 CMPXCHG Ew,Gw */ - /* 0xb2 LSS */ + case 0xb2: /* LSS */ + { + GetRMrw;GetEAa; + *rmrw=LoadMw(eaa);SegSet16(ss,LoadMw(eaa+2)); + break; + } case 0xb3: /* BTR Ew,Gw */ { GetRMrw; @@ -389,7 +400,6 @@ switch(Fetchb()) { flags.type=t_UNKNOWN; break; } - /* 0xbd BSR Gw,Ew */ case 0xbe: /* MOVSX Gw,Eb */ { GetRMrw; diff --git a/src/cpu/core_16/stop.h b/src/cpu/core_16/stop.h index 297949e..68145d7 100644 --- a/src/cpu/core_16/stop.h +++ b/src/cpu/core_16/stop.h @@ -16,4 +16,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +decode_end: + SAVEIP; diff --git a/src/cpu/core_16/support.h b/src/cpu/core_16/support.h index ace3a10..5f540a0 100644 --- a/src/cpu/core_16/support.h +++ b/src/cpu/core_16/support.h @@ -95,22 +95,26 @@ static INLINE Bit32u Pop_32() { from=SegBase(ds)+reg_si; \ } - #include "helpers.h" #include "table_ea.h" #include "../modrm.h" #include "instructions.h" -static Bits Repeat_Normal(bool testz,bool prefix_66,Bits count_remain) { +static Bit8s table_df_8[2]={1,-1}; +static Bit16s table_df_16[2]={2,-2}; +static Bit32s table_df_32[2]={4,-4}; + + +static void Repeat_Normal(bool testz,bool prefix_66) { - Bits count=count_remain; PhysPt base_si,base_di; Bit16s direct; if (flags.df) direct=-1; else direct=1; base_di=SegBase(es); + if (prefix.mark & PREFIX_ADDR) E_Exit("Unhandled 0x67 prefixed string op"); rep_again: if (prefix.mark & PREFIX_SEG) { base_si=(prefix.segbase); @@ -138,21 +142,32 @@ rep_again: prefix.mark|=PREFIX_SEG; prefix.count++; goto rep_again; + case 0x64: /* FS Prefix */ + prefix.segbase=SegBase(fs); + prefix.mark|=PREFIX_SEG; + prefix.count++; + goto rep_again; + case 0x65: /* GS Prefix */ + prefix.segbase=SegBase(gs); + 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; SaveMb(base_di+reg_di,IO_Read(reg_dx)); reg_di+=direct; } - 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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)); @@ -161,25 +176,26 @@ rep_again: } } else { direct*=2; - for (;(reg_cx && count>0);reg_cx--,count--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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)); @@ -188,161 +204,152 @@ rep_again: } } else { direct*=2; - for (;(reg_cx && count>0);reg_cx--,count--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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);) { + Bit8u op1,op2; + if (!reg_cx) { CPU_Cycles--;goto normalexit; } + for (;CPU_Cycles>0;CPU_Cycles--) { 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; + reg_cx--;reg_si+=direct;reg_di+=direct; + if ((op1==op2)!=testz || !reg_cx) { CMPB(op1,op2,LoadRb,0);goto normalexit; } } 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 (!reg_cx) { CPU_Cycles--;goto normalexit; } if (prefix_66) { - direct*=4; - Bit32u op1,op2; - for (;(reg_cx && count>0);) { + direct*=4;Bit32u op1,op2; + for (;CPU_Cycles>0;CPU_Cycles--) { 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; + reg_cx--;reg_si+=direct;reg_di+=direct; + if ((op1==op2)!=testz || !reg_cx) { CMPD(op1,op2,LoadRd,0);goto normalexit; } } CMPD(op1,op2,LoadRd,0); - if ((op1==op2)!=testz) goto stopit; } else { - direct*=2; - Bit16u op1,op2; - for (;(reg_cx && count>0);) { + direct*=2;Bit16u op1,op2; + for (;CPU_Cycles>0;CPU_Cycles--) { 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; + reg_cx--,reg_si+=direct;reg_di+=direct; + if ((op1==op2)!=testz || !reg_cx) { CMPW(op1,op2,LoadRw,0);goto normalexit; } } 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; SaveMd(base_di+reg_di,reg_eax); reg_di+=direct; } } else { direct*=2; - for (;(reg_cx && count>0);reg_cx--,count--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; reg_eax=LoadMd(base_si+reg_si); reg_si+=direct; } } else { direct*=2; - for (;(reg_cx && count>0);reg_cx--,count--) { + for (;CPU_Cycles>0;CPU_Cycles--) { + if (!reg_cx) goto normalexit; reg_cx--; 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);) { + Bit8u op2; + if (!reg_cx) { CPU_Cycles--;goto normalexit; } + for (;CPU_Cycles>0;CPU_Cycles--) { op2=LoadMb(base_di+reg_di); - reg_cx--,count--;reg_di+=direct; - if ((reg_al==op2)!=testz) break; + reg_cx--;reg_di+=direct; + if ((reg_al==op2)!=testz || !reg_cx) { CMPB(reg_al,op2,LoadRb,0);goto normalexit; } } 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 (!reg_cx) { CPU_Cycles--;goto normalexit; } if (prefix_66) { - direct*=4; - Bit32u op2; - for (;(reg_cx && count>0);) { + direct*=4;Bit32u op2; + for (;CPU_Cycles>0;CPU_Cycles--) { op2=LoadMd(base_di+reg_di); - reg_cx--,count--;reg_di+=direct; - if ((reg_eax==op2)!=testz) break; + reg_cx--;reg_di+=direct; + if ((reg_eax==op2)!=testz || !reg_cx) { CMPD(reg_eax,op2,LoadRd,0);goto normalexit; } } CMPD(reg_eax,op2,LoadRd,0); - if ((reg_eax==op2)!=testz) goto stopit; } else { - direct*=2; - Bit16u op2; - for (;(reg_cx && count>0);) { + direct*=2;Bit16u op2; + for (;CPU_Cycles>0;CPU_Cycles--) { op2=LoadMw(base_di+reg_di); - reg_cx--,count--;reg_di+=direct; - if ((reg_ax==op2)!=testz) break; + reg_cx--;reg_di+=direct; + if ((reg_ax==op2)!=testz || !reg_cx) { CMPW(reg_ax,op2,LoadRw,0);goto normalexit; } } CMPW(reg_ax,op2,LoadRw,0); - if ((reg_ax==op2)!=testz) goto stopit; } - if (reg_cx && count<=0) goto countzero; } break; default: @@ -350,13 +357,10 @@ rep_again: LOG_DEBUG("Unhandled REP Prefix %X",Fetchb()); } -stopit: - PrefixReset; - return count_remain-count; -countzero: + /* If we end up here it's because the CPU_Cycles counter is 0, so restart instruction */ IPPoint-=(prefix.count+2); /* Rep instruction and whatever string instruction */ +normalexit: PrefixReset; - return count_remain; } //flags.io and nt shouldn't be compiled for 386 @@ -376,7 +380,10 @@ countzero: PIC_runIRQs(); \ LOADIP; \ } \ - if (flags.tf) LOG_DEBUG("CPU:Trap Flag not supported"); \ + if (flags.tf) { \ + cpudecoder=&CPU_Real_16_Slow_Decode_Trap; \ + goto decode_end; \ + } \ } #else @@ -394,7 +401,10 @@ countzero: PIC_runIRQs(); \ LOADIP; \ } \ - if (flags.tf) LOG_DEBUG("CPU:Trap Flag not supported"); \ + if (flags.tf) { \ + cpudecoder=&CPU_Real_16_Slow_Decode_Trap; \ + goto decode_end; \ + } \ } #endif diff --git a/src/cpu/core_16/table_ea.h b/src/cpu/core_16/table_ea.h index 48fd12a..d702fe1 100644 --- a/src/cpu/core_16/table_ea.h +++ b/src/cpu/core_16/table_ea.h @@ -19,6 +19,8 @@ /* Some variables for EA Loolkup */ typedef EAPoint (*GetEATable[256])(void); +typedef EAPoint (*EA_LookupHandler)(void); + static GetEATable * lookupEATable; #define PREFIX_NONE 0x0 @@ -35,6 +37,7 @@ static struct { /* Gets initialized at the bottem, can't seem to declare forward references */ static GetEATable * EAPrefixTable[4]; + #define SegPrefix(blah) \ prefix.segbase=SegBase(blah); \ prefix.mark|=PREFIX_SEG; \ @@ -55,29 +58,6 @@ static GetEATable * EAPrefixTable[4]; prefix.count=0; \ lookupEATable=EAPrefixTable[PREFIX_NONE]; -#if 1 - -#define GetEADirect \ -EAPoint eaa;switch (prefix.mark) { \ -case PREFIX_NONE:eaa=SegBase(ds)+Fetchw();break; \ -case PREFIX_SEG:eaa=prefix.segbase+Fetchw();PrefixReset;break; \ -case PREFIX_ADDR:eaa=SegBase(ds)+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 - - - /* The MOD/RM Decoder for EA for this decoder's addressing modes */ static EAPoint EA_16_00_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_si); } @@ -240,32 +220,32 @@ INLINE EAPoint Sib(Bitu mode) { }; -static EAPoint EA_32_00_n(void) { return SegBase(ds)+reg_eax; } -static EAPoint EA_32_01_n(void) { return SegBase(ds)+reg_ecx; } -static EAPoint EA_32_02_n(void) { return SegBase(ds)+reg_edx; } -static EAPoint EA_32_03_n(void) { return SegBase(ds)+reg_ebx; } -static EAPoint EA_32_04_n(void) { return Sib(0);} -static EAPoint EA_32_05_n(void) { return SegBase(ds)+Fetchd(); } -static EAPoint EA_32_06_n(void) { return SegBase(ss)+reg_esi; } -static EAPoint EA_32_07_n(void) { return SegBase(ds)+reg_edi; } +static EAPoint EA_32_00_n(void) { PrefixReset;return SegBase(ds)+reg_eax; } +static EAPoint EA_32_01_n(void) { PrefixReset;return SegBase(ds)+reg_ecx; } +static EAPoint EA_32_02_n(void) { PrefixReset;return SegBase(ds)+reg_edx; } +static EAPoint EA_32_03_n(void) { PrefixReset;return SegBase(ds)+reg_ebx; } +static EAPoint EA_32_04_n(void) { PrefixReset;return Sib(0);} +static EAPoint EA_32_05_n(void) { PrefixReset;return SegBase(ds)+Fetchd(); } +static EAPoint EA_32_06_n(void) { PrefixReset;return SegBase(ds)+reg_esi; } +static EAPoint EA_32_07_n(void) { PrefixReset;return SegBase(ds)+reg_edi; } -static EAPoint EA_32_40_n(void) { return SegBase(ds)+reg_eax+Fetchbs(); } -static EAPoint EA_32_41_n(void) { return SegBase(ds)+reg_ecx+Fetchbs(); } -static EAPoint EA_32_42_n(void) { return SegBase(ds)+reg_edx+Fetchbs(); } -static EAPoint EA_32_43_n(void) { return SegBase(ds)+reg_ebx+Fetchbs(); } -static EAPoint EA_32_44_n(void) { return Sib(1)+Fetchbs();} -static EAPoint EA_32_45_n(void) { return SegBase(ss)+reg_ebp+Fetchbs(); } -static EAPoint EA_32_46_n(void) { return SegBase(ds)+reg_esi+Fetchbs(); } -static EAPoint EA_32_47_n(void) { return SegBase(ds)+reg_edi+Fetchbs(); } +static EAPoint EA_32_40_n(void) { PrefixReset;return SegBase(ds)+reg_eax+Fetchbs(); } +static EAPoint EA_32_41_n(void) { PrefixReset;return SegBase(ds)+reg_ecx+Fetchbs(); } +static EAPoint EA_32_42_n(void) { PrefixReset;return SegBase(ds)+reg_edx+Fetchbs(); } +static EAPoint EA_32_43_n(void) { PrefixReset;return SegBase(ds)+reg_ebx+Fetchbs(); } +static EAPoint EA_32_44_n(void) { PrefixReset;return Sib(1)+Fetchbs();} +static EAPoint EA_32_45_n(void) { PrefixReset;return SegBase(ss)+reg_ebp+Fetchbs(); } +static EAPoint EA_32_46_n(void) { PrefixReset;return SegBase(ds)+reg_esi+Fetchbs(); } +static EAPoint EA_32_47_n(void) { PrefixReset;return SegBase(ds)+reg_edi+Fetchbs(); } -static EAPoint EA_32_80_n(void) { return SegBase(ds)+reg_eax+Fetchds(); } -static EAPoint EA_32_81_n(void) { return SegBase(ds)+reg_ecx+Fetchds(); } -static EAPoint EA_32_82_n(void) { return SegBase(ds)+reg_edx+Fetchds(); } -static EAPoint EA_32_83_n(void) { return SegBase(ds)+reg_ebx+Fetchds(); } -static EAPoint EA_32_84_n(void) { return Sib(2)+Fetchds();} -static EAPoint EA_32_85_n(void) { return SegBase(ss)+reg_ebp+Fetchds(); } -static EAPoint EA_32_86_n(void) { return SegBase(ds)+reg_esi+Fetchds(); } -static EAPoint EA_32_87_n(void) { return SegBase(ds)+reg_edi+Fetchds(); } +static EAPoint EA_32_80_n(void) { PrefixReset;return SegBase(ds)+reg_eax+Fetchds(); } +static EAPoint EA_32_81_n(void) { PrefixReset;return SegBase(ds)+reg_ecx+Fetchds(); } +static EAPoint EA_32_82_n(void) { PrefixReset;return SegBase(ds)+reg_edx+Fetchds(); } +static EAPoint EA_32_83_n(void) { PrefixReset;return SegBase(ds)+reg_ebx+Fetchds(); } +static EAPoint EA_32_84_n(void) { PrefixReset;return Sib(2)+Fetchds();} +static EAPoint EA_32_85_n(void) { PrefixReset;return SegBase(ss)+reg_ebp+Fetchds(); } +static EAPoint EA_32_86_n(void) { PrefixReset;return SegBase(ds)+reg_esi+Fetchds(); } +static EAPoint EA_32_87_n(void) { PrefixReset;return SegBase(ds)+reg_edi+Fetchds(); } static GetEATable GetEA_32_n={ /* 00 */ @@ -327,7 +307,8 @@ INLINE EAPoint Sib_s(Bitu mode) { case 7: /* EDI Base */ base=prefix.segbase+reg_edi;break; } - base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); PrefixReset; + base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); + PrefixReset; return base; }; @@ -346,7 +327,7 @@ static EAPoint EA_32_40_s(void) { segprefixed_32(reg_eax+Fetchbs()); } static EAPoint EA_32_41_s(void) { segprefixed_32(reg_ecx+Fetchbs()); } static EAPoint EA_32_42_s(void) { segprefixed_32(reg_edx+Fetchbs()); } static EAPoint EA_32_43_s(void) { segprefixed_32(reg_ebx+Fetchbs()); } -static EAPoint EA_32_44_s(void) { return Sib(1)+Fetchbs();} +static EAPoint EA_32_44_s(void) { return Sib_s(1)+Fetchbs();} static EAPoint EA_32_45_s(void) { segprefixed_32(reg_ebp+Fetchbs()); } static EAPoint EA_32_46_s(void) { segprefixed_32(reg_esi+Fetchbs()); } static EAPoint EA_32_47_s(void) { segprefixed_32(reg_edi+Fetchbs()); } @@ -355,7 +336,7 @@ static EAPoint EA_32_80_s(void) { segprefixed_32(reg_eax+Fetchds()); } static EAPoint EA_32_81_s(void) { segprefixed_32(reg_ecx+Fetchds()); } static EAPoint EA_32_82_s(void) { segprefixed_32(reg_edx+Fetchds()); } static EAPoint EA_32_83_s(void) { segprefixed_32(reg_ebx+Fetchds()); } -static EAPoint EA_32_84_s(void) { return Sib(2)+Fetchds();} +static EAPoint EA_32_84_s(void) { return Sib_s(2)+Fetchds();} static EAPoint EA_32_85_s(void) { segprefixed_32(reg_ebp+Fetchds()); } static EAPoint EA_32_86_s(void) { segprefixed_32(reg_esi+Fetchds()); } static EAPoint EA_32_87_s(void) { segprefixed_32(reg_edi+Fetchds()); } @@ -396,4 +377,21 @@ static GetEATable GetEA_32_s={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static EAPoint GetEADirect_NONE(void) { + EAPoint result=SegBase(ds)+Fetchw(); + return result; +} +static EAPoint GetEADirect_SEG(void) { + EAPoint result=prefix.segbase+Fetchw();PrefixReset; + return result; +} +static EAPoint GetEADirect_ADDR(void) { + EAPoint result=SegBase(ds)+Fetchd();PrefixReset; + return result; +} +static EAPoint GetEADirect_SEG_ADDR(void) { + EAPoint result=prefix.segbase+Fetchd();PrefixReset; + return result; +} +static EA_LookupHandler GetEADirect[4]={GetEADirect_NONE,GetEADirect_SEG,GetEADirect_ADDR,GetEADirect_SEG_ADDR}; diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 51090e1..18f2a31 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -30,21 +30,24 @@ Flag_Info flags; CPU_Regs cpu_regs; Segment Segs[6]; -Bitu cpu_cycles; + +Bits CPU_Cycles=0; +Bits CPU_CycleLeft=0; +Bits CPU_CycleMax=1500; CPU_Decoder * cpudecoder; static void CPU_CycleIncrease(void) { - 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); + Bitu old_cycles=CPU_CycleMax; + CPU_CycleMax=(Bitu)(CPU_CycleMax*1.2); + if (CPU_CycleMax==old_cycles) CPU_CycleMax++; + LOG_MSG("CPU:%d cycles",CPU_CycleMax); } static void CPU_CycleDecrease(void) { - cpu_cycles=(Bitu)(cpu_cycles/1.2); - if (!cpu_cycles) cpu_cycles=1; - LOG_MSG("CPU:%d cycles",cpu_cycles); + CPU_CycleMax=(Bitu)(CPU_CycleMax/1.2); + if (!CPU_CycleMax) CPU_CycleMax=1; + LOG_MSG("CPU:%d cycles",CPU_CycleMax); } Bit8u lastint; @@ -67,10 +70,10 @@ void Interrupt(Bit8u num) { case 0x11: case 0x12: case 0x13: - case 0x16: case 0x15: - case 0x1A: + case 0x16: case 0x17: + case 0x1A: case 0x1C: case 0x21: case 0x2a: @@ -80,6 +83,10 @@ void Interrupt(Bit8u num) { case 0x74: break; case 0xcd: +#if C_HEAVY_DEBUG + LOG_DEBUG("Call to interrupt 0xCD this is BAD"); + DEBUG_HeavyWriteLogInstruction(); +#endif E_Exit("Call to interrupt 0xCD this is BAD"); case 0x03: #if C_DEBUG @@ -163,13 +170,15 @@ void CPU_Init(Section* sec) { flags.io=0; SetCPU16bit(); - 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"); + CPU_Cycles=0; + CPU_CycleMax=section->Get_int("cycles");; + if (!CPU_CycleMax) CPU_CycleMax=1500; + CPU_CycleLeft=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/flags.cpp b/src/cpu/flags.cpp index 02d4169..6e78c3e 100644 --- a/src/cpu/flags.cpp +++ b/src/cpu/flags.cpp @@ -46,7 +46,6 @@ bool get_CF(void) { case t_RCLd: return flags.cf; break; - case t_ADDb: return (flags.result.b=0x80000000); case t_DIV: case t_MUL: - return false; + return false; /* Unkown */ default: - E_Exit("get_SF Unkown %d",flags.type); + LOG_WARN("get_SF Unkown %d",flags.type); } return false; @@ -419,6 +416,9 @@ again: case t_RCLb: case t_RCLw: case t_RCLd: + case t_SARb: + case t_SARw: + case t_SARd: return flags.of; case t_CF: type=flags.prev_type; @@ -523,9 +523,6 @@ again: return (flags.result.w >= 0x4000); case t_SHRd: return (flags.result.d >= 0x40000000); - case t_SARb: - case t_SARw: - case t_SARd: case t_ORb: case t_ORw: case t_ORd: @@ -538,10 +535,11 @@ again: case t_TESTb: case t_TESTw: case t_TESTd: + return false; /* Return false */ case t_DIV: - return false; + return false; /* Unkown */ default: - E_Exit("get_OF Unkown %d",flags.type); + LOG_WARN("get_OF Unkown %d",flags.type); } return false; } diff --git a/src/cpu/slow_16.cpp b/src/cpu/slow_16.cpp index 0bf3d76..40146a3 100644 --- a/src/cpu/slow_16.cpp +++ b/src/cpu/slow_16.cpp @@ -55,49 +55,55 @@ extern Bitu cycle_count; /* Enable parts of the cpu emulation */ #define CPU_386 //Enable 386 instructions +#define CPU_PREFIX_67 //Enable the 0x67 prefix +#define CPU_PREFIX_COUNT //Enable counting of prefixes + #if C_FPU #define CPU_FPU //Enable FPU escape instructions #endif -#include "core_16/support.h" -static Bitu CPU_Real_16_Slow_Decode_Special(Bitu count); -static Bitu CPU_Real_16_Slow_Decode(Bits count) { +#include "core_16/support.h" +static Bitu CPU_Real_16_Slow_Decode_Trap(void); + +static Bitu CPU_Real_16_Slow_Decode(void) { #include "core_16/start.h" - do { + while (CPU_Cycles>0) { #if C_DEBUG cycle_count++; #endif #if C_HEAVY_DEBUG SAVEIP; - if (DEBUG_HeavyIsBreakpoint()) return CBRET_NONE; + if (DEBUG_HeavyIsBreakpoint()) return 1; #endif - #include "core_16/main.h" - } while (--count>0); + #include "core_16/main.h" + if (prefix.count) { + PrefixReset; + //DEBUG_HeavyWriteLogInstruction(); + LOG_DEBUG("Prefix for non prefixed instruction"); + } + CPU_Cycles--; + } #include "core_16/stop.h" return CBRET_NONE; } -static Bitu CPU_Real_16_Slow_Decode_Special(Bits count) { - while (count>0) { - if (flags.tf) { - Interrupt(3); - cpudecoder=&CPU_Real_16_Slow_Decode; - return CBRET_NONE; - } - CPU_Real_16_Slow_Decode(1); - if (!flags.tf) { - cpudecoder=&CPU_Real_16_Slow_Decode; - return CBRET_NONE; - }; - count--; - } +static Bitu CPU_Real_16_Slow_Decode_Trap(void) { + + Bits oldCycles = CPU_Cycles; + CPU_Cycles = 1; + CPU_Real_16_Slow_Decode(); + +// LOG_DEBUG("TRAP: Trap Flag executed"); + INTERRUPT(1); + + CPU_Cycles = oldCycles-1; + cpudecoder = &CPU_Real_16_Slow_Decode; return CBRET_NONE; } void CPU_Real_16_Slow_Start(void) { - cpudecoder=&CPU_Real_16_Slow_Decode; EAPrefixTable[0]=&GetEA_16_n; EAPrefixTable[1]=&GetEA_16_s; diff --git a/src/debug/debug.cpp b/src/debug/debug.cpp index 29c0dbe..3c3d1bd 100644 --- a/src/debug/debug.cpp +++ b/src/debug/debug.cpp @@ -34,7 +34,7 @@ #include "mixer.h" #include "debug_inc.h" #include "timer.h" -#include "..\shell\shell_inc.h" +#include "../shell/shell_inc.h" #ifdef WIN32 void WIN32_Console(); @@ -48,6 +48,7 @@ class DEBUG; DEBUG* pDebugcom = 0; bool exitLoop = false; +bool logHeavy = false; static struct { Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip; @@ -91,7 +92,7 @@ static Bit16u dataSeg,dataOfs; bool skipFirstInstruction = false; -enum EBreakpoint { BKPNT_UNKNOWN, BKPNT_PHYSICAL, BKPNT_INTERRUPT }; +enum EBreakpoint { BKPNT_UNKNOWN, BKPNT_PHYSICAL, BKPNT_INTERRUPT, BKPNT_MEMORY }; #define BPINT_ALL 0x100 @@ -104,21 +105,24 @@ public: 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; }; - + void SetType (EBreakpoint _type) { type = _type; }; + void SetValue (Bit8u value) { ahValue = value; }; + 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; }; + PhysPt GetLocation (void) { if (GetType()!=BKPNT_INTERRUPT) 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; }; + Bit8u GetIntNr (void) { if (GetType()==BKPNT_INTERRUPT) return intNr; else return 0; }; + Bit16u GetValue (void) { if (GetType()!=BKPNT_PHYSICAL) 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 CBreakpoint* AddMemBreakpoint (Bit16u seg, Bit32u off); static void ActivateBreakpoints (PhysPt adr, bool activate); static bool CheckBreakpoint (PhysPt adr); static bool CheckIntBreakpoint (PhysPt adr, Bit8u intNr, Bit16u ahValue); @@ -145,6 +149,7 @@ private: bool once; static std::list BPoints; +public: static CBreakpoint* ignoreOnce; }; @@ -192,9 +197,18 @@ CBreakpoint* CBreakpoint::AddIntBreakpoint(Bit8u intNum, Bit16u ah, bool once) return bp; }; +CBreakpoint* CBreakpoint::AddMemBreakpoint(Bit16u seg, Bit32u off) +{ + CBreakpoint* bp = new CBreakpoint(); + bp->SetAddress (seg,off); + bp->SetOnce (false); + bp->SetType (BKPNT_MEMORY); + BPoints.push_front (bp); + return bp; +}; + void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate) { - ignoreOnce = 0; // activate all breakpoints std::list::iterator i; CBreakpoint* bp; @@ -202,7 +216,7 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate) bp = static_cast(*i); // Do not activate, when bp is an actual adress if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { - ignoreOnce = bp; + // Do not activate :) continue; } bp->Activate(activate); @@ -212,26 +226,45 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool 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)) { + // Ignore Once ? + if (ignoreOnce==bp) { + ignoreOnce=0; + bp->Activate(true); + return false; + }; // Found, if (bp->GetOnce()) { // delete it, if it should only be used once (BPoints.erase)(i); bp->Activate(false); delete bp; - } + } else { + ignoreOnce = bp; + }; return true; + } +#if C_HEAVY_DEBUG + // Memory breakpoint support + else if ((bp->GetType()==BKPNT_MEMORY) && bp->IsActive()) { + + Bit8u value = mem_readb(bp->GetLocation()); + if (bp->GetValue() != value) { + // Yup, memory value changed + char buffer[200]; + sprintf(buffer,"DEBUG: Memory breakpoint: %04X:%04X - %02X -> %02X",bp->GetSegment(),bp->GetOffset(),bp->GetValue(),value); + LOG_DEBUG(buffer); + bp->SetValue(value); + return true; + }; + }; +#endif }; return false; }; @@ -239,11 +272,6 @@ bool CBreakpoint::CheckBreakpoint(PhysPt adr) 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; @@ -251,13 +279,21 @@ bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue) bp = static_cast(*i); if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) { if ((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) { + // Ignoie it once ? + if (ignoreOnce==bp) { + ignoreOnce=0; + bp->Activate(true); + return false; + }; // Found if (bp->GetOnce()) { // delete it, if it should only be used once (BPoints.erase)(i); bp->Activate(false); delete bp; - } + } else { + ignoreOnce = bp; + } return true; } }; @@ -292,6 +328,7 @@ bool CBreakpoint::DeleteByIndex(Bit16u index) delete bp; return true; } + nr++; }; return false; }; @@ -353,14 +390,15 @@ void CBreakpoint::ShowList(void) 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); + 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++; + } else if (bp->GetType()==BKPNT_MEMORY) { + wprintw(dbg.win_out,"%02X. BPMEM %04X:%04X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue()); + nr++; }; } wrefresh(dbg.win_out); @@ -591,6 +629,47 @@ Bit32u GetHexValue(char* str, char*& hex) return value; }; +bool ChangeRegister(char* str) +{ + Bit32u value = 0; + + char* hex = str; + while (*hex==' ') hex++; + if (strstr(hex,"AX")==hex) { hex+=2; reg_ax = GetHexValue(hex,hex); } else + if (strstr(hex,"BX")==hex) { hex+=2; reg_bx = GetHexValue(hex,hex); } else + if (strstr(hex,"CX")==hex) { hex+=2; reg_cx = GetHexValue(hex,hex); } else + if (strstr(hex,"DX")==hex) { hex+=2; reg_dx = GetHexValue(hex,hex); } else + if (strstr(hex,"SI")==hex) { hex+=2; reg_si = GetHexValue(hex,hex); } else + if (strstr(hex,"DI")==hex) { hex+=2; reg_di = GetHexValue(hex,hex); } else + if (strstr(hex,"BP")==hex) { hex+=2; reg_bp = GetHexValue(hex,hex); } else + if (strstr(hex,"SP")==hex) { hex+=2; reg_sp = GetHexValue(hex,hex); } else + if (strstr(hex,"IP")==hex) { hex+=2; reg_ip = GetHexValue(hex,hex); } else + if (strstr(hex,"CS")==hex) { hex+=2; SegSet16(cs,GetHexValue(hex,hex)); } else + if (strstr(hex,"DS")==hex) { hex+=2; SegSet16(ds,GetHexValue(hex,hex)); } else + if (strstr(hex,"ES")==hex) { hex+=2; SegSet16(es,GetHexValue(hex,hex)); } else + if (strstr(hex,"FS")==hex) { hex+=2; SegSet16(fs,GetHexValue(hex,hex)); } else + if (strstr(hex,"GS")==hex) { hex+=2; SegSet16(gs,GetHexValue(hex,hex)); } else + if (strstr(hex,"SS")==hex) { hex+=2; SegSet16(ss,GetHexValue(hex,hex)); } else + if (strstr(hex,"EAX")==hex) { hex+=3; reg_eax = GetHexValue(hex,hex); } else + if (strstr(hex,"EBX")==hex) { hex+=3; reg_ebx = GetHexValue(hex,hex); } else + if (strstr(hex,"ECX")==hex) { hex+=3; reg_ecx = GetHexValue(hex,hex); } else + if (strstr(hex,"EDX")==hex) { hex+=3; reg_edx = GetHexValue(hex,hex); } else + if (strstr(hex,"ESI")==hex) { hex+=3; reg_esi = GetHexValue(hex,hex); } else + if (strstr(hex,"EDI")==hex) { hex+=3; reg_edi = GetHexValue(hex,hex); } else + if (strstr(hex,"EBP")==hex) { hex+=3; reg_ebp = GetHexValue(hex,hex); } else + if (strstr(hex,"ESP")==hex) { hex+=3; reg_esp = GetHexValue(hex,hex); } else + if (strstr(hex,"EIP")==hex) { hex+=3; reg_eip = GetHexValue(hex,hex); } else + if (strstr(hex,"AF")==hex) { hex+=2; flags.af = (GetHexValue(hex,hex)!=0); } else + if (strstr(hex,"CF")==hex) { hex+=2; flags.cf = (GetHexValue(hex,hex)!=0); } else + if (strstr(hex,"DF")==hex) { hex+=2; flags.df = (GetHexValue(hex,hex)!=0); } else + if (strstr(hex,"IF")==hex) { hex+=2; flags.intf = (GetHexValue(hex,hex)!=0); } else + if (strstr(hex,"OF")==hex) { hex+=3; flags.of = (GetHexValue(hex,hex)!=0); } else + if (strstr(hex,"ZF")==hex) { hex+=3; flags.zf = (GetHexValue(hex,hex)!=0); } else + if (strstr(hex,"PF")==hex) { hex+=3; flags.pf = (GetHexValue(hex,hex)!=0); } else + { return false; }; + return true; +}; + bool ParseCommand(char* str) { char* found = str; @@ -604,6 +683,17 @@ bool ParseCommand(char* str) LOG_DEBUG("DEBUG: Set breakpoint at %04X:%04X",seg,ofs); return true; } +#if C_HEAVY_DEBUG + found = strstr(str,"BPM "); + if (found) { // Add new breakpoint + found+=3; + Bit16u seg = GetHexValue(found,found);found++; // skip ":" + Bit32u ofs = GetHexValue(found,found); + CBreakpoint::AddMemBreakpoint(seg,ofs); + LOG_DEBUG("DEBUG: Set memory breakpoint at %04X:%04X",seg,ofs); + return true; + } +#endif found = strstr(str,"BPINT"); if (found) { // Add Interrupt Breakpoint found+=5; @@ -666,6 +756,30 @@ bool ParseCommand(char* str) LOG_DEBUG("DEBUG: Logfile LOGCPU.TXT created."); return true; } + found = strstr(str,"SR "); + if (found) { // Set register value + found+=2; + if (ChangeRegister(found)) LOG_DEBUG("DEBUG: Set Register success."); + else LOG_DEBUG("DEBUG: Set Register failure."); + return true; + } + found = strstr(str,"SM "); + if (found) { // Set memory with following values + found+=3; + Bit16u seg = GetHexValue(found,found); found++; + Bit32u ofs = GetHexValue(found,found); found++; + Bit16u count = 0; + while (*found) { + while (*found==' ') found++; + if (*found) { + Bit8u value = GetHexValue(found,found); found++; + mem_writeb(PhysMake(seg,ofs+count),value); + count++; + } + }; + LOG_DEBUG("DEBUG: Memory changed."); + return true; + } found = strstr(str,"INTT "); if (found) { // Create Cpu log file found+=4; @@ -688,6 +802,15 @@ bool ParseCommand(char* str) Interrupt(intNr); return true; } +#if C_HEAVY_DEBUG + found = strstr(str,"HEAVYLOG"); + if (found) { // Create Cpu log file + logHeavy = !logHeavy; + if (logHeavy) LOG_DEBUG("DEBUG: Heavy cpu logging on."); + else LOG_DEBUG("DEBUG: Heavy cpu logging off."); + return true; + } +#endif if ((*str=='H') || (*str=='?')) { wprintw(dbg.win_out,"Debugger keys:\n"); wprintw(dbg.win_out,"--------------------------------------------------------------------------\n"); @@ -703,11 +826,19 @@ bool ParseCommand(char* str) wprintw(dbg.win_out,"BP [segment]:[offset] - Set breakpoint\n"); wprintw(dbg.win_out,"BPINT [intNr] * - Set interrupt breakpoint\n"); wprintw(dbg.win_out,"BPINT [intNr] [ah] - Set interrupt breakpoint with ah\n"); +#if C_HEAVY_DEBUG + wprintw(dbg.win_out,"BPM [segment]:[offset] - Set memory breakpoint (memory change)\n"); +#endif 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"); +#if C_HEAVY_DEBUG + wprintw(dbg.win_out,"HEAVYLOG - Enable/Disable automatic cpu log for INT CD\n"); +#endif + wprintw(dbg.win_out,"SR [reg] [value] - Set register value\n"); + wprintw(dbg.win_out,"SM [seg]:[off] [val] [.]..- Set memory with following values\n"); wprintw(dbg.win_out,"H - Help\n"); wrefresh(dbg.win_out); return TRUE; @@ -744,22 +875,28 @@ Bit32u DEBUG_CheckKeys(void) { if (key>0) { switch (toupper(key)) { case '1': - ret=(*cpudecoder)(100); + CPU_Cycles = 100; + ret=(*cpudecoder)(); break; case '2': - ret=(*cpudecoder)(500); + CPU_Cycles = 500; + ret=(*cpudecoder)(); break; case '3': - ret=(*cpudecoder)(1000); + CPU_Cycles = 1000; + ret=(*cpudecoder)(); break; case '4': - ret=(*cpudecoder)(5000); + CPU_Cycles = 5000; + ret=(*cpudecoder)(); break; case '5': - ret=(*cpudecoder)(10000); + CPU_Cycles = 10000; + ret=(*cpudecoder)(); break; case 'q': - ret=(*cpudecoder)(5); + CPU_Cycles = 5; + ret=(*cpudecoder)(); break; case 'D': dataSeg = SegValue(ds); dataOfs = reg_si; @@ -813,14 +950,18 @@ Bit32u DEBUG_CheckKeys(void) { if (StepOver()) return 0; else { skipFirstInstruction = true; // for heavy debugger - Bitu ret=(*cpudecoder)(1); + CPU_Cycles = 1; + Bitu ret=(*cpudecoder)(); SetCodeWinStart(); + CBreakpoint::ignoreOnce = 0; } break; case KEY_F(11): // trace into skipFirstInstruction = true; // for heavy debugger - ret = (*cpudecoder)(1); + CPU_Cycles = 1; + ret = (*cpudecoder)(); SetCodeWinStart(); + CBreakpoint::ignoreOnce = 0; break; // default: @@ -868,10 +1009,20 @@ static void DEBUG_RaiseTimerIrq(void) { PIC_ActivateIRQ(0); } +static void LogInstruction(Bit16u segValue, Bit32u eipValue, char* buffer) +{ + PhysPt start = PhysMake(segValue,eipValue); + 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," "); + // Get register values + 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",segValue,eipValue,dline,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(es),SegValue(fs),SegValue(gs),SegValue(ss),get_CF(),get_ZF(),get_SF(),get_OF(),get_AF(),get_PF()); +}; + static bool DEBUG_Log_Loop(int count) { char buffer[512]; - getcwd(buffer,512); FILE* f = fopen("LOGCPU.TXT","wt"); if (!f) return false; @@ -884,23 +1035,17 @@ static bool DEBUG_Log_Loop(int count) { // 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()); + LogInstruction(csValue,eipValue,buffer); fprintf(f,"%s",buffer); + + CPU_Cycles = 1; + ret=(*cpudecoder)(); + count--; if (count==0) break; - } while (!ret && PIC_IRQAgain); + } while (!ret); if (ret) break; } while (count>0); @@ -920,15 +1065,42 @@ public: void Run(void) { char filename[128]; - char args[128]; + char args[256]; cmd->FindCommand(1,temp_line); strncpy(filename,temp_line.c_str(),128); - cmd->FindCommand(2,temp_line); - strncpy(args,temp_line.c_str(),128); + // Read commandline + Bit16u i =2; + bool ok = false; + args[0] = 0; + do { + ok = cmd->FindCommand(i++,temp_line); + strncat(args,temp_line.c_str(),256); + strncat(args," ",256); + } while (ok); // Start new shell and execute prog active = true; - DOS_Shell shell; - shell.Execute(filename,args); + // Save cpu state.... + Bit16u oldcs = SegValue(cs); + Bit32u oldeip = reg_eip; + Bit16u oldss = SegValue(ss); + Bit32u oldesp = reg_esp; + + // Workaround : Allocate Stack Space + Bit16u segment; + Bit16u size = 0x200 / 0x10; + if (DOS_AllocateMemory(&segment,&size)) { + SegSet16(ss,segment); + reg_sp = 0x200; + // Start shell + DOS_Shell shell; + shell.Execute(filename,args); + DOS_FreeMemory(segment); + } + // set old reg values + SegSet16(ss,oldss); + reg_esp = oldesp; + SegSet16(cs,oldcs); + reg_eip = oldeip; }; private: @@ -954,6 +1126,9 @@ void DEBUG_SetupConsole(void) { #ifdef WIN32 WIN32_Console(); + #else + printf("\e[8;50;80t"); //resize terminal + fflush(NULL); #endif memset((void *)&dbg,0,sizeof(dbg)); debugging=false; @@ -987,8 +1162,53 @@ void DEBUG_Init(Section* sec) { #if C_HEAVY_DEBUG +const Bit16u LOGCPUMAX = 200; + +static Bit16u logCpuCS [LOGCPUMAX]; +static Bit32u logCpuEIP[LOGCPUMAX]; +static Bit32u logCount = 0; + +typedef struct SLogInst { + char buffer[256]; +} TLogInst; + +TLogInst logInst[LOGCPUMAX]; + +void DEBUG_HeavyLogInstruction(void) +{ + LogInstruction(SegValue(cs),reg_eip,logInst[logCount++].buffer); + if (logCount>=LOGCPUMAX) logCount = 0; +}; + +void DEBUG_HeavyWriteLogInstruction(void) +{ + if (!logHeavy) return; + + LOG_DEBUG("DEBUG: Creating cpu log LOGCPU_INT_CD.TXT"); + + FILE* f = fopen("LOGCPU_INT_CD.TXT","wt"); + if (!f) { + LOG_DEBUG("DEBUG: Failed."); + return; + } + + Bit16u startLog = logCount; + do { + // Write Intructions + fprintf(f,"%s",logInst[startLog++].buffer); + if (startLog>=LOGCPUMAX) startLog = 0; + } while (startLog!=logCount); + + fclose(f); + + LOG_DEBUG("DEBUG: Done."); +}; + bool DEBUG_HeavyIsBreakpoint(void) { + // LogInstruction + if (logHeavy) DEBUG_HeavyLogInstruction(); + if (skipFirstInstruction) { skipFirstInstruction = false; return false; diff --git a/src/debug/debug_disasm.cpp b/src/debug/debug_disasm.cpp index 42cd96d..67559cd 100644 --- a/src/debug/debug_disasm.cpp +++ b/src/debug/debug_disasm.cpp @@ -344,7 +344,7 @@ static char *groups[][8] = { /* group 0 is group 3 for %Ev set */ { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" }, /* 2 */ /* v v*/ - { "test %Eq,%Iq", "test %Eq,%Iq", "not %Ec", "neg %Ev", + { "test %Eq,%Iq", "test %Eq,%Iq", "not %Ec", "neg %Ec", "mul %Ec", "imul %Ec", "div %Ec", "idiv %Ec" }, /* 3 */ { "inc %Eb", "dec %Eb", 0, 0, @@ -457,7 +457,7 @@ static char *addr_to_hex(UINT32 addr, int splitup) { } static PhysPt getbyte_mac; - +static PhysPt startPtr; static UINT8 getbyte(void) { return mem_readb(getbyte_mac++); @@ -662,7 +662,7 @@ static void reg_name(int regnum, char size) uprintf("st(%d)", regnum); return; } - if (((size == 'v') && (opsize == 32)) || (size == 'd')) + if ((((size == 'c') || (size == 'v')) && (opsize == 32)) || (size == 'd')) uputchar('e'); if ((size=='q' || size == 'b' || size=='c') && !wordop) { uputchar("acdbacdb"[regnum]); @@ -822,6 +822,8 @@ static void floating_point(int e1) /*------------------------------------------------------------------------*/ /* Main table driver */ +#define INSTRUCTION_SIZE (int)getbyte_mac - (int)startPtr + static void percent(char type, char subtype) { INT32 vofs = 0; @@ -864,13 +866,13 @@ static void percent(char type, char subtype) switch (bytes(subtype)) { /* sizeof offset value */ case 1: vofs = (INT8)getbyte(); - name = addr_to_hex(vofs+instruction_offset,0); + name = addr_to_hex(vofs+instruction_offset+INSTRUCTION_SIZE,0); break; case 2: vofs = getbyte(); vofs += getbyte()<<8; vofs = (INT16)vofs; - name = addr_to_hex(vofs+instruction_offset,0); + name = addr_to_hex(vofs+instruction_offset+INSTRUCTION_SIZE,0); break; #if 0 /* i386 */ @@ -879,7 +881,7 @@ static void percent(char type, char subtype) vofs |= (UINT32)getbyte() << 8; vofs |= (UINT32)getbyte() << 16; vofs |= (UINT32)getbyte() << 24; - name = addr_to_hex(vofs+instruction_offset,1); + name = addr_to_hex(vofs+instruction_offset+INSTRUCTION_SIZE,1); break; #endif } @@ -1077,6 +1079,7 @@ Bitu DasmI386(char* buffer, PhysPt pc, Bitu cur_ip, bool bit32) instruction_offset = cur_ip; /* input buffer */ + startPtr = pc; getbyte_mac = pc; /* output buffer */ diff --git a/src/debug/debug_gui.cpp b/src/debug/debug_gui.cpp index 43d8d30..64eb95f 100644 --- a/src/debug/debug_gui.cpp +++ b/src/debug/debug_gui.cpp @@ -122,6 +122,10 @@ void DBGUI_StartUp(void) { noecho(); /* don't echo input */ nodelay(dbg.win_main,true); keypad(dbg.win_main,true); + #ifndef WIN32 + resizeterm(50,80); + touchwin(dbg.win_main); + #endif cycle_count=0; MakePairs(); MakeSubWindows(); diff --git a/src/dos/dev_con.h b/src/dos/dev_con.h index 77998e2..c262736 100644 --- a/src/dos/dev_con.h +++ b/src/dos/dev_con.h @@ -16,6 +16,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "dos_inc.h" +#include "../ints/int10.h" + +#define NUMBER_ANSI_DATA 10 + class device_CON : public DOS_Device { public: device_CON(); @@ -23,17 +28,36 @@ public: bool Write(Bit8u * data,Bit16u * size); bool Seek(Bit32u * pos,Bit32u type); bool Close(); + void ClearAnsi(void); Bit16u GetInformation(void); private: Bit8u cache; + struct ansi { /* should create a constructor which fills them with the appriorate values */ + bool esc; + bool sci; + Bit8u attr; + Bit8u data[NUMBER_ANSI_DATA]; + Bit8u numberofarg; + Bit16u nrows; + Bit16u ncols; + Bit8s savecol; + Bit8s saverow; + } ansi; + }; +void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page); +void INT10_SetCursorPos(Bit8u row,Bit8u col,Bit8u page); bool device_CON::Read(Bit8u * data,Bit16u * size) { Bit16u oldax=reg_ax; Bit16u count=0; if ((cache) && (*size)) { data[count++]=cache; - cache=0; + if(dos.echo) { + INT10_TeletypeOutput(cache,7,false,0); + } + cache=0; + } while (*size>count) { reg_ah=0; @@ -41,11 +65,26 @@ bool device_CON::Read(Bit8u * data,Bit16u * size) { switch(reg_al) { case 13: data[count++]=0x0D; -// if (*size>count) data[count++]=0x0A; -// else cache=0x0A; - *size=count; + if (*size>count) data[count++]=0x0A; // it's only expanded if there is room for it. (NO cache) + *size=count; reg_ax=oldax; + if(dos.echo) { + INT10_TeletypeOutput(13,7,false,0); //maybe don't do this ( no need for it actually ) (but it's compatible) + INT10_TeletypeOutput(10,7,false,0); + } return true; + break; + case 8: + if(*size==1) data[count++]=reg_al; //one char at the time so give back that BS + else if(count) { //Remove data if it exists (extended keys don't go right) + data[count--]=0; + INT10_TeletypeOutput(8,7,false,0); + INT10_TeletypeOutput(' ',7,false,0); + } else { + continue; //no data read yet so restart whileloop. + } + + break; default: data[count++]=reg_al; break; @@ -54,27 +93,247 @@ bool device_CON::Read(Bit8u * data,Bit16u * size) { if (*size>count) data[count++]=reg_ah; else cache=reg_ah; break; - } + + } + if(dos.echo) { //what to do if *size==1 and character is BS ????? + INT10_TeletypeOutput(reg_al,7,false,0); + } } *size=count; reg_ax=oldax; return true; } -extern void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page); + bool device_CON::Write(Bit8u * data,Bit16u * size) { Bit16u count=0; - while (*size>count) { + Bitu i; + Bit8s col,row; + static bool ansiwarned=false; - INT10_TeletypeOutput(data[count],7,false,0); - count++; + while (*size>count) { + if (!ansi.esc){ + if(data[count]=='\033') { + /*clear the datastructure */ + ClearAnsi(); + /* start the sequence */ + ansi.esc=true; + count++; + if(!ansiwarned) { + LOG_WARN("ANSI sequences detected. enabling ansi support"); /* maybe LOG_MSG */ + ansiwarned=true; + } + continue; + + } else { + INT10_TeletypeOutput(data[count],ansi.attr,true,0); + count++; + continue; + }; + }; + /* ansi.esc=true */ + if(!ansi.sci){ + + switch(data[count]){ + case '[': + ansi.sci=true; + break; + case '7': /* save cursor pos +attr */ + case '8': /* restore this (Wonder if this is actually used) */ + case 'D':/* scrolling DOWN*/ + case 'M':/* scrolling UP*/ + default: + LOG_DEBUG("ANSI: unknown char %c after a esc",data[count]); /*prob () */ + ClearAnsi(); + break; + } + count++; + continue; + + } + /*ansi.esc and ansi.sci are true */ + switch(data[count]){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ansi.data[ansi.numberofarg]=10*ansi.data[ansi.numberofarg]+(data[count]-'0'); + break; + case ';': /* till a max of NUMBER_ANSI_DATA */ + ansi.numberofarg++; + break; + case 'm': /* SGR */ + for(i=0;i<=ansi.numberofarg;i++){ + + switch(ansi.data[i]){ + case 0: /* normal */ + ansi.attr=0x7; + break; + case 1: /* bold mode on*/ + ansi.attr|=0x8; + break; + case 4: /* underline */ + LOG_DEBUG("ANSI:no support for underline yet"); + break; + case 5: /* blinking */ + LOG_DEBUG("ANSI:no support for blinking yet"); + break; + case 7: /* reverse */ + LOG_DEBUG("ANSI:no support for reverse yet"); + break; + case 30: /* fg color black */ + ansi.attr&=0xf8; + ansi.attr|=0x0; + break; + case 31: /* fg color red */ + ansi.attr&=0xf8; + ansi.attr|=0x4; + break; + case 32: /* fg color green */ + ansi.attr&=0xf8; + ansi.attr|=0x2; + break; + case 33: /* fg color yellow */ + ansi.attr&=0xf8; + ansi.attr|=0x6; + break; + case 34: /* fg color blue */ + ansi.attr&=0xf8; + ansi.attr|=0x1; + break; + case 35: /* fg color magenta */ + ansi.attr&=0xf8; + ansi.attr|=0x5; + break; + case 36: /* fg color cyan */ + ansi.attr&=0xf8; + ansi.attr|=0x3; + break; + case 37: /* fg color white */ + ansi.attr&=0xf8; + ansi.attr|=0x7; + break; + case 40: + ansi.attr&=0x8f; + ansi.attr|=0x0; + break; + case 41: + ansi.attr&=0x8f; + ansi.attr|=0x40; + break; + case 42: + ansi.attr&=0x8f; + ansi.attr|=0x20; + break; + case 43: + ansi.attr&=0x8f; + ansi.attr|=0x60; + break; + case 44: + ansi.attr&=0x8f; + ansi.attr|=0x10; + break; + case 45: + ansi.attr&=0x8f; + ansi.attr|=0x50; + break; + case 46: + ansi.attr&=0x8f; + ansi.attr|=0x30; + break; + case 47: + ansi.attr&=0x8f; + ansi.attr|=0x70; + break; + default: + break; + + } + } + ClearAnsi(); + break; + case 'f': + case 'H':/* Cursor Pos*/ + if(ansi.data[0]==0) ansi.data[0]=1; + if(ansi.data[1]==0) ansi.data[1]=1; + INT10_SetCursorPos(--(ansi.data[0]),--(ansi.data[1]),0); /*ansi=1 based, int10 is 0 based */ + ClearAnsi(); + break; + case 'A': /* cursor up*/ + col=CURSOR_POS_COL(0) ; + row=CURSOR_POS_ROW(0) - (ansi.data[0]? ansi.data[0] : 1); + INT10_SetCursorPos(row,col,0); + ClearAnsi(); + break; + case 'C': /*cursor forward */ + col=CURSOR_POS_COL(0) + (ansi.data[0]? ansi.data[0] : 1); + row=CURSOR_POS_ROW(0); + while(col>=ansi.ncols) { + row++; + col = col - ansi.ncols; // should depend on linebrake mode + } + INT10_SetCursorPos(row,col,0); + ClearAnsi(); + break; + case 'J': /*erase screen and move cursor home*/ + if(ansi.data[0]==0) ansi.data[0]=2; + if(ansi.data[0]!=2) {/* only number 2 (the standard one supported) */ + LOG_DEBUG("ANSI: esc[%dJ called : not supported",ansi.data[0]); + break; + } + for(i=0;i<(Bitu)ansi.ncols*ansi.nrows;i++) INT10_TeletypeOutput(' ',ansi.attr,true,0); + ClearAnsi(); + INT10_SetCursorPos(0,0,0); + break; + case 'h': /* set MODE (if code =7 enable linewrap) */ + case 'I': /*RESET MODE */ + LOG_DEBUG("ANSI: set/reset mode called(not supported)"); + ClearAnsi(); + break; + case 'D': /*Cursor Backward */ + col=CURSOR_POS_COL(0) - (ansi.data[0]? ansi.data[0] : 1); + row=CURSOR_POS_ROW(0); + while(col<0) { + row--; + col = col + ansi.ncols ; // should depend on linebrake mode + } + INT10_SetCursorPos(row,col,0); + ClearAnsi(); + break; + case 'u': /* Restore Cursor Pos */ + INT10_SetCursorPos(ansi.saverow,ansi.savecol,0); + ClearAnsi(); + break; + case 's': /* SAVE CURSOR POS */ + ansi.savecol=CURSOR_POS_COL(0); + ansi.saverow=CURSOR_POS_ROW(0); + ClearAnsi(); + break; + case 'K':/* erase till end of line */ + case 'l':/* (if code =7) disable linewrap */ + case 'p':/* reassign keys (needs strings) */ + case 'i':/* printer stuff */ + default: + LOG_DEBUG("ANSI: unhandled char %c in esc[",data[count]); + ClearAnsi(); + break; + } + count++; } *size=count; return true; } bool device_CON::Seek(Bit32u * pos,Bit32u type) { - return false; + // seek is valid + *pos = 0; + return true; } bool device_CON::Close() { @@ -89,9 +348,23 @@ Bit16u device_CON::GetInformation(void) { return 0x8093; /* Key Available */ }; - device_CON::device_CON() { name="CON"; cache=0; + ansi.esc=false; + ansi.sci=false; + ansi.attr=0x7; + ansi.numberofarg=0; + for(Bit8u i=0; i12) || (reg_dh==0)) { reg_al=0xff;break;} if ((reg_dl>31) || (reg_dl==0)) { reg_al=0xff;break;} @@ -307,9 +301,9 @@ static Bitu DOS_21Handler(void) { Bit32u ticks=mem_readd(BIOS_TIMER); Bit32u seconds=(ticks*10)/182; reg_ch=(Bit8u)(seconds/3600); - reg_cl=(Bit8u)(seconds % 3600)/60; + reg_cl=(Bit8u)((seconds % 3600)/60); reg_dh=(Bit8u)(seconds % 60); - reg_dl=(Bit8u)(ticks % 19)*5; + reg_dl=(Bit8u)((ticks % 20)*5); /* 0-19 ->0-95 */ } break; case 0x2d: /* Set System Time */ @@ -367,7 +361,8 @@ static Bitu DOS_21Handler(void) { break; case 0x36: /* Get Free Disk Space */ { - Bit16u bytes,sectors,clusters,free; + Bit16u bytes,clusters,free; + Bit8u sectors; if (DOS_GetFreeDiskSpace(reg_dl,&bytes,§ors,&clusters,&free)) { reg_ax=sectors; reg_bx=free; @@ -459,7 +454,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); + dos.echo=true; if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) { MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread); reg_ax=toread; @@ -468,12 +463,12 @@ static Bitu DOS_21Handler(void) { reg_ax=dos.errorcode; CALLBACK_SCF(true); } + dos.echo=false; break; } 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; @@ -604,8 +599,11 @@ static Bitu DOS_21Handler(void) { } break; //TODO Check for use of execution state AL=5 + case 0x00: + reg_ax=0x4c00; /* Terminate Program */ case 0x4c: /* EXIT Terminate with return code */ - { + + { if (DOS_Terminate(false)) { /* This can't ever return false normally */ } else { @@ -652,9 +650,10 @@ static Bitu DOS_21Handler(void) { //TODO Think hard how shit this is gonna be //And will any game ever use this :) case 0x53: /* Translate BIOS parameter block to drive parameter block */ -//YEAH RIGHT + E_Exit("Unhandled Dos 21 call %02X",reg_ah); + break; case 0x54: /* Get verify flag */ - E_Exit("Unhandled Dos 21 call %02X",reg_ah); + reg_al=dos.verify?1:0; break; case 0x55: /* Create Child PSP*/ DOS_NewPSP(reg_dx,reg_si); @@ -686,9 +685,10 @@ static Bitu DOS_21Handler(void) { case 0x58: /* Get/Set Memory allocation strategy */ switch (reg_al) { case 0: /* Get Strategy */ - reg_ax=0; //Low memory first fit + reg_ax=DOS_GetMemAllocStrategy(); break; case 1: /* Set Strategy */ + DOS_SetMemAllocStrategy(reg_bx); break; default: LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al); @@ -733,8 +733,8 @@ static Bitu DOS_21Handler(void) { } break; } + case 0x5c: /* FLOCK File region locking */ - case 0x5d: /* Network Functions */ case 0x5e: /* More Network Functions */ case 0x5f: /* And Even More Network Functions */ E_Exit("DOS:Unhandled call %02X",reg_ah); @@ -752,10 +752,6 @@ static Bitu DOS_21Handler(void) { case 0x62: /* Get Current PSP Address */ reg_bx=dos.psp; break; - case 0x63: /* Weirdo double byte stuff */ - reg_al=0xff; - LOG_WARN("DOS:0x63:Doubly byte characters not supported"); - break; case 0x64: /* Set device driver lookahead flag */ E_Exit("Unhandled Dos 21 call %02X",reg_ah); break; @@ -792,9 +788,6 @@ static Bitu DOS_21Handler(void) { LOG_DEBUG("DOS:67:Set Handle Count not working"); CALLBACK_SCF(false); break; - case 0x68: /* FFLUSH Commit file */ - E_Exit("Unhandled Dos 21 call %02X",reg_ah); - break; case 0x69: /* Get/Set disk serial number */ { switch(reg_al) { @@ -817,11 +810,21 @@ static Bitu DOS_21Handler(void) { CALLBACK_SCF(true); LOG_WARN("DOS:Windows long file name support call %2X",reg_al); break; - case 0xE0: - LOG_DEBUG("DOS:E0:Unhandled, what should this call do?"); - break; + case 0x68: /* FFLUSH Commit file */ + case 0x63: /* Weirdo double byte stuff (fails but say it succeeded) available only in MSDOS 2.25 */ + CALLBACK_SCF(false); //mirek + case 0xE0: + 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 */ + case 0x20: /* NULL Function for CP/M compatibility or Extended rename FCB */ + case 0x6b: /* NULL Function */ + case 0x61: /* UNUSED */ + case 0xEF: /* Used in Ancient Art Of War CGA */ + case 0x5d: /* Network Functions */ default: - E_Exit("DOS:Unhandled call %02X",reg_ah); + LOG_DEBUG("DOS:Unhandled call %02X al=%02X. Set al to default of 0",reg_ah,reg_al); + reg_al=0x00; /* default value */ break; }; return CBRET_NONE; @@ -837,6 +840,22 @@ static Bitu DOS_20Handler(void) { return CBRET_NONE; } +static Bitu DOS_27Handler(void) +{ + // Terminate & stay resident + Bit16u para = (reg_dx/16)+((reg_dx % 16)>0); + if (DOS_ResizeMemory(dos.psp,¶)) DOS_Terminate(true); + return CBRET_NONE; +} + +static Bitu DOS_28Handler(void) { + return CBRET_NONE; +} + +static Bitu DOS_29Handler(void) { + LOG_DEBUG("int 29 called"); + return CBRET_NONE; +} void DOS_Init(Section* sec) { MSG_Add("DOS_CONFIGFILE_HELP","Setting a memory size to 0 will disable it.\n"); @@ -845,9 +864,21 @@ void DOS_Init(Section* sec) { RealSetVec(0x20,CALLBACK_RealPointer(call_20)); call_21=CALLBACK_Allocate(); - CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET); + CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET_STI); RealSetVec(0x21,CALLBACK_RealPointer(call_21)); + call_27=CALLBACK_Allocate(); + CALLBACK_Setup(call_27,DOS_27Handler,CB_IRET); + RealSetVec(0x27,CALLBACK_RealPointer(call_27)); + + call_28=CALLBACK_Allocate(); + CALLBACK_Setup(call_28,DOS_28Handler,CB_IRET); + RealSetVec(0x28,CALLBACK_RealPointer(call_28)); + + call_29=CALLBACK_Allocate(); + CALLBACK_Setup(call_29,DOS_29Handler,CB_IRET); + RealSetVec(0x29,CALLBACK_RealPointer(call_29)); + DOS_SetupFiles(); /* Setup system File tables */ DOS_SetupDevices(); /* Setup dos devices */ DOS_SetupTables(); @@ -855,8 +886,16 @@ void DOS_Init(Section* sec) { DOS_SetupPrograms(); DOS_SetupMisc(); /* Some additional dos interrupts */ DOS_SetDefaultDrive(25); - /* Execute the file that should be */ + dos.version.major=5; dos.version.minor=0; -// DOS_RunProgram(startname); -}; + /* Setup time and date */ + time_t curtime;struct tm *loctime; + curtime = time (NULL);loctime = localtime (&curtime); + + dos.date.day=(Bit8u)loctime->tm_mday; + dos.date.month=(Bit8u)loctime->tm_mon+1; + dos.date.year=(Bit16u)loctime->tm_year+1900; + Bit32u ticks=(Bit32u)((loctime->tm_hour*3600+loctime->tm_min*60+loctime->tm_sec)*18.2); + mem_writed(BIOS_TIMER,ticks); +} diff --git a/src/dos/dos_classes.cpp b/src/dos/dos_classes.cpp index 3f1c729..6025b28 100644 --- a/src/dos/dos_classes.cpp +++ b/src/dos/dos_classes.cpp @@ -318,7 +318,7 @@ void DOS_FCB::SetRandom(Bit32u _random) { } void DOS_FCB::FileOpen(Bit8u _fhandle) { - sSave(sFCB,drive,GetDrive()); + sSave(sFCB,drive,GetDrive()+1); sSave(sFCB,file_handle,_fhandle); sSave(sFCB,cur_block,0); sSave(sFCB,rec_size,128); diff --git a/src/dos/dos_execute.cpp b/src/dos/dos_execute.cpp index bb3c623..6562148 100644 --- a/src/dos/dos_execute.cpp +++ b/src/dos/dos_execute.cpp @@ -208,7 +208,7 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { Bitu headersize,imagesize; DOS_ParamBlock block(block_pt); block.LoadData(); - if (flags!=LOADNGO && flags!=OVERLAY) { + if (flags!=LOADNGO && flags!=OVERLAY && flags!=LOAD) { E_Exit("DOS:Not supported execute mode %d for file %s",flags,name); } /* Check for EXE or COM File */ @@ -271,12 +271,12 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { pos=headersize;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); while (imagesize>0x7FFF) { readsize=0x8000;DOS_ReadFile(fhandle,loadaddress,&readsize); - if (readsize!=0x8000) E_Exit("Illegal header"); + if (readsize!=0x8000) LOG_WARN("Illegal header"); loadaddress+=0x8000;imagesize-=0x8000; } if (imagesize>0) { readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadaddress,&readsize); - if (readsize!=imagesize) E_Exit("Illegal header"); + if (readsize!=imagesize) LOG_WARN("Illegal header"); } /* Relocate the exe image */ Bit16u relocate; @@ -302,6 +302,20 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { csip=RealMake(loadseg+head.initCS,head.initIP); sssp=RealMake(loadseg+head.initSS,head.initSP); } + + if (flags==LOAD) { + DOS_PSP callpsp(dos.psp); + /* Save the SS:SP on the PSP of calling program */ + callpsp.SetStack(RealMakeSeg(ss,reg_sp)); + /* Switch the psp's */ + dos.psp=pspseg; + + block.exec.initsssp = sssp; + block.exec.initcsip = csip; + block.SaveData(); + return true; + } + if (flags==LOADNGO) { /* Get Caller's program CS:IP of the stack and set termination address to that */ RealSetVec(0x22,RealMake(mem_readw(SegPhys(ss)+reg_sp+2),mem_readw(SegPhys(ss)+reg_sp))); diff --git a/src/dos/dos_files.cpp b/src/dos/dos_files.cpp index 99217e3..3dc25fa 100644 --- a/src/dos/dos_files.cpp +++ b/src/dos/dos_files.cpp @@ -78,6 +78,7 @@ bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) { case '\\': case '$': case '#': case '@': case '(': case ')': case '!': case '%': case '{': case '}': case '`': case '~': case '_': case '-': case '.': case '*': case '?': case '&': + case '\'': upname[w++]=c; break; default: @@ -150,8 +151,10 @@ bool DOS_GetCurrentDir(Bit8u drive,char * buffer) { } bool DOS_ChangeDir(char * dir) { + Bit8u drive;char fulldir[DOS_PATHLENGTH]; if (!DOS_MakeName(dir,fulldir,&drive)) return false; + if (Drives[drive]->TestDir(fulldir)) { strcpy(Drives[drive]->curdir,fulldir); return true; @@ -202,14 +205,14 @@ bool DOS_FindFirst(char * search,Bit16u attr) { } dta.SetupSearch(drive,(Bit8u)attr,pattern); if (Drives[drive]->FindFirst(dir,dta)) return true; - DOS_SetError(DOSERR_FILE_NOT_FOUND); + DOS_SetError(DOSERR_NO_MORE_FILES); return false; } bool DOS_FindNext(void) { DOS_DTA dta(dos.dta); if (Drives[dta.GetSearchDrive()]->FindNext(dta)) return true; - DOS_SetError(DOSERR_FILE_NOT_FOUND); + DOS_SetError(DOSERR_NO_MORE_FILES); return false; } @@ -397,7 +400,7 @@ bool DOS_Canonicalize(char * name,char * big) { return true; } -bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) { +bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free) { if (drive==0) drive=DOS_GetDefaultDrive(); else drive--; if ((drive>DOS_DRIVES) || (!Drives[drive])) { @@ -473,7 +476,6 @@ bool DOS_CreateTempFile(char * name,Bit16u * entry) { } -#if 1 static bool FCB_MakeName2 (DOS_FCB & fcb, char* outname, Bit8u* outdrive){ char short_name[DOS_FCBNAME]; @@ -626,7 +628,16 @@ static void SaveFindResult(DOS_FCB & find_fcb) { fcb.SetSizeDateTime(size,date,time); } -bool DOS_FCBOpenCreate(Bit16u seg,Bit16u offset) { +bool DOS_FCBCreate(Bit16u seg,Bit16u offset) { + DOS_FCB fcb(seg,offset); + char shortname[DOS_FCBNAME];Bit16u handle; + fcb.GetName(shortname); + if (!DOS_CreateFile(shortname,2,&handle)) return false; + fcb.FileOpen((Bit8u)handle); + return true; +} + +bool DOS_FCBOpen(Bit16u seg,Bit16u offset) { DOS_FCB fcb(seg,offset); char shortname[DOS_FCBNAME];Bit16u handle; fcb.GetName(shortname); @@ -687,7 +698,7 @@ Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset,Bit16u recno) { return FCB_READ_PARTIAL; } -bool DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno) +Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno) { DOS_FCB fcb(seg,offset); Bit8u fhandle,cur_rec;Bit16u cur_block,rec_size; @@ -709,13 +720,19 @@ bool DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno) } Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) { +/* if restore is true :random read else random blok read. + * random read updates old block and old record to reflect the random data + * before the read!!!!!!!!! and the random data is not updated! (user must do this) + * Random block read updates these fields to reflect the state after the read! + */ 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)); + if (restore) fcb.GetRecord(old_block,old_rec);//store this for after the read. // Read records for (int i=0; iFileExists(fullname); } -bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters) { +bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters) { if (!drive) drive=dos.current_drive; else drive--; if (!Drives[drive]) return false; diff --git a/src/dos/dos_ioctl.cpp b/src/dos/dos_ioctl.cpp index f01b181..2a4a50a 100644 --- a/src/dos/dos_ioctl.cpp +++ b/src/dos/dos_ioctl.cpp @@ -86,6 +86,13 @@ bool DOS_IOCTL(void) { return false; } break; + case 0x06: /* Get Input Status */ + if(reg_bx==0x00) { /* might work for other handles, but tested it only for STDIN */ + if(Files[handle]->GetInformation() & 0x40) reg_al=0x00; else + reg_al=0xFF; + return true; + break; + } default: LOG_ERROR("DOS:IOCTL Call %2X unhandled",reg_al); return false; @@ -96,7 +103,8 @@ bool DOS_IOCTL(void) { bool DOS_GetSTDINStatus(void) { Bit32u handle=RealHandle(STDIN); - if (Files[handle]->GetInformation() & 64) return false; + if (handle==0xFF) return false; + if (Files[handle] && (Files[handle]->GetInformation() & 64)) return false; return true; }; diff --git a/src/dos/dos_memory.cpp b/src/dos/dos_memory.cpp index 0140655..0fb72a3 100644 --- a/src/dos/dos_memory.cpp +++ b/src/dos/dos_memory.cpp @@ -24,6 +24,7 @@ #define MEM_START 0x60 //First Segment that DOS can use //#define MEM_START 4000 //First Segment that DOS can use +static Bit16u memAllocStrategy = 0x00; static void DOS_CompressMemory(void) { MCB * pmcb;MCB * pmcbnext; @@ -57,6 +58,15 @@ void DOS_FreeProcessMemory(Bit16u pspseg) { DOS_CompressMemory(); }; +Bit16u DOS_GetMemAllocStrategy() +{ + return memAllocStrategy; +}; + +void DOS_SetMemAllocStrategy(Bit16u strat) +{ + memAllocStrategy = strat; +}; bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { MCB * pmcb;MCB * pmcbnext; @@ -77,17 +87,33 @@ bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { *segment=mcb_segment+1; return true; } else { + // TODO: Strategy "1": Best matching block /* If so allocate it */ - pmcbnext=(MCB *)HostMake(mcb_segment+*blocks+1,0); - pmcbnext->psp_segment=MCB_FREE; - pmcbnext->type=pmcb->type; - pmcbnext->size=pmcb->size-*blocks-1; - pmcb->size=*blocks; - pmcb->type=0x4D; - pmcb->psp_segment=dos.psp; - //TODO Filename - *segment=mcb_segment+1; - return true; + if ((memAllocStrategy & 0x03)==0) { + pmcbnext=(MCB *)HostMake(mcb_segment+*blocks+1,0); + pmcbnext->psp_segment=MCB_FREE; + pmcbnext->type=pmcb->type; + pmcbnext->size=pmcb->size-*blocks-1; + pmcb->size=*blocks; + pmcb->type=0x4D; + pmcb->psp_segment=dos.psp; + //TODO Filename + *segment=mcb_segment+1; + return true; + } else { + // * Last Block * + // New created block + *segment = mcb_segment+1+pmcb->size-*blocks; + pmcbnext=(MCB *)HostMake(*segment-1,0); + pmcbnext->size = *blocks; + pmcbnext->type = pmcb->type; + pmcbnext->psp_segment = dos.psp; + // Old Block + pmcb->size = pmcb->size-*blocks-1; + pmcb->psp_segment = MCB_FREE; + pmcb->type = 0x4D; + return true; + }; } } /* Onward to the next MCB if there is one */ diff --git a/src/dos/dos_misc.cpp b/src/dos/dos_misc.cpp index 5280a52..cabfd2a 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -60,11 +60,13 @@ static bool DOS_MultiplexFunctions(void) { //TODO Maybe do some idling but could screw up other systems :) reg_al=0; return true; + case 0x168f: /* Close awareness crap */ + return true; } + return false; } - void DOS_SetupMisc(void) { /* Setup the dos multiplex interrupt */ first_multiplex=0; diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index 1046e12..24b1ce8 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -25,6 +25,7 @@ #include "cross.h" #include "regs.h" #include "callback.h" +#include "../shell/shell_inc.h" class MOUNT : public Program { public: @@ -84,7 +85,8 @@ public: 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); + Bit8u bit8size=(Bit8u) sizes[1]; + newdrive=new localDrive(temp_line.c_str(),sizes[0],bit8size,sizes[2],sizes[3],mediaid); } cmd->FindCommand(1,temp_line); if (temp_line.size()>1) goto showusage; @@ -220,6 +222,69 @@ static void UPCASE_ProgramStart(Program * * make) { } #endif +// LOADFIX + +class LOADFIX : public Program { +public: + void Run(void); +}; + +void LOADFIX::Run(void) +{ + Bit16u commandNr = 1; + Bit16u kb = 64; + if (cmd->FindCommand(commandNr,temp_line)) { + if (temp_line[0]=='-') { + char ch = temp_line[1]; + if ((*upcase(&ch)=='D') || (*upcase(&ch)=='F')) { + // Deallocate all + DOS_FreeProcessMemory(0x40); + WriteOut(MSG_Get("PROGRAM_LOADFIX_DEALLOCALL"),kb); + return; + } else { + // Set mem amount to allocate + kb = atoi(temp_line.c_str()+1); + if (kb==0) kb=64; + commandNr++; + } + } + } + // Allocate Memory + Bit16u segment; + Bit16u blocks = kb*1024/16; + if (DOS_AllocateMemory(&segment,&blocks)) { + MCB* pmcb = (MCB*)HostMake(segment-1,0); + pmcb->psp_segment = 0x40; // use fake segment + WriteOut(MSG_Get("PROGRAM_LOADFIX_ALLOC"),kb); + // Prepare commandline... + if (cmd->FindCommand(commandNr++,temp_line)) { + // get Filename + char filename[128]; + strncpy(filename,temp_line.c_str(),128); + // Setup commandline + bool ok; + char args[256]; + args[0] = 0; + do { + ok = cmd->FindCommand(commandNr++,temp_line); + strncat(args,temp_line.c_str(),256); + strncat(args," ",256); + } while (ok); + // Use shell to start program + DOS_Shell shell; + shell.Execute(filename,args); + DOS_FreeMemory(segment); + WriteOut(MSG_Get("PROGRAM_LOADFIX_DEALLOC"),kb); + } + } else { + WriteOut(MSG_Get("PROGRAM_LOADFIX_ERROR"),kb); + } +}; + +static void LOADFIX_ProgramStart(Program * * make) { + *make=new LOADFIX; +} + void DOS_SetupPrograms(void) { /*Add Messages */ MSG_Add("PROGRAM_MOUNT_STATUS_2","Drive %c is mounted as %s\n"); @@ -233,6 +298,11 @@ void DOS_SetupPrograms(void) { MSG_Add("PROGRAM_MEM_EXTEND","%10d Kb free extended memory\n"); MSG_Add("PROGRAM_MEM_EXPAND","%10d Kb free expanded memory\n"); + MSG_Add("PROGRAM_LOADFIX_ALLOC","%d kb allocated.\n"); + MSG_Add("PROGRAM_LOADFIX_DEALLOC","%d kb freed.\n"); + MSG_Add("PROGRAM_LOADFIX_DEALLOCALL","Used memory freed.\n"); + MSG_Add("PROGRAM_LOADFIX_ERROR","Memory allocation error.\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"); @@ -247,6 +317,7 @@ void DOS_SetupPrograms(void) { /*regular setup*/ PROGRAMS_MakeFile("MOUNT.COM",MOUNT_ProgramStart); PROGRAMS_MakeFile("MEM.COM",MEM_ProgramStart); + PROGRAMS_MakeFile("LOADFIX.COM",LOADFIX_ProgramStart); #if !defined (WIN32) /* Unix */ PROGRAMS_MakeFile("UPCASE.COM",UPCASE_ProgramStart); #endif diff --git a/src/dos/drive_local.cpp b/src/dos/drive_local.cpp index 7dfd868..a12c504 100644 --- a/src/dos/drive_local.cpp +++ b/src/dos/drive_local.cpp @@ -43,7 +43,7 @@ private: }; -bool localDrive:: FileCreate(DOS_File * * file,char * name,Bit16u attributes) { +bool localDrive::FileCreate(DOS_File * * file,char * name,Bit16u attributes) { //TODO Maybe care for attributes but not likely char newname[CROSS_LEN]; strcpy(newname,basedir); @@ -188,6 +188,14 @@ bool localDrive::TestDir(char * dir) { strcpy(newdir,basedir); strcat(newdir,dir); CROSS_FILENAME(newdir); + // Skip directory test, if "\" + Bit16u len = strlen(newdir); + if ((len>0) && (newdir[len-1]!='\\')) { + // It has to be a directory ! + struct stat test; + if (stat(newdir,&test)==-1) return false; + if ((test.st_mode & S_IFDIR)==0) return false; + }; int temp=access(newdir,F_OK); return (temp==0); } @@ -206,7 +214,7 @@ bool localDrive::Rename(char * oldname,char * newname) { }; -bool localDrive::AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) { +bool localDrive::AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) { /* Always report 100 mb free should be enough */ /* Total size is always 1 gb */ *_bytes_sector=allocation.bytes_sector; @@ -251,7 +259,7 @@ Bit8u localDrive::GetMediaByte(void) { return allocation.mediaid; } -localDrive::localDrive(const char * startdir,Bit16u _bytes_sector,Bit16u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid) { +localDrive::localDrive(const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid) { strcpy(basedir,startdir); sprintf(info,"local directory %s",startdir); srch_opendir=NULL; diff --git a/src/dos/drive_virtual.cpp b/src/dos/drive_virtual.cpp index 84235e3..f697c59 100644 --- a/src/dos/drive_virtual.cpp +++ b/src/dos/drive_virtual.cpp @@ -204,7 +204,7 @@ bool Virtual_Drive::Rename(char * oldname,char * newname) { return false; } -bool Virtual_Drive::AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) { +bool Virtual_Drive::AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) { /* Always report 100 mb free should be enough */ /* Total size is always 1 gb */ *_bytes_sector=512; diff --git a/src/dos/drives.cpp b/src/dos/drives.cpp index 2785b18..65d6483 100644 --- a/src/dos/drives.cpp +++ b/src/dos/drives.cpp @@ -63,6 +63,7 @@ bool WildFileCmp(const char * file, const char * wild) r++; } checkext: + r=0; while (r<3) { if (wild_ext[r]=='*') return true; if (wild_ext[r]!='?' && wild_ext[r]!=file_ext[r]) return false; diff --git a/src/dos/drives.h b/src/dos/drives.h index 910f147..90c8fce 100644 --- a/src/dos/drives.h +++ b/src/dos/drives.h @@ -29,7 +29,7 @@ bool WildFileCmp(const char * file, const char * wild); class localDrive : public DOS_Drive { public: - localDrive(const char * startdir,Bit16u _bytes_sector,Bit16u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid); + localDrive(const char * startdir,Bit16u _bytes_sector,Bit8u _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); @@ -40,7 +40,7 @@ public: bool FindNext(DOS_DTA & dta); bool GetFileAttr(char * name,Bit16u * attr); bool Rename(char * oldname,char * newname); - bool AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters); + bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _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); @@ -50,7 +50,7 @@ private: DIR * srch_opendir; struct { Bit16u bytes_sector; - Bit16u sectors_cluster; + Bit8u sectors_cluster; Bit16u total_clusters; Bit16u free_clusters; Bit8u mediaid; @@ -73,7 +73,7 @@ public: bool FindNext(DOS_DTA & dta); bool GetFileAttr(char * name,Bit16u * attr); bool Rename(char * oldname,char * newname); - bool AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters); + bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _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); diff --git a/src/dosbox.cpp b/src/dosbox.cpp index 83ed464..56087e7 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -64,15 +64,20 @@ void KEYBOARD_Init(Section*); //TODO This should setup INT 16 too but ok ;) void JOYSTICK_Init(Section*); void MOUSE_Init(Section*); void SBLASTER_Init(Section*); +void GUS_Init(Section*); void ADLIB_Init(Section*); void PCSPEAKER_Init(Section*); void TANDYSOUND_Init(Section*); void CMS_Init(Section*); +void DISNEY_Init(Section*); + + void PIC_Init(Section*); void TIMER_Init(Section*); void BIOS_Init(Section*); void DEBUG_Init(Section*); +void CMOS_Init(Section*); /* Dos Internal mostly */ void EMS_Init(Section*); @@ -84,27 +89,36 @@ void INT10_Init(Section*); static LoopHandler * loop; +Bitu RemainTicks;; +Bitu LastTicks; + static Bitu Normal_Loop(void) { - Bit32u new_ticks; - new_ticks=GetTicks(); - if (new_ticks>LastTicks) { - Bit32u ticks=new_ticks-LastTicks; - if (ticks>20) ticks=20; - LastTicks=new_ticks; - TIMER_AddTicks(ticks); + Bitu ret,NewTicks; + while (RemainTicks) { + ret=PIC_RunQueue(); + #if C_DEBUG + if (DEBUG_ExitLoop()) return 0; + #endif + if (ret) return ret; + RemainTicks--; + TIMER_AddTick(); + GFX_Events(); } - GFX_Events(); - TIMER_CheckPIT(); - PIC_runIRQs(); - 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; + NewTicks=GetTicks(); + if (NewTicks>LastTicks) { + RemainTicks+=NewTicks-LastTicks; + if (RemainTicks>20) { +// LOG_DEBUG("Ticks to handle overflow %d",RemainTicks); + RemainTicks=20; + } + LastTicks=NewTicks; + } + //TODO Make this selectable in the config file, since it gives some lag */ + if (!RemainTicks) { + SDL_Delay(1); + return 0; + } + return 0; } void DOSBOX_SetLoop(LoopHandler * handler) { @@ -127,7 +141,7 @@ static void DOSBOX_RealInit(Section * sec) { /* Initialize some dosbox internals */ errorlevel=section->Get_int("warnings"); MSG_Add("DOSBOX_CONFIGFILE_HELP","General Dosbox settings\n"); - LastTicks=GetTicks(); + RemainTicks=0;LastTicks=GetTicks(); DOSBOX_SetLoop(&Normal_Loop); MSG_Init(section); } @@ -154,11 +168,14 @@ void DOSBOX_Init(void) { secprop->AddInitFunction(&PIC_Init); secprop->AddInitFunction(&PROGRAMS_Init); secprop->AddInitFunction(&TIMER_Init); - secprop->AddInitFunction(&RENDER_Init); + secprop->AddInitFunction(&CMOS_Init); + secprop=control->AddSection_prop("render",&RENDER_Init); + secprop->Add_int("frameskip",0); + secprop->Add_bool("keepsmall",false); secprop->Add_string("snapshots","snapshots"); secprop=control->AddSection_prop("cpu",&CPU_Init); - secprop->Add_int("cycles",4000); + secprop->Add_int("cycles",1800); secprop->AddInitFunction(&DMA_Init); secprop->AddInitFunction(&VGA_Init); @@ -181,8 +198,13 @@ void DOSBOX_Init(void) { secprop->Add_bool("adlib",true); secprop->AddInitFunction(&CMS_Init); secprop->Add_bool("cms",false); + +// secprop=control->AddSection_prop("gus",&GUS_Init); + secprop=control->AddSection_prop("disney",&DISNEY_Init); + secprop=control->AddSection_prop("speaker",&PCSPEAKER_Init); + secprop->Add_bool("enabled",true); secprop->Add_bool("sinewave",false); secprop->AddInitFunction(&TANDYSOUND_Init); secprop->Add_bool("tandy",false); diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 00fc576..ec0a145 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -1,5 +1,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libgui.a -libgui_a_SOURCES = sdlmain.cpp render.cpp +libgui_a_SOURCES = sdlmain.cpp render.cpp render_support.h diff --git a/src/gui/Makefile.in b/src/gui/Makefile.in index edb51fc..7ec07b9 100644 --- a/src/gui/Makefile.in +++ b/src/gui/Makefile.in @@ -84,7 +84,7 @@ install_sh = @install_sh@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libgui.a -libgui_a_SOURCES = sdlmain.cpp render.cpp +libgui_a_SOURCES = sdlmain.cpp render.cpp render_support.h subdir = src/gui mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h @@ -110,6 +110,11 @@ CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ CXXFLAGS = @CXXFLAGS@ +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ DIST_SOURCES = $(libgui_a_SOURCES) DIST_COMMON = Makefile.am Makefile.in SOURCES = $(libgui_a_SOURCES) diff --git a/src/gui/render.cpp b/src/gui/render.cpp index 0edcb9a..42235c1 100644 --- a/src/gui/render.cpp +++ b/src/gui/render.cpp @@ -26,9 +26,10 @@ #include "keyboard.h" #include "cross.h" + #define MAX_RES 2048 - +typedef void (* RENDER_Part_Handler)(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy); struct PalData { struct { @@ -39,6 +40,10 @@ struct PalData { } rgb[256]; Bitu first; Bitu last; + union { + Bit32u bpp32[256]; + Bit16u bpp16[256]; + } lookup; }; @@ -48,18 +53,40 @@ static struct { Bitu height; Bitu bpp; Bitu pitch; + Bitu flags; float ratio; + RENDER_Part_Handler part_handler; } src; + struct { + Bitu width; + Bitu height; + Bitu pitch; + Bitu next_line; + Bitu next_pixel; + Bitu bpp; /* The type of BPP the operation requires for input */ + RENDER_Operation want_type; + RENDER_Operation type; + void * dest; + void * buffer; + void * pixels; + } op; + struct { + Bitu count; + Bitu max; + } frameskip; Bitu flags; - RENDER_Handler * handler; - Bitu stretch_x[MAX_RES]; - Bitu stretch_y[MAX_RES]; PalData pal; - bool remake; - bool enlarge; + bool keep_small; bool screenshot; + bool active; } render; +/* Forward declerations */ +static void RENDER_ResetPal(void); + +/* Include the different rendering routines */ +#include "render_support.h" + static const char * snapshots_dir; /* Take a screenshot of the data that should be rendered */ @@ -150,7 +177,6 @@ static void TakeScreenShot(Bit8u * bitmap) { /*clean up dynamically allocated RAM.*/ free(row_pointers); - } @@ -158,56 +184,38 @@ static void TakeScreenShot(Bit8u * bitmap) { /* This could go kinda bad with multiple threads */ static void Check_Palette(void) { if (render.pal.first>render.pal.last) return; - - GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]); + switch (render.op.bpp) { + case 8: + GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]); + break; + case 16: + for (;render.pal.first<=render.pal.last;render.pal.first++) { + render.pal.lookup.bpp16[render.pal.first]=GFX_GetRGB( + render.pal.rgb[render.pal.first].red, + render.pal.rgb[render.pal.first].green, + render.pal.rgb[render.pal.first].blue); + } + break; + case 32: + for (;render.pal.first<=render.pal.last;render.pal.first++) { + render.pal.lookup.bpp32[render.pal.first]= + GFX_GetRGB( + render.pal.rgb[render.pal.first].red, + render.pal.rgb[render.pal.first].green, + render.pal.rgb[render.pal.first].blue); + } + break; + }; + /* Setup pal index to startup values */ render.pal.first=256; render.pal.last=0; } -static void MakeTables(void) { - //The stretching tables - Bitu i;Bit32u c,a; - c=0;a=(render.src.width<<16)/gfx_info.width; - for (i=0;i> 16; - } - c=0;a=(render.src.height<<16)/gfx_info.height; - for (i=0;i>16)*render.src.pitch; - } +static void RENDER_ResetPal(void) { + render.pal.first=0; + render.pal.last=255; } -static void Draw_8_Normal(Bit8u * src_data,Bit8u * dst_data) { - for (Bitu y=0;y0) render.frameskip.max--; + LOG_MSG("Frame Skip at %d",render.frameskip.max); +} + + 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.keep_small=section->Get_bool("keepsmall"); + render.frameskip.max=section->Get_int("frameskip"); + render.frameskip.count=0; KEYBOARD_AddEvent(KBD_f5,CTRL_PRESSED,EnableScreenShot); + KEYBOARD_AddEvent(KBD_f7,CTRL_PRESSED,DecreaseFrameSkip); + KEYBOARD_AddEvent(KBD_f8,CTRL_PRESSED,IncreaseFrameSkip); } diff --git a/src/gui/render_support.h b/src/gui/render_support.h new file mode 100644 index 0000000..3d91cb0 --- /dev/null +++ b/src/gui/render_support.h @@ -0,0 +1,228 @@ +static void Render_Normal_8_None(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=render.op.pitch-dx; + Bitu rem=dx&3;dx>>=2; + for (;dy>0;dy--) { + Bitu tempx; + for (tempx=dx;tempx>0;tempx--) { + Bit32u temp=*(Bit32u *)src;src+=4; + *(Bit32u *)dest=temp; + dest+=4; + } + for (tempx=rem;tempx>0;tempx--) { + *dest++=*src++; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_8_DoubleWidth(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x*2; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=render.op.pitch-dx*2; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + *dest=*src;*(dest+1)=*src; + src++;dest+=2; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_8_DoubleHeight(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch+x; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=(2*render.op.pitch)-dx; + Bitu rem=dx&3;dx>>=2; + for (;dy>0;dy--) { + Bitu tempx; + for (tempx=dx;tempx>0;tempx--) { + Bit32u temp=*(Bit32u *)src;src+=4; + *(Bit32u *)dest=temp; + *(Bit32u *)(dest+render.op.pitch)=temp; + dest+=4; + } + for (tempx=rem;tempx>0;tempx--) { + *dest=*src; + *(dest+render.op.pitch)=*src; + dest++; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_8_DoubleBoth(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=(2*render.op.pitch)-dx*2; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit8u val=src[0];src++; + dest[0]=val;dest[1]=val; + dest[render.op.pitch]=val;dest[render.op.pitch+1]=val; + dest+=2; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_16_None(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=render.op.pitch-dx*2; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit16u val=render.pal.lookup.bpp16[src[0]];src++; + *(Bit16u *)dest=val; + dest+=2; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_16_DoubleWidth(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x*4; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=render.op.pitch-dx*4; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit16u val=render.pal.lookup.bpp16[src[0]];src++; + *(Bit16u *)dest=val; + *(Bit16u *)(dest+2)=val; + dest+=4; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_16_DoubleHeight(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch+x*2; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=(2*render.op.pitch)-dx*2; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit16u val=render.pal.lookup.bpp16[src[0]];src++; + *(Bit16u *)dest=val; + *(Bit16u *)(dest+render.op.pitch)=val; + dest+=2; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_16_DoubleBoth(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch+x*4; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=(2*render.op.pitch)-dx*4; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit16u val=render.pal.lookup.bpp16[src[0]];src++; + *(Bit16u *)(dest+0)=val; + *(Bit16u *)(dest+2)=val; + *(Bit16u *)(dest+render.op.pitch)=val; + *(Bit16u *)(dest+render.op.pitch+2)=val; + dest+=4; + } + src+=next_src;dest+=next_dest; + } +} + + +static void Render_Normal_32_None(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x*4; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=render.op.pitch-dx*4; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit32u val=render.pal.lookup.bpp32[src[0]];src++; + *(Bit32u *)dest=val; + dest+=4; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_32_DoubleWidth(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+y*render.op.pitch+x*8; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=render.op.pitch-dx*8; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit32u val=render.pal.lookup.bpp32[src[0]];src++; + *(Bit32u *)dest=val; + *(Bit32u *)(dest+4)=val; + dest+=8; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_32_DoubleHeight(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch+x*4; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=(2*render.op.pitch)-dx*4; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit32u val=render.pal.lookup.bpp32[src[0]];src++; + *(Bit32u *)dest=val; + *(Bit32u *)(dest+render.op.pitch)=val; + dest+=4; + } + src+=next_src;dest+=next_dest; + } +} + +static void Render_Normal_32_DoubleBoth(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) { + Bit8u * dest=(Bit8u *)render.op.pixels+2*y*render.op.pitch+x*8; + Bitu next_src=render.src.pitch-dx; + Bitu next_dest=(2*render.op.pitch)-dx*8; + for (;dy>0;dy--) { + for (Bitu tempx=dx;tempx>0;tempx--) { + Bit32u val=render.pal.lookup.bpp32[src[0]];src++; + *(Bit32u *)(dest+0)=val; + *(Bit32u *)(dest+4)=val; + *(Bit32u *)(dest+render.op.pitch)=val; + *(Bit32u *)(dest+render.op.pitch+4)=val; + dest+=8; + } + src+=next_src;dest+=next_dest; + } +} + + +static RENDER_Part_Handler Render_Normal_8_Table[4]= { + Render_Normal_8_None,Render_Normal_8_DoubleWidth,Render_Normal_8_DoubleHeight,Render_Normal_8_DoubleBoth +}; + +static RENDER_Part_Handler Render_Normal_16_Table[4]= { + Render_Normal_16_None,Render_Normal_16_DoubleWidth,Render_Normal_16_DoubleHeight,Render_Normal_16_DoubleBoth +}; + +static RENDER_Part_Handler Render_Normal_32_Table[4]= { + Render_Normal_32_None,Render_Normal_32_DoubleWidth,Render_Normal_32_DoubleHeight,Render_Normal_32_DoubleBoth +}; + + +static void Render_Normal_CallBack(Bitu width,Bitu height,Bitu bpp,Bitu pitch,Bitu flags) { + if (!(flags & MODE_SET)) return; + render.op.width=width; + render.op.height=height; + render.op.bpp=bpp; + render.op.pitch=pitch; + switch (bpp) { + case 8: + render.src.part_handler=Render_Normal_8_Table[render.src.flags]; + break; + case 16: + render.src.part_handler=Render_Normal_16_Table[render.src.flags]; + break; + case 32: + render.src.part_handler=Render_Normal_32_Table[render.src.flags]; + break; + default: + E_Exit("RENDER:Unsupported display depth of %d",bpp); + break; + } + RENDER_ResetPal(); +} diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 7da7a2d..41b81fa 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include "dosbox.h" #include "video.h" @@ -33,20 +32,16 @@ //#define DISABLE_JOYSTICK - struct SDL_Block { bool active; //If this isn't set don't draw Bitu width; Bitu height; Bitu bpp; - GFX_DrawHandler * draw; - GFX_ResizeHandler * resize; + Bitu flags; + GFX_ModeCallBack mode_callback; bool full_screen; - SDL_Thread * thread; - SDL_mutex * mutex; SDL_Surface * surface; SDL_Joystick * joy; - SDL_Color pal[256]; struct { bool autolock; bool autoenable; @@ -54,62 +49,48 @@ struct SDL_Block { bool locked; Bitu sensitivity; } mouse; - struct { - Bitu skip; - Bitu count; - } frames ; }; static SDL_Block sdl; +static void CaptureMouse(void); -GFX_Info gfx_info; - -static void RestorePalette(void) { - if (sdl.bpp!=8) return; -/* Use some other way of doing this */ - if (sdl.full_screen) { - if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,sdl.pal,0,256)) { - E_Exit("SDL:Can't set palette"); - } - } else { - if (!SDL_SetPalette(sdl.surface,SDL_LOGPAL,sdl.pal,0,256)) { - E_Exit("SDL:Can't set palette"); - } - } - return; -} /* Reset the screen with current values in the sdl structure */ static void ResetScreen(void) { + GFX_Stop(); if (sdl.full_screen) { /* First get the original resolution */ - sdl.surface=SDL_SetVideoMode(sdl.width,sdl.height,sdl.bpp,SDL_HWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN|SDL_DOUBLEBUF); + sdl.surface=SDL_SetVideoMode(sdl.width,sdl.height,sdl.bpp,SDL_HWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN); } else { - sdl.surface=SDL_SetVideoMode(sdl.width,sdl.height,sdl.bpp,SDL_SWSURFACE|SDL_RESIZABLE); + if (sdl.flags & GFX_FIXED_BPP) sdl.surface=SDL_SetVideoMode(sdl.width,sdl.height,sdl.bpp,SDL_HWSURFACE); + else sdl.surface=SDL_SetVideoMode(sdl.width,sdl.height,0,SDL_HWSURFACE); } if (sdl.surface==0) { E_Exit("SDL:Would be nice if I could get a surface."); } SDL_WM_SetCaption(VERSION,VERSION); /* also fill up gfx_info structure */ - gfx_info.width=sdl.width; - gfx_info.height=sdl.height; - gfx_info.bpp=sdl.bpp; - gfx_info.pitch=sdl.surface->pitch; - RestorePalette(); + Bitu flags=MODE_SET; + if (sdl.full_screen) flags|=MODE_FULLSCREEN; + if (sdl.mode_callback) sdl.mode_callback(sdl.surface->w,sdl.surface->h,sdl.surface->format->BitsPerPixel,sdl.surface->pitch,flags); + GFX_Start(); } -void GFX_Resize(Bitu width,Bitu height,Bitu bpp,GFX_ResizeHandler * resize) { +void GFX_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu flags,GFX_ModeCallBack callback) { GFX_Stop(); sdl.width=width; sdl.height=height; sdl.bpp=bpp; - sdl.resize=resize; + sdl.flags=flags; + sdl.mode_callback=callback; ResetScreen(); GFX_Start(); } -static void CaptureMouse() { + + + +static void CaptureMouse(void) { sdl.mouse.locked=!sdl.mouse.locked; if (sdl.mouse.locked) { SDL_WM_GrabInput(SDL_GRAB_ON); @@ -120,72 +101,40 @@ 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; if (sdl.full_screen) { - if (sdl.resize) { - sdl.width=0;sdl.height=0; - (*sdl.resize)(&sdl.width,&sdl.height); - } +//TODO Give an resize event + if (!sdl.mouse.locked) CaptureMouse(); + } else { + if (sdl.mouse.locked) CaptureMouse(); } + ResetScreen(); - GFX_Start(); } //only prototype existed void GFX_SwitchFullScreen(void) { SwitchFullScreen(); } -static void GFX_Redraw() { -#if C_THREADED - if (SDL_mutexP(sdl.mutex)) { - E_Exit("Can't Lock Mutex"); - }; -#endif - - if (++sdl.frames.countpixels && sdl.draw) (*sdl.draw)((Bit8u *)sdl.surface->pixels); - SDL_UnlockSurface(sdl.surface ); - 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"); + if (SDL_MUSTLOCK(sdl.surface)) if (SDL_LockSurface(sdl.surface)) return 0; + return sdl.surface->pixels; + } else { + return 0; } -#endif } -static int SDLGFX_Thread(void * data) { - do { - GFX_Redraw(); - SDL_Delay(1000/70); - } while (true); - return 1; +void GFX_EndUpdate(void) { + if (SDL_MUSTLOCK(sdl.surface)) SDL_UnlockSurface(sdl.surface ); + if (sdl.full_screen) SDL_Flip(sdl.surface); + else SDL_UpdateRect(sdl.surface,0,0,0,0); } + void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) { /* I should probably not change the GFX_PalEntry :) */ -#if C_THREADED - if (SDL_mutexP(sdl.mutex)) { - E_Exit("SDL:Can't Lock Mutex"); - }; -#endif if (sdl.full_screen) { if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,(SDL_Color *)entries,start,count)) { E_Exit("SDL:Can't set palette"); @@ -195,27 +144,14 @@ void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) { E_Exit("SDL:Can't set palette"); } } - /* Copy palette entries into some internal back up table */ -#if C_THREADED - if (SDL_mutexV(sdl.mutex)) { - E_Exit("SDL:Can't Release Mutex"); - } -#endif - memcpy(&sdl.pal[start],entries,count*sizeof(SDL_Color)); } -void GFX_SetDrawHandler(GFX_DrawHandler * handler) { - sdl.draw=handler; +Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue) { + return SDL_MapRGB(sdl.surface->format,red,green,blue); } void GFX_Stop() { -#if C_THREADED - SDL_mutexP(sdl.mutex); -#endif sdl.active=false; -#if C_THREADED - SDL_mutexV(sdl.mutex); -#endif } @@ -235,27 +171,16 @@ static void GUI_StartUp(Section * sec) { 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_SetSize(640,400,8,0,0); SDL_EnableKeyRepeat(250,30); /* Get some Keybinds */ 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); } @@ -409,7 +334,11 @@ static void HandleMouseMotion(SDL_MouseMotionEvent * motion) { static void HandleMouseButton(SDL_MouseButtonEvent * button) { switch (button->state) { case SDL_PRESSED: - if (sdl.mouse.requestlock && !sdl.mouse.locked) CaptureMouse(); + if (sdl.mouse.requestlock && !sdl.mouse.locked) { + CaptureMouse(); + // Dont pass klick to mouse handler + break; + } switch (button->button) { case SDL_BUTTON_LEFT: Mouse_ButtonPressed(0); @@ -459,17 +388,11 @@ static void HandleJoystickButton(SDL_JoyButtonEvent * jbutton) { static void HandleVideoResize(SDL_ResizeEvent * resize) { - Bitu width,height; - width=resize->w; - height=resize->h; - if (sdl.resize) { - GFX_Stop(); - (*sdl.resize)(&width,&height); - sdl.width=width; - sdl.height=height; - ResetScreen(); - GFX_Start(); - } + + + + + } void GFX_Events() { @@ -568,8 +491,11 @@ int main(int argc, char* argv[]) { control->StartUp(); /* Shutdown everything */ } catch (char * error) { + if (sdl.full_screen) SwitchFullScreen(); + if (sdl.mouse.locked) CaptureMouse(); LOG_MSG("Exit to error: %sPress enter to continue.",error); fgetc(stdin); } + GFX_ShutDown(); return 0; }; diff --git a/src/hardware/Makefile.am b/src/hardware/Makefile.am index 8f6507d..737c3eb 100644 --- a/src/hardware/Makefile.am +++ b/src/hardware/Makefile.am @@ -7,5 +7,6 @@ noinst_LIBRARIES = libhardware.a libhardware_a_SOURCES = adlib.cpp dma.cpp gameblaster.cpp hardware.cpp iohandler.cpp joystick.cpp keyboard.cpp \ memory.cpp mixer.cpp pcspeaker.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \ vga.cpp vga.h vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_fonts.cpp vga_gfx.cpp \ - vga_memory.cpp vga_misc.cpp vga_seq.cpp font-switch.h ega-switch.h + vga_memory.cpp vga_misc.cpp vga_seq.cpp font-switch.h ega-switch.h cmos.cpp disney.cpp \ + gus.cpp diff --git a/src/hardware/Makefile.in b/src/hardware/Makefile.in index 3ef7bf2..179e9ef 100644 --- a/src/hardware/Makefile.in +++ b/src/hardware/Makefile.in @@ -90,7 +90,8 @@ noinst_LIBRARIES = libhardware.a libhardware_a_SOURCES = adlib.cpp dma.cpp gameblaster.cpp hardware.cpp iohandler.cpp joystick.cpp keyboard.cpp \ memory.cpp mixer.cpp pcspeaker.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \ vga.cpp vga.h vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_fonts.cpp vga_gfx.cpp \ - vga_memory.cpp vga_misc.cpp vga_seq.cpp font-switch.h ega-switch.h + vga_memory.cpp vga_misc.cpp vga_seq.cpp font-switch.h ega-switch.h cmos.cpp disney.cpp \ + gus.cpp subdir = src/hardware mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -108,7 +109,7 @@ am_libhardware_a_OBJECTS = adlib.$(OBJEXT) dma.$(OBJEXT) \ vga.$(OBJEXT) vga_attr.$(OBJEXT) vga_crtc.$(OBJEXT) \ vga_dac.$(OBJEXT) vga_draw.$(OBJEXT) vga_fonts.$(OBJEXT) \ vga_gfx.$(OBJEXT) vga_memory.$(OBJEXT) vga_misc.$(OBJEXT) \ - vga_seq.$(OBJEXT) + vga_seq.$(OBJEXT) cmos.$(OBJEXT) disney.$(OBJEXT) gus.$(OBJEXT) libhardware_a_OBJECTS = $(am_libhardware_a_OBJECTS) DEFS = @DEFS@ @@ -118,18 +119,20 @@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles -@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/adlib.Po ./$(DEPDIR)/dma.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/gameblaster.Po ./$(DEPDIR)/hardware.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/iohandler.Po ./$(DEPDIR)/joystick.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/keyboard.Po ./$(DEPDIR)/memory.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/mixer.Po ./$(DEPDIR)/pcspeaker.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/pic.Po ./$(DEPDIR)/sblaster.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/tandy_sound.Po ./$(DEPDIR)/timer.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/vga.Po ./$(DEPDIR)/vga_attr.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/vga_crtc.Po ./$(DEPDIR)/vga_dac.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/vga_draw.Po ./$(DEPDIR)/vga_fonts.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/vga_gfx.Po ./$(DEPDIR)/vga_memory.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/vga_misc.Po ./$(DEPDIR)/vga_seq.Po +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/adlib.Po ./$(DEPDIR)/cmos.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/disney.Po ./$(DEPDIR)/dma.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/gameblaster.Po ./$(DEPDIR)/gus.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/hardware.Po ./$(DEPDIR)/iohandler.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/joystick.Po ./$(DEPDIR)/keyboard.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/memory.Po ./$(DEPDIR)/mixer.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/pcspeaker.Po ./$(DEPDIR)/pic.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/sblaster.Po ./$(DEPDIR)/tandy_sound.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/timer.Po ./$(DEPDIR)/vga.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vga_attr.Po ./$(DEPDIR)/vga_crtc.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vga_dac.Po ./$(DEPDIR)/vga_draw.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vga_fonts.Po ./$(DEPDIR)/vga_gfx.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vga_memory.Po ./$(DEPDIR)/vga_misc.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/vga_seq.Po CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) @@ -171,8 +174,11 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adlib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmos.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/disney.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dma.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gameblaster.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hardware.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iohandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joystick.Po@am__quote@ diff --git a/src/hardware/adlib.cpp b/src/hardware/adlib.cpp index 87e3630..dc8bb48 100644 --- a/src/hardware/adlib.cpp +++ b/src/hardware/adlib.cpp @@ -22,7 +22,7 @@ #include "dosbox.h" #include "inout.h" #include "mixer.h" -#include "timer.h" +#include "pic.h" #include "hardware.h" #include "setup.h" /* @@ -32,27 +32,45 @@ namespace MAME { /* Defines */ # define logerror(x) - /* Disable recurring warnings */ -#pragma warning ( disable : 4018 ) -#pragma warning ( disable : 4244 ) - /* Bring in Tatsuyuki Satoh's OPL emulation */ -#define HAS_YM3812 1 -#include "fmopl.c" + /* Disable recurring warnings */ +# pragma warning ( disable : 4018 ) +# pragma warning ( disable : 4244 ) + + /* Work around ANSI compliance problem (see driver.h) */ + struct __MALLOCPTR { + void* m_ptr; + + __MALLOCPTR(void) : m_ptr(NULL) { } + __MALLOCPTR(void* src) : m_ptr(src) { } + void* operator=(void* rhs) { return (m_ptr = rhs); } + operator int*() const { return (int*)m_ptr; } + operator int**() const { return (int**)m_ptr; } + operator char*() const { return (char*)m_ptr; } + }; + + /* Bring in the MAME OPL emulation */ +# define HAS_YM3812 1 +# include "fmopl.c" + } + struct OPLTimer_t { bool isEnabled; bool isMasked; bool isOverflowed; - Bit32u count; - Bit32u base; + Bit64u count; + Bit64u base; }; static OPLTimer_t timer1,timer2; -static MAME::FM_OPL * myopl; static Bit8u regsel; + #define OPL_INTERNAL_FREQ 3600000 // The OPL operates at 3.6MHz +#define OPL_NUM_CHIPS 1 // Number of OPL chips +#define OPL_CHIP0 0 + static MIXER_Channel * adlib_chan; static void ADLIB_CallBack(Bit8u *stream, Bit32u len) { @@ -60,25 +78,25 @@ static void ADLIB_CallBack(Bit8u *stream, Bit32u len) { /* Calculate teh machine ms we are at now */ /* update 1 ms of data */ - MAME::YM3812UpdateOne(myopl,(MAME::INT16 *)stream,len); + MAME::YM3812UpdateOne(0,(MAME::INT16 *)stream,len); } static Bit8u read_p388(Bit32u port) { Bit8u ret=0; - Bit32u new_ticks=GetTicks(); + Bit64u micro=PIC_MicroCount(); if (timer1.isEnabled) { - if ((new_ticks-timer1.base)>timer1.count) { + if ((micro-timer1.base)>timer1.count) { timer1.isOverflowed=true; - timer1.base=new_ticks; + timer1.base=micro; } if (timer1.isOverflowed || !timer1.isMasked) { ret|=0xc0; } } if (timer2.isEnabled) { - if ((new_ticks-timer2.base)>timer2.count) { + if ((micro-timer2.base)>timer2.count) { timer2.isOverflowed=true; - timer2.base=new_ticks; + timer2.base=micro; } if (timer2.isOverflowed || !timer2.isMasked) { ret|=0xA0; @@ -94,10 +112,10 @@ static void write_p388(Bit32u port,Bit8u val) { static void write_p389(Bit32u port,Bit8u val) { switch (regsel) { case 0x02: /* Timer 1 */ - timer1.count=(val*80/1000); + timer1.count=val*80; return; case 0x03: /* Timer 2 */ - timer2.count=(val*320/1000); + timer2.count=val*320; return; case 0x04: /* IRQ clear / mask and Timer enable */ if (val&0x80) { @@ -105,25 +123,24 @@ static void write_p389(Bit32u port,Bit8u val) { timer2.isOverflowed=false; return; } - if (val&0x40) { - timer1.isMasked=true; - } else { - timer1.isMasked=false; - timer1.isEnabled=((val&1)>0); - timer1.base=GetTicks(); - } - if (val&0x20) { - timer2.isMasked=true; - } else { - timer2.isMasked=false; - timer2.isEnabled=((val&2)>0); - timer2.base=GetTicks(); - } + if (val&0x40) timer1.isMasked=true; + else timer1.isMasked=false; + + if (val&1) { + timer1.isEnabled=true; + timer1.base=PIC_MicroCount(); + } else timer1.isEnabled=false; + if (val&0x20) timer2.isMasked=true; + else timer2.isMasked=false; + if (val&2) { + timer2.isEnabled=true; + timer2.base=PIC_MicroCount(); + } else timer2.isEnabled=false; return; default: /* Normal OPL call queue it */ - MAME::OPLWriteReg(myopl,regsel,val); + /* Use a little hack to directly write to the register */ + MAME::OPLWriteReg(MAME::OPL_YM3812[0],regsel,val); } - } static bool adlib_enabled; @@ -169,7 +186,10 @@ void ADLIB_Init(Section* sec) { timer2.isOverflowed=false; #define ADLIB_FREQ 22050 - myopl=MAME::OPLCreate(0,OPL_INTERNAL_FREQ,ADLIB_FREQ); + if (MAME::YM3812Init(OPL_NUM_CHIPS,OPL_INTERNAL_FREQ,ADLIB_FREQ)) { + E_Exit("Can't create adlib OPL Emulator"); + }; + adlib_chan=MIXER_AddChannel(ADLIB_CallBack,ADLIB_FREQ,"ADLIB"); MIXER_SetMode(adlib_chan,MIXER_16MONO); diff --git a/src/hardware/cmos.cpp b/src/hardware/cmos.cpp new file mode 100644 index 0000000..9c20f9e --- /dev/null +++ b/src/hardware/cmos.cpp @@ -0,0 +1,118 @@ +/* + * 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 "dosbox.h" +#include "timer.h" +#include "pic.h" +#include "inout.h" +#include "config.h" + +static struct { + + Bit8u regs[0x40]; + bool nmi; + Bit8u reg; + struct { + bool enabled; + Bit8u div; + Bitu micro; + } timer; + Bit8u status_c; + bool ack; + bool update_ended; + +} cmos; + +static void cmos_timerevent(void) { + PIC_ActivateIRQ(8); + if (cmos.ack) { + PIC_AddEvent(cmos_timerevent,cmos.timer.micro); + cmos.status_c=0x20; + cmos.ack=false; + } +} + +static void cmos_checktimer(void) { + PIC_RemoveEvents(cmos_timerevent); + if (!cmos.timer.div && !cmos.timer.enabled) return; + if (cmos.timer.div<=2) cmos.timer.div+=7; + cmos.timer.micro=(Bitu) (10000000.0/(32768.0 / (1 << (cmos.timer.div - 1)))); + LOG_DEBUG("RTC Timer at %f hz",1000000.0/cmos.timer.micro); + PIC_AddEvent(cmos_timerevent,cmos.timer.micro); +} + +void cmos_selreg(Bit32u port,Bit8u val) { + cmos.reg=val & 0x3f; + cmos.nmi=(val & 0x80)>0; +} + +static void cmos_writereg(Bit32u port,Bit8u val) { + switch (cmos.reg) { + case 0x00: /* Seconds */ + case 0x01: /* Seconds Alarm */ + case 0x02: /* Minutes */ + case 0x03: /* Minutes Alarm */ + case 0x04: /* Hours */ + case 0x05: /* Hours Alarm */ + case 0x06: /* Day of week */ + case 0x07: /* Date of month */ + case 0x08: /* Month */ + case 0x09: /* Year */ + cmos.regs[cmos.reg]=val; + break; + case 0x0a: /* Status reg A */ + cmos.regs[cmos.reg]=val & 0x7f; + if (val & 0x70!=0x20) LOG_DEBUG("CMOS Illegal 22 stage divider value"); + cmos.timer.div=(val & 0xf); + cmos_checktimer(); + break; + case 0x0b: /* Status reg B */ + cmos.regs[cmos.reg]=val & 0x7f; + cmos.timer.enabled=(val & 0x40)>0; + if (val&0x10) LOG_DEBUG("CMOS:Updated ended interrupt not supported yet"); + cmos_checktimer(); + break; + default: + cmos.regs[cmos.reg]=val & 0x7f; + LOG_DEBUG("CMOS:Unhandled register %x",cmos.reg); + } +} + +static Bit8u cmos_readreg(Bit32u port) { + if (cmos.reg>0x3f) { + LOG_DEBUG("CMOS:Read from illegal register %x",cmos.reg); + return 0xff; + } + switch (cmos.reg) { + case 0x0c: + if (cmos.ack) return 0; + else { + cmos.ack=true; + return 0x80|cmos.status_c; + } + default: + return cmos.regs[cmos.reg]; + } +} + +void CMOS_Init(Section* sec) { + IO_RegisterWriteHandler(0x70,cmos_selreg,"CMOS"); + IO_RegisterWriteHandler(0x71,cmos_writereg,"CMOS"); + IO_RegisterReadHandler(0x71,cmos_readreg,"CMOS"); + cmos.timer.enabled=false; +} \ No newline at end of file diff --git a/src/hardware/disney.cpp b/src/hardware/disney.cpp new file mode 100644 index 0000000..0e2291c --- /dev/null +++ b/src/hardware/disney.cpp @@ -0,0 +1,102 @@ +#include +#include "dosbox.h" +#include "inout.h" +#include "mixer.h" +#include "dma.h" +#include "pic.h" +#include "hardware.h" +#include "setup.h" +#include "programs.h" + + + +#define DISNEY_BASE 0x0378 + +#define DISNEY_SIZE 32 + +static struct { + Bit8u data; + Bit8u status; + Bit8u control; + Bit8u buffer[DISNEY_SIZE]; + Bitu used; + bool enabled; + Bit8u delay; + MIXER_Channel * chan; +} disney; + +static void disney_write(Bit32u port,Bit8u val) { + switch (port-DISNEY_BASE) { + case 0: /* Data Port */ + disney.data=val; + break; + case 1: /* Status Port */ + LOG_WARN("DISNEY:Status write %x",val); + break; + case 2: /* Control Port */ +// LOG_WARN("DISNEY:Control write %x",val); + if (val&0x8) { + if (disney.used=16) return 0x40; + else return 0x0; + break; + case 2: /* Control Port */ + LOG_WARN("DISNEY:Read from control port"); + return disney.control; + break; + } + return 0xff; +} + + +static void DISNEY_CallBack(Bit8u * stream,Bit32u len) { + if (!len) return; + if (disney.used>len) { + memcpy(stream,disney.buffer,len); + memmove(disney.buffer,&disney.buffer[len],disney.used-len); + disney.used-=len; + return; + } else { + memcpy(stream,disney.buffer,disney.used); + memset(stream+disney.used,0x80,len-disney.used); + disney.used=0; + } +} + + +void DISNEY_Init(Section* sec) { + IO_RegisterWriteHandler(DISNEY_BASE,disney_write,"DISNEY"); + IO_RegisterWriteHandler(DISNEY_BASE+1,disney_write,"DISNEY"); + IO_RegisterWriteHandler(DISNEY_BASE+2,disney_write,"DISNEY"); + + IO_RegisterReadHandler(DISNEY_BASE,disney_read,"DISNEY"); + IO_RegisterReadHandler(DISNEY_BASE+1,disney_read,"DISNEY"); + IO_RegisterReadHandler(DISNEY_BASE+2,disney_read,"DISNEY"); + + disney.chan=MIXER_AddChannel(&DISNEY_CallBack,7000,"DISNEY"); + MIXER_SetMode(disney.chan,MIXER_8MONO); + MIXER_Enable(disney.chan,true); + + disney.status=0x84; + disney.control=0; + disney.used=0; +} + diff --git a/src/hardware/dma.cpp b/src/hardware/dma.cpp index eb317d4..c2e9aea 100644 --- a/src/hardware/dma.cpp +++ b/src/hardware/dma.cpp @@ -83,14 +83,20 @@ static Bit8u read_dma(Bit32u port) { ret=(chan->current_address>>8)&0xff; } cont->flipflop=!cont->flipflop; + break; case 0x01:case 0x03:case 0x05:case 0x07: if (cont->flipflop) { - ret=(chan->current_count-1) & 0xff; + ret=(Bit8u)((chan->current_count-1) & 0xff); } else { - ret=((chan->current_count-1)>>8)&0xff; + ret=(Bit8u)(((chan->current_count-1)>>8)&0xff); } cont->flipflop=!cont->flipflop; break; + case 0x08: /* Read Status */ + ret=cont->status_reg; + cont->status_reg&=0xf; /* Clear lower 4 bits on read */ + break; + default: LOG_WARN("DMA:Unhandled read from %d",port); } @@ -105,18 +111,18 @@ static void write_dma(Bit32u port,Bit8u val) { switch (port) { case 0x00:case 0x02:case 0x04:case 0x06: if (cont->flipflop) { - chan->base_address=val; + chan->base_address=(chan->base_address & 0xff00) | val; } else { - chan->base_address|=(val<<8); + chan->base_address=(chan->base_address & 0x00ff) | (val<<8); } cont->flipflop=!cont->flipflop; chan->addr_changed=true; break; case 0x01:case 0x03:case 0x05:case 0x07: if (cont->flipflop) { - chan->base_count=val; + chan->base_count=(chan->base_count & 0xff00) | val; } else { - chan->base_count|=(val<<8); + chan->base_count=(chan->base_count & 0x00ff) | (val<<8); } cont->flipflop=!cont->flipflop; chan->addr_changed=true; @@ -128,6 +134,8 @@ static void write_dma(Bit32u port,Bit8u val) { case 0x09: /* Request Register */ if (val&4) { /* Set Request bit */ + Bitu channel = val & 0x03; + cont->status_reg |= (1 << (channel+4)); } else { Bitu channel = val & 0x03; cont->status_reg &= ~(1 << (channel+4)); @@ -153,19 +161,20 @@ static void write_dma(Bit32u port,Bit8u val) { }; -static Bit8u channelindex[7] = {2, 3, 1, 0, 0, 0, 0}; void write_dma_page(Bit32u port,Bit8u val) { - + Bitu channel; switch (port) { case 0x81: /* dma0 page register, channel 2 */ + channel=2;break; case 0x82: /* dma0 page register, channel 3 */ + channel=3;break; case 0x83: /* dma0 page register, channel 1 */ + channel=1;break; case 0x87: /* dma0 page register, channel 0 */ - Bitu channel = channelindex[port - 0x81]; - dma[0].chan[channel].page=val; - dma[0].chan[channel].addr_changed=true; - break; + channel=0;break; } + dma[0].chan[channel].page=val; + dma[0].chan[channel].addr_changed=true; } Bit16u DMA_8_Read(Bit32u dmachan,Bit8u * buffer,Bit16u count) { @@ -183,7 +192,7 @@ Bit16u DMA_8_Read(Bit32u dmachan,Bit8u * buffer,Bit16u count) { chan->current_address=chan->base_address; DMA_DEBUG("DMA:Transfer from %d size %d",(chan->page << 16)+chan->base_address,chan->current_count); } - if (chan->current_count>=count) { + if (chan->current_count>count) { MEM_BlockRead(chan->address,buffer,count); chan->address+=count; chan->current_address+=count; @@ -192,18 +201,27 @@ Bit16u DMA_8_Read(Bit32u dmachan,Bit8u * buffer,Bit16u count) { } else { /* Copy remaining piece of first buffer */ MEM_BlockRead(chan->address,buffer,chan->current_count); - buffer+=chan->current_count; - count-=(Bit16u)chan->current_count; - /* Autoinit reset the dma channel */ - chan->address=(chan->page << 16)+chan->base_address; - chan->current_count=chan->base_count+1; - chan->current_address=chan->base_address; - /* Copy the rest of the buffer */ - MEM_BlockRead(chan->address,buffer,count); - chan->address+=count; - chan->current_address+=count; - chan->current_count-=count; - return count; + if (!chan->mode.autoinit_enable) { + /* Set the end of counter bit */ + dma[0].status_reg|=(1 << dmachan); + count=(Bit16u)chan->current_count; + chan->current_address+=count;; + chan->current_count=0; + return count; + } else { + buffer+=chan->current_count; + Bit16u left=count-(Bit16u)chan->current_count; + /* Autoinit reset the dma channel */ + chan->address=(chan->page << 16)+chan->base_address; + chan->current_count=chan->base_count+1; + chan->current_address=chan->base_address; + /* Copy the rest of the buffer */ + MEM_BlockRead(chan->address,buffer,left); + chan->address+=left; + chan->current_address+=left; + chan->current_count-=left; + return count; + } } }; diff --git a/src/hardware/fmopl.c b/src/hardware/fmopl.c index 2f73d7d..ebc9792 100644 --- a/src/hardware/fmopl.c +++ b/src/hardware/fmopl.c @@ -4,17 +4,26 @@ ** types OPL and OPL2 ** ** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmulator development -** (c) 2002 Jarek Burczynski +** Copyright (C) 2002 Jarek Burczynski ** -** Version 0.58 +** Version 0.60 ** Revision History: +04-28-2002 Jarek Burczynski: + - binary exact Envelope Generator (verified on real YM3812); + compared to YM2151: the EG clock is equal to internal_clock, + rates are 2 times slower and volume resolution is one bit less + - modified interface functions (they no longer return pointer - + that's internal to the emulator now): + - new wrapper functions for OPLCreate: YM3526Init(), YM3812Init() and Y8950Init() + - corrected 'off by one' error in feedback calculations (when feedback is off) + - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) + - speeded up noise generator calculations (Nicola Salmoria) + 03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) - Complete rewrite (all verified on real YM3812): - - corrected sin_tab and tl_tab data - corrected operator output calculations - corrected waveform_select_enable register; @@ -35,7 +44,6 @@ Revision History: - fixed subscription range of attack/decay tables - To do: add delay before key off in CSM mode (see CSMKeyControll) verify volume of the FM part on the Y8950 @@ -55,8 +63,6 @@ Revision History: - - /* output final shift */ #if (OPL_SAMPLE_BITS==16) #define FINAL_SH (0) @@ -70,20 +76,19 @@ Revision History: #define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define ENV_SH 16 /* 16.16 fixed point (envelope calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ #define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ #define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ #define FREQ_MASK ((1<>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency counter */ + UINT32 Incr; /* frequency counter step */ + UINT8 FB; /* feedback shift value */ + INT32 *connect1; /* slot1 output pointer */ + INT32 op1_out[2]; /* slot1 output for feedback */ + UINT8 CON; /* connection (algorithm) type */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/non-percussive mode */ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + unsigned int wavetable; +} OPL_SLOT; + +typedef struct{ + OPL_SLOT SLOT[2]; + /* phase generator state */ + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f { + /* FM channel slots */ + OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT8 rhythm; /* Rhythm mode */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + /* LFO */ + UINT8 lfo_am_depth; + UINT8 lfo_pm_depth_range; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + UINT8 wavesel; /* waveform select enable flag */ + + int T[2]; /* timer counters */ + UINT8 st[2]; /* timer enable */ + +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + + YM_DELTAT *deltat; + + /* Keyboard / I/O interface unit*/ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + int port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + int keyboard_param; +#endif + + /* external event callback handlers */ + OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ + int TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + int IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ + int UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ + + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + double TimerBase; /* Timer base time (==sampling time)*/ +} FM_OPL; + + + /* mapping of register number (offset) to slot number used by the emulator */ static const int slot_array[32]= { @@ -149,8 +288,8 @@ static const int slot_array[32]= /* key scale level */ /* table is 3dB/octave , DV converts this into 6dB/octave */ -/* 0.09375 is bit 0 weight expressed in the 'decibel' scale */ -#define DV (0.09375/2.0) +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/2.0) static const UINT32 ksl_tab[8*16]= { /* OCT 0 */ @@ -196,15 +335,123 @@ static const UINT32 ksl_tab[8*16]= }; #undef DV -/* sustain lebel table (3dB per step) */ +/* sustain level table (3dB per step) */ /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) * (1<>3) +#define ENV_QUIET (TL_TAB_LEN>>4) /* sin waveform table in 'decibel' scale */ /* four waveforms on OPL2 type chips */ @@ -230,6 +477,7 @@ static unsigned int sin_tab[SIN_LEN * 4]; /* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples Length: 210 elements. @@ -237,8 +485,8 @@ static unsigned int sin_tab[SIN_LEN * 4]; exactly 64 times (on 64 consecutive samples). The whole table takes: 64 * 210 = 13440 samples. - When AM = 1 data is multiplied by 2 - When AM = 0 data is divided by 4 and then multiplied by 2 (loosing precision is important) + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (loosing precision is important) */ #define LFO_AM_TAB_ELEMENTS 210 @@ -354,17 +602,6 @@ static INT32 LFO_PM; -/* log output level */ -#define LOG_ERR 3 /* ERROR */ -#define LOG_WAR 2 /* WARNING */ -#define LOG_INF 1 /* INFORMATION */ - -#define LOG_LEVEL LOG_INF - -#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x - - - INLINE int limit( int val, int max, int min ) { if ( val > max ) val = max; @@ -375,7 +612,6 @@ INLINE int limit( int val, int max, int min ) { } - /* status set and IRQ handling */ INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) { @@ -431,104 +667,119 @@ INLINE void advance_lfo(FM_OPL *OPL) tmp = lfo_am_table[ OPL->lfo_am_cnt >> LFO_SH ]; if (OPL->lfo_am_depth) - LFO_AM = (tmp) * 2; + LFO_AM = tmp; else - LFO_AM = (tmp>>2) * 2; + LFO_AM = tmp>>2; OPL->lfo_pm_cnt += OPL->lfo_pm_inc; - LFO_PM = ( (OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; + LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; } /* advance to next sample */ INLINE void advance(FM_OPL *OPL) { OPL_CH *CH; - OPL_SLOT *SLOT; + OPL_SLOT *op; int i; + OPL->eg_timer += OPL->eg_timer_add; + + while (OPL->eg_timer >= OPL->eg_timer_overflow) + { + OPL->eg_timer -= OPL->eg_timer_overflow; + + OPL->eg_cnt++; + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Envelope Generator */ + switch(op->state) + { + case EG_ATT: /* attack phase */ + { + + if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>3; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + + } + break; + + case EG_DEC: /* decay phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + default: + break; + } + } + } for (i=0; i<9*2; i++) { - CH = &OPL->P_CH[i/2]; - SLOT = &CH->SLOT[i&1]; - - /* Envelope Generator */ - switch(SLOT->state) - { - case EG_ATT: /* attack phase */ - { - INT32 step = SLOT->volume; - - SLOT->volume -= SLOT->delta_ar; - step = (step>>ENV_SH) - (((UINT32)SLOT->volume)>>ENV_SH); /* number of levels passed since last time */ - if (step > 0) - { - INT32 tmp_volume = SLOT->volume + (step<>4) & ~ENV_MASK); - if (tmp_volume <= MIN_ATT_INDEX) - break; - step--; - }while(step); - SLOT->volume = tmp_volume; - } - - if (SLOT->volume <= MIN_ATT_INDEX) - { - if (SLOT->volume < 0) - SLOT->volume = 0; /* this is not quite correct (checked) */ - - SLOT->state = EG_DEC; - } - } - break; - - case EG_DEC: /* decay phase */ - - if ( (SLOT->volume += SLOT->delta_dr) >= SLOT->sl ) - { - SLOT->volume = SLOT->sl; /* this is not quite correct (checked) */ - SLOT->state = EG_SUS; - } - break; - - case EG_SUS: /* sustain phase */ - - /* this is important behaviour: - one can change percusive/non-percussive modes on the fly and - the chip will remain in sustain phase - verified on real YM3812 */ - - if(SLOT->eg_type) /* non-percussive mode */ - { - /* do nothing */ - } - else /* percussive mode */ - { - /* during sustain phase chip adds Release Rate (in percussive mode) */ - - if ( (SLOT->volume += SLOT->delta_rr) > MAX_ATT_INDEX ) - { - SLOT->volume = MAX_ATT_INDEX; - } - /* else do nothing in sustain phase */ - } - break; - - case EG_REL: /* release phase */ - if ( (SLOT->volume += SLOT->delta_rr) > MAX_ATT_INDEX ) - { - SLOT->volume = MAX_ATT_INDEX; - SLOT->state = EG_OFF; - } - break; - - default: - break; - } + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; /* Phase Generator */ - if(SLOT->vib) + if(op->vib) { UINT8 block; unsigned int block_fnum = CH->block_fnum; @@ -541,16 +792,16 @@ INLINE void advance(FM_OPL *OPL) { block_fnum += lfo_fn_table_index_offset; block = (block_fnum&0x1c00) >> 10; - SLOT->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * SLOT->mul;//ok + op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul;//ok } else /* LFO phase modulation = zero */ { - SLOT->Cnt += SLOT->Incr; + op->Cnt += op->Incr; } } else /* LFO phase modulation disabled for this operator */ { - SLOT->Cnt += SLOT->Incr; + op->Cnt += op->Incr; } } @@ -570,26 +821,40 @@ INLINE void advance(FM_OPL *OPL) OPL->noise_p &= FREQ_MASK; while (i) { + /* UINT32 j; j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; + OPL->noise_rng >>= 1; + i--; } } -INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm) +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) { UINT32 p; - p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK ]; + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; if (p >= TL_TAB_LEN) return 0; return tl_tab[p]; } -INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) { UINT32 p; INT32 i; @@ -598,7 +863,7 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) /*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/ - p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK]; + p = (env<<4) + sin_tab[ wave_tab + ((i>>FREQ_SH) & SIN_MASK)]; /*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ @@ -608,7 +873,7 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) } -#define volume_calc(OP) ((OP)->TLL + (((UINT32)(OP)->volume)>>ENV_SH) + (LFO_AM & (OP)->AMmask)) +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) /* calculate output */ INLINE void OPL_CALC_CH( OPL_CH *CH ) @@ -622,18 +887,22 @@ INLINE void OPL_CALC_CH( OPL_CH *CH ) /* SLOT 1 */ SLOT = &CH->SLOT[SLOT1]; env = volume_calc(SLOT); - out = CH->op1_out[0] + CH->op1_out[1]; - CH->op1_out[0] = CH->op1_out[1]; - *CH->connect1 += CH->op1_out[0]; - CH->op1_out[1] = 0; + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + *SLOT->connect1 += SLOT->op1_out[0]; + SLOT->op1_out[1] = 0; if( env < ENV_QUIET ) - CH->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB) ); + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } /* SLOT 2 */ SLOT++; env = volume_calc(SLOT); if( env < ENV_QUIET ) - output[0] += op_calc(SLOT->Cnt, env, phase_modulation); + output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); } /* @@ -691,23 +960,27 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) /* SLOT 1 */ SLOT = &CH[6].SLOT[SLOT1]; env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + if (!SLOT->CON) + phase_modulation = SLOT->op1_out[0]; + //else ignore output of operator 1 + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) { - out = CH[6].op1_out[0] + CH[6].op1_out[1]; - CH[6].op1_out[0] = CH[6].op1_out[1]; - - if (!CH[6].CON) - phase_modulation = CH[6].op1_out[0]; - //else ignore output of operator 1 - - CH[6].op1_out[1] = 0; - if( env < ENV_QUIET ) - CH[6].op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); } + /* SLOT 2 */ SLOT++; env = volume_calc(SLOT); if( env < ENV_QUIET ) - output[0] += op_calc(SLOT->Cnt, env, phase_modulation) * 2; + output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; /* Phase generation is based on: */ @@ -775,7 +1048,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) phase = 0xd0>>2; } - output[0] += op_calc(phase<wavetable) * 2; } /* Snare Drum (verified on real YM3812) */ @@ -796,13 +1069,13 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) if (noise) phase ^= 0x100; - output[0] += op_calc(phase<wavetable) * 2; } /* Tom Tom (verified on real YM3812) */ env = volume_calc(SLOT8_1); if( env < ENV_QUIET ) - output[0] += op_calc(SLOT8_1->Cnt, env, 0) * 2; + output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT->wavetable) * 2; /* Top Cymbal (verified on real YM3812) */ env = volume_calc(SLOT8_2); @@ -829,69 +1102,11 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) if (res2) phase = 0x300; - output[0] += op_calc(phase<wavetable) * 2; } } -/* initialize time tables */ -static void init_timetables( FM_OPL *OPL ) -{ - int i; - double rate; - - /* make attack rate & decay rate tables */ - for (i = 0;i < 16+4;i++) - OPL->eg_tab[i] = 0; - - for (i = 4;i < 64;i++) - { - rate = OPL->freqbase; /* frequency rate */ - if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ - rate *= 1 << (i>>2); /* b2-5 : shift bit */ - rate /= /*576*/ 8 * 1024.0; - rate *= (double)(1<eg_tab[16+i] = rate; -#if 0 - logerror("FMOPL.C: Rate %2i %1i Decay [real %11.4f ms][emul %11.4f ms][d=%08x]\n",i>>2, i&3, - ( ((double)(ENV_LEN<rate), - ( ((double)(ENV_LEN<eg_tab[16+i]) * (1000.0 / (double)OPL->rate), OPL->eg_tab[16+i] ); -#endif - } - - for (i = 0; i < 16; i++) - { - OPL->eg_tab[16+64+i] = OPL->eg_tab[16+63]; - } - -#if 0 - for (i = 4; i < 64 ; i++) /* test */ - { - UINT32 vol = 0; - UINT32 vol_step = OPL->eg_tab[16+i]; - int j=0, change_no=0; - int lastchange=-1; - - logerror("FMOPL.C - EG TEST: Rate %2i %1i [d=%08x]\n",i>>2, i&3, vol_step ); - logerror(" -> changes every samples: "); - - while (change_no<16) - { - UINT32 tmp_vol = vol>>ENV_SH; - vol += vol_step; - if (tmp_vol!=(vol>>ENV_SH)) - { - //display the distance (in number of samples) since last level change - logerror("%i ",j-lastchange); - lastchange = j; - change_no++; - } - j++; - } - logerror("\n"); - } -#endif -} /* generic table initialize */ static int init_tables(void) @@ -926,9 +1141,9 @@ static int init_tables(void) tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; } #if 0 - logerror("tl %04i", x); + logerror("tl %04i", x*2); for (i=0; i<12; i++) - logerror(", [%02i] %4i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); logerror("\n"); #endif } @@ -962,19 +1177,25 @@ static int init_tables(void) for (i=0; i>1) ]; - /* waveform 3: /- /- /- /- */ + /* waveform 3: _ _ _ _ */ + /* / |_/ |_/ |_/ |_*/ /* abs(output only first quarter of the sinus waveform) */ + if (i & (1<<(SIN_BITS-2)) ) sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; else @@ -1018,9 +1239,6 @@ static void OPL_initalize(FM_OPL *OPL) /* Timer base time */ OPL->TimerBase = 1.0 / ((double)OPL->clock / 72.0 ); - /* make time tables */ - init_timetables( OPL ); - /* make fnumber -> increment counter table */ for( i=0 ; i < 1024 ; i++ ) { @@ -1051,8 +1269,8 @@ static void OPL_initalize(FM_OPL *OPL) #endif - /* Amplitude modulation: 26 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ - /* In our LFO_AM_TABLE one entry lasts for 64 samples */ + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ OPL->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ @@ -1062,6 +1280,11 @@ static void OPL_initalize(FM_OPL *OPL) /* Noise generator: a step takes 1 sample */ OPL->noise_f = (1.0 / 1.0) * (1<freqbase; + + OPL->eg_timer_add = (1<freqbase; + OPL->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ + } INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) @@ -1105,12 +1328,20 @@ INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) SLOT->ksr = ksr; /* calculate envelope generator rates */ - if ((SLOT->ARval + SLOT->ksr) < 16+60) - SLOT->delta_ar = SLOT->AR[ SLOT->ksr ]; + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } else - SLOT->delta_ar = MAX_ATT_INDEX+1; - SLOT->delta_dr = SLOT->DR[ SLOT->ksr ]; - SLOT->delta_rr = SLOT->RR[ SLOT->ksr ]; + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; } } @@ -1136,7 +1367,7 @@ INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ SLOT->ksl = ksl ? 3-ksl : 31; - SLOT->TL = (v&0x3f)<<(ENV_BITS-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); } @@ -1146,17 +1377,23 @@ INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int DRval = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->ARval = (v>>4) ? 16 + ((v>>4) <<2) : 0; - SLOT->AR = &OPL->eg_tab[ SLOT->ARval ]; + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; - if ((SLOT->ARval + SLOT->ksr) < 16+60) - SLOT->delta_ar = SLOT->AR[ SLOT->ksr ]; + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } else - SLOT->delta_ar = MAX_ATT_INDEX+1; - SLOT->DR = &OPL->eg_tab[DRval]; - SLOT->delta_dr = SLOT->DR[ SLOT->ksr ]; + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; } /* set sustain level & release rate */ @@ -1164,12 +1401,12 @@ INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) { OPL_CH *CH = &OPL->P_CH[slot/2]; OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int RRval = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; SLOT->sl = sl_tab[ v>>4 ]; - SLOT->RR = &OPL->eg_tab[RRval]; - SLOT->delta_rr = SLOT->RR[ SLOT->ksr ]; + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; } @@ -1247,7 +1484,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) if(OPL->keyboardhandler_w) OPL->keyboardhandler_w(OPL->keyboard_param,v); else - LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); + logerror("OPL:write unmapped KEYBOARD port\n"); } break; case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ @@ -1295,22 +1532,22 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) break; case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ slot = slot_array[r&0x1f]; - if(slot == -1) return; + if(slot < 0) return; set_mul(OPL,slot,v); break; case 0x40: slot = slot_array[r&0x1f]; - if(slot == -1) return; + if(slot < 0) return; set_ksl_tl(OPL,slot,v); break; case 0x60: slot = slot_array[r&0x1f]; - if(slot == -1) return; + if(slot < 0) return; set_ar_dr(OPL,slot,v); break; case 0x80: slot = slot_array[r&0x1f]; - if(slot == -1) return; + if(slot < 0) return; set_sl_rr(OPL,slot,v); break; case 0xa0: @@ -1402,7 +1639,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ if (OPL->mode&0x40) - CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ else CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ @@ -1419,19 +1656,19 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) /* FB,C */ if( (r&0x0f) > 8) return; CH = &OPL->P_CH[r&0x0f]; - CH->FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; - CH->CON = v&1; - CH->connect1 = CH->CON ? &output[0] : &phase_modulation; + CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; + CH->SLOT[SLOT1].CON = v&1; + CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output[0] : &phase_modulation; break; case 0xe0: /* waveform select */ /* simply ignore write to the waveform select register if selecting not enabled in test register */ if(OPL->wavesel) { slot = slot_array[r&0x1f]; - if(slot == -1) return; + if(slot < 0) return; CH = &OPL->P_CH[slot/2]; - CH->SLOT[slot&1].wavetable = &sin_tab[(v&0x03)*SIN_LEN]; + CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; } break; } @@ -1491,22 +1728,310 @@ static void OPL_UnLockTable(void) } -#if (BUILD_YM3812 || BUILD_YM3526) -/*******************************************************************************/ -/* YM3812 local section */ -/*******************************************************************************/ +static void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; -/* Generate samples for one of the YM3812's -* -* '*OPL' is pointer to the virtual YM3812 -* '*buffer' is pointer to the sample buffer -* 'length' is the number of samples that should be generated -*/ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) + OPL->eg_timer = 0; + OPL->eg_cnt = 0; + + OPL->noise_rng = 1; /* noise shift register */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wavesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = 0; + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = &output_deltat[0]; + DELTAT->portshift = 5; + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,0); + } +#endif +} + +/* Create one of virtual YM3812 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static FM_OPL *OPLCreate(int type, int clock, int rate) +{ + char *ptr; + FM_OPL *OPL; + int state_size; + + if (OPL_LockTable() ==-1) return NULL; + + /* calculate OPL state size */ + state_size = sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); +#endif + + /* allocate memory block */ + ptr = (char *)malloc(state_size); + + if (ptr==NULL) + return NULL; + + /* clear */ + memset(ptr,0,state_size); + + OPL = (FM_OPL *)ptr; + + ptr += sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) + OPL->deltat = (YM_DELTAT *)ptr; + ptr += sizeof(YM_DELTAT); +#endif + + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + + /* init global tables */ + OPL_initalize(OPL); + + /* reset chip */ + OPLResetChip(OPL); + return OPL; +} + +/* Destroy one of virtual YM3812 */ +static void OPLDestroy(FM_OPL *OPL) +{ + OPL_UnLockTable(); + free(OPL); +} + +/* Option handlers */ + +static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) +{ + OPL->TimerHandler = TimerHandler; + OPL->TimerParam = channelOffset; +} +static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} + +/* YM3812 I/O interface */ +static int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +static unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { + /* status port */ + return OPL->status & (OPL->statusmask|0x80); + } + +#if BUILD_Y8950 + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + else + logerror("OPL:read unmapped KEYBOARD port\n"); + } + return 0; +#if 0 + case 0x0f: /* ADPCM-DATA */ + return 0; +#endif + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + else + logerror("OPL:read unmapped I/O port\n"); + } + return 0; + case 0x1a: /* PCM-DATA */ + return 0; + } +#endif + + return 0xff; +} + +/* CSM Key Controll */ +INLINE void CSMKeyControll(OPL_CH *CH) +{ + FM_KEYON (&CH->SLOT[SLOT1], 4); + FM_KEYON (&CH->SLOT[SLOT2], 4); + + /* The key off should happen exactly one sample later - not implemented correctly yet */ + + FM_KEYOFF(&CH->SLOT[SLOT1], ~4); + FM_KEYOFF(&CH->SLOT[SLOT2], ~4); +} + + +static int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0; ch<9; ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); + return OPL->status>>7; +} + + +#define MAX_OPL_CHIPS 2 + + +#if (BUILD_YM3812) + +static FM_OPL *OPL_YM3812[MAX_OPL_CHIPS]; /* array of pointers to the YM3812's */ +static int YM3812NumChips = 0; /* number of chips */ + +int YM3812Init(int num, int clock, int rate) { int i; - OPLSAMPLE *buf = buffer; - UINT8 rhythm = OPL->rhythm&0x20; + + if (YM3812NumChips) + return -1; /* duplicate init. */ + + YM3812NumChips = num; + + for (i = 0;i < YM3812NumChips; i++) + { + /* emulator create */ + OPL_YM3812[i] = OPLCreate(OPL_TYPE_YM3812,clock,rate); + if(OPL_YM3812[i] == NULL) + { + /* it's really bad - we run out of memeory */ + YM3812NumChips = 0; + return -1; + } + } + + return 0; +} + +void YM3812Shutdown(void) +{ + int i; + + for (i = 0;i < YM3812NumChips; i++) + { + /* emulator shutdown */ + OPLDestroy(OPL_YM3812[i]); + OPL_YM3812[i] = NULL; + } + YM3812NumChips = 0; +} +void YM3812ResetChip(int which) +{ + OPLResetChip(OPL_YM3812[which]); +} + +int YM3812Write(int which, int a, int v) +{ + return OPLWrite(OPL_YM3812[which], a, v); +} + +unsigned char YM3812Read(int which, int a) +{ + /* YM3812 always returns bit2 and bit1 in HIGH state */ + return OPLRead(OPL_YM3812[which], a) | 0x06 ; +} +int YM3812TimerOver(int which, int c) +{ + return OPLTimerOver(OPL_YM3812[which], c); +} + +void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) +{ + OPLSetTimerHandler(OPL_YM3812[which], TimerHandler, channelOffset); +} +void YM3812SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) +{ + OPLSetIRQHandler(OPL_YM3812[which], IRQHandler, param); +} +void YM3812SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPLSetUpdateHandler(OPL_YM3812[which], UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3812's +** +** 'which' is the virtual YM3812 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void YM3812UpdateOne(int which, INT16 *buffer, int length) +{ + FM_OPL *OPL = OPL_YM3812[which]; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; if( (void *)OPL != cur_chip ){ cur_chip = (void *)OPL; @@ -1540,7 +2065,7 @@ void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) } else /* Rhythm part */ { - OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>22)&1 ); + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); } lt = output[0]; @@ -1558,20 +2083,253 @@ void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) buf[i] = lt; advance(OPL); - } } -#endif /* (BUILD_YM3812 || BUILD_YM3526) */ +#endif /* BUILD_YM3812 */ + + + +#if (BUILD_YM3526) + +static FM_OPL *OPL_YM3526[MAX_OPL_CHIPS]; /* array of pointers to the YM3526's */ +static int YM3526NumChips = 0; /* number of chips */ + +int YM3526Init(int num, int clock, int rate) +{ + int i; + + if (YM3526NumChips) + return -1; /* duplicate init. */ + + YM3526NumChips = num; + + for (i = 0;i < YM3526NumChips; i++) + { + /* emulator create */ + OPL_YM3526[i] = OPLCreate(OPL_TYPE_YM3526,clock,rate); + if(OPL_YM3526[i] == NULL) + { + /* it's really bad - we run out of memeory */ + YM3526NumChips = 0; + return -1; + } + } + + return 0; +} + +void YM3526Shutdown(void) +{ + int i; + + for (i = 0;i < YM3526NumChips; i++) + { + /* emulator shutdown */ + OPLDestroy(OPL_YM3526[i]); + OPL_YM3526[i] = NULL; + } + YM3526NumChips = 0; +} +void YM3526ResetChip(int which) +{ + OPLResetChip(OPL_YM3526[which]); +} + +int YM3526Write(int which, int a, int v) +{ + return OPLWrite(OPL_YM3526[which], a, v); +} + +unsigned char YM3526Read(int which, int a) +{ + return OPLRead(OPL_YM3526[which], a); +} +int YM3526TimerOver(int which, int c) +{ + return OPLTimerOver(OPL_YM3526[which], c); +} + +void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) +{ + OPLSetTimerHandler(OPL_YM3526[which], TimerHandler, channelOffset); +} +void YM3526SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) +{ + OPLSetIRQHandler(OPL_YM3526[which], IRQHandler, param); +} +void YM3526SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPLSetUpdateHandler(OPL_YM3526[which], UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void YM3526UpdateOne(int which, INT16 *buffer, int length) +{ + FM_OPL *OPL = OPL_YM3526[which]; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* rhythm slots */ + SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + } + for( i=0; i < length ; i++ ) + { + int lt; + + output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(&OPL->P_CH[0]); + OPL_CALC_CH(&OPL->P_CH[1]); + OPL_CALC_CH(&OPL->P_CH[2]); + OPL_CALC_CH(&OPL->P_CH[3]); + OPL_CALC_CH(&OPL->P_CH[4]); + OPL_CALC_CH(&OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(&OPL->P_CH[6]); + OPL_CALC_CH(&OPL->P_CH[7]); + OPL_CALC_CH(&OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + SAVE_ALL_CHANNELS + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3526 */ + + + #if BUILD_Y8950 -void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) +static FM_OPL *OPL_Y8950[MAX_OPL_CHIPS]; /* array of pointers to the Y8950's */ +static int Y8950NumChips = 0; /* number of chips */ + +int Y8950Init(int num, int clock, int rate) { int i; - OPLSAMPLE *buf = buffer; - UINT8 rhythm = OPL->rhythm&0x20; - YM_DELTAT *DELTAT = OPL->deltat; + + if (Y8950NumChips) + return -1; /* duplicate init. */ + + Y8950NumChips = num; + + for (i = 0;i < Y8950NumChips; i++) + { + /* emulator create */ + OPL_Y8950[i] = OPLCreate(OPL_TYPE_Y8950,clock,rate); + if(OPL_Y8950[i] == NULL) + { + /* it's really bad - we run out of memeory */ + Y8950NumChips = 0; + return -1; + } + } + + return 0; +} + +void Y8950Shutdown(void) +{ + int i; + + for (i = 0;i < Y8950NumChips; i++) + { + /* emulator shutdown */ + OPLDestroy(OPL_Y8950[i]); + OPL_Y8950[i] = NULL; + } + Y8950NumChips = 0; +} +void Y8950ResetChip(int which) +{ + OPLResetChip(OPL_Y8950[which]); +} + +int Y8950Write(int which, int a, int v) +{ + return OPLWrite(OPL_Y8950[which], a, v); +} + +unsigned char Y8950Read(int which, int a) +{ + return OPLRead(OPL_Y8950[which], a); +} +int Y8950TimerOver(int which, int c) +{ + return OPLTimerOver(OPL_Y8950[which], c); +} + +void Y8950SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) +{ + OPLSetTimerHandler(OPL_Y8950[which], TimerHandler, channelOffset); +} +void Y8950SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) +{ + OPLSetIRQHandler(OPL_Y8950[which], IRQHandler, param); +} +void Y8950SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) +{ + OPLSetUpdateHandler(OPL_Y8950[which], UpdateHandler, param); +} + +void Y8950SetDeltaTMemory(int which, void * deltat_rom, int deltat_rom_size ) +{ + FM_OPL *OPL = OPL_Y8950[which]; + OPL->deltat->memory = (UINT8 *)(deltat_rom); + OPL->deltat->memory_size = deltat_rom_size; +} + +/* +** Generate samples for one of the Y8950's +** +** 'which' is the virtual Y8950 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void Y8950UpdateOne(int which, INT16 *buffer, int length) +{ + int i; + FM_OPL *OPL = OPL_Y8950[which]; + UINT8 rhythm = OPL->rhythm&0x20; + YM_DELTAT *DELTAT = OPL->deltat; + OPLSAMPLE *buf = buffer; /* setup DELTA-T unit */ YM_DELTAT_DECODE_PRESET(DELTAT); @@ -1614,7 +2372,7 @@ void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) } else /* Rhythm part */ { - OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>22)&1 ); + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); } lt = output[0] + (output_deltat[0]>>11); @@ -1644,235 +2402,22 @@ void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) OPL->status |= 0x10; } } -#endif - -void OPLResetChip(FM_OPL *OPL) -{ - int c,s; - int i; - - OPL->noise_rng = 1; /* noise shift register */ - OPL->mode = 0; /* normal mode */ - OPL_STATUS_RESET(OPL,0x7f); - - /* reset with register write */ - OPLWriteReg(OPL,0x01,0); /* wavesel disable */ - OPLWriteReg(OPL,0x02,0); /* Timer1 */ - OPLWriteReg(OPL,0x03,0); /* Timer2 */ - OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ - for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); - - /* reset operator parameters */ - for( c = 0 ; c < 9 ; c++ ) - { - OPL_CH *CH = &OPL->P_CH[c]; - for(s = 0 ; s < 2 ; s++ ) - { - /* wave table */ - CH->SLOT[s].wavetable = &sin_tab[0]; - CH->SLOT[s].state = EG_OFF; - CH->SLOT[s].volume = MAX_ATT_INDEX; - } - } -#if BUILD_Y8950 - if(OPL->type&OPL_TYPE_ADPCM) - { - YM_DELTAT *DELTAT = OPL->deltat; - - DELTAT->freqbase = OPL->freqbase; - DELTAT->output_pointer = &output_deltat[0]; - DELTAT->portshift = 5; - DELTAT->output_range = 1<<23; - YM_DELTAT_ADPCM_Reset(DELTAT,0); - } -#endif -} - -/* Create one of virtual YM3812 */ -/* 'clock' is chip clock in Hz */ -/* 'rate' is sampling rate */ -FM_OPL *OPLCreate(int type, int clock, int rate) -{ - union { - char *ptr; - void *ptr_void; - }; - FM_OPL *OPL; - int state_size; - - if (OPL_LockTable() ==-1) return NULL; - - /* calculate OPL state size */ - state_size = sizeof(FM_OPL); - -#if BUILD_Y8950 - if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); -#endif - - /* allocate memory block */ - ptr_void = malloc(state_size); - - if (ptr==NULL) - return NULL; - - /* clear */ - memset(ptr,0,state_size); - - OPL = (FM_OPL *)ptr; - - ptr += sizeof(FM_OPL); - -#if BUILD_Y8950 - if (type&OPL_TYPE_ADPCM) - OPL->deltat = (YM_DELTAT *)ptr; - ptr += sizeof(YM_DELTAT); -#endif - - OPL->type = type; - OPL->clock = clock; - OPL->rate = rate; - - /* init global tables */ - OPL_initalize(OPL); - - /* reset chip */ - OPLResetChip(OPL); - return OPL; -} - -/* Destroy one of virtual YM3812 */ -void OPLDestroy(FM_OPL *OPL) -{ - OPL_UnLockTable(); - free(OPL); -} - -/* Option handlers */ - -void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) -{ - OPL->TimerHandler = TimerHandler; - OPL->TimerParam = channelOffset; -} -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) -{ - OPL->IRQHandler = IRQHandler; - OPL->IRQParam = param; -} -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) -{ - OPL->UpdateHandler = UpdateHandler; - OPL->UpdateParam = param; -} - -#if BUILD_Y8950 -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) +void Y8950SetPortHandler(int which,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) { + FM_OPL *OPL = OPL_Y8950[which]; OPL->porthandler_w = PortHandler_w; OPL->porthandler_r = PortHandler_r; OPL->port_param = param; } -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) +void Y8950SetKeyboardHandler(int which,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) { + FM_OPL *OPL = OPL_Y8950[which]; OPL->keyboardhandler_w = KeyboardHandler_w; OPL->keyboardhandler_r = KeyboardHandler_r; OPL->keyboard_param = param; } + #endif -/* YM3812 I/O interface */ -int OPLWrite(FM_OPL *OPL,int a,int v) -{ - if( !(a&1) ) - { /* address port */ - OPL->address = v & 0xff; - } - else - { /* data port */ - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - OPLWriteReg(OPL,OPL->address,v); - } - return OPL->status>>7; -} - -unsigned char OPLRead(FM_OPL *OPL,int a) -{ - if( !(a&1) ) - { - /* YM3812 returns 0x06 (bit2 and bit1 are HIGH) */ - - /* status port */ - return OPL->status & (OPL->statusmask|0x80); - } - -#if BUILD_Y8950 - /* data port */ - switch(OPL->address) - { - case 0x05: /* KeyBoard IN */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_r) - return OPL->keyboardhandler_r(OPL->keyboard_param); - else - LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); - } - return 0; -#if 0 - case 0x0f: /* ADPCM-DATA */ - return 0; -#endif - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - if(OPL->porthandler_r) - return OPL->porthandler_r(OPL->port_param); - else - LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); - } - return 0; - case 0x1a: /* PCM-DATA */ - return 0; - } -#endif - - return 0xff; -} - -/* CSM Key Controll */ -INLINE void CSMKeyControll(OPL_CH *CH) -{ - FM_KEYON (&CH->SLOT[SLOT1], 4); - FM_KEYON (&CH->SLOT[SLOT2], 4); - - /* The key off should happen exactly one sample later - not implemented correctly yet */ - - FM_KEYOFF(&CH->SLOT[SLOT1], ~4); - FM_KEYOFF(&CH->SLOT[SLOT2], ~4); -} - - -int OPLTimerOver(FM_OPL *OPL,int c) -{ - if( c ) - { /* Timer B */ - OPL_STATUS_SET(OPL,0x20); - } - else - { /* Timer A */ - OPL_STATUS_SET(OPL,0x40); - /* CSM mode key,TL controll */ - if( OPL->mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - int ch; - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - for(ch=0; ch<9; ch++) - CSMKeyControll( &OPL->P_CH[ch] ); - } - } - /* reload timer */ - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); - return OPL->status>>7; -} diff --git a/src/hardware/fmopl.h b/src/hardware/fmopl.h index 46c5c15..4ba2b6b 100644 --- a/src/hardware/fmopl.h +++ b/src/hardware/fmopl.h @@ -6,8 +6,7 @@ #define BUILD_YM3526 (HAS_YM3526) #define BUILD_Y8950 (HAS_Y8950) -/* --- system optimize --- */ -/* select bit size of output : 8 or 16 */ +/* select output bits size of output : 8 or 16 */ #define OPL_SAMPLE_BITS 16 /* compiler dependence */ @@ -25,167 +24,88 @@ typedef signed int INT32; /* signed 32bit */ typedef INT16 OPLSAMPLE; #endif #if (OPL_SAMPLE_BITS==8) -typedef unsigned char OPLSAMPLE; +typedef INT8 OPLSAMPLE; #endif -#if BUILD_Y8950 -#include "ymdeltat.h" -#endif - typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); typedef void (*OPL_IRQHANDLER)(int param,int irq); typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); typedef unsigned char (*OPL_PORTHANDLER_R)(int param); -/* !!!!! here is private section , do not access there member direct !!!!! */ -#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ -#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ -#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ -#define OPL_TYPE_IO 0x08 /* I/O port */ +#if BUILD_YM3812 -/* Saving is necessary for member of the 'R' mark for suspend/resume */ -/* ---------- OPL slot ---------- */ -typedef struct fm_opl_slot { - const UINT32 *AR; /* attack rate tab :&eg_table[AR<<2]*/ - const UINT32 *DR; /* decay rate tab :&eg_table[DR<<2]*/ - const UINT32 *RR; /* release rate tab:&eg_table[RR<<2]*/ - UINT8 KSR; /* key scale rate */ - UINT8 ARval; /* current AR */ - UINT8 ksl; /* keyscale level */ - UINT8 ksr; /* key scale rate :kcode>>KSR */ - UINT8 mul; /* multiple :ML_TABLE[ML] */ +int YM3812Init(int num, int clock, int rate); +void YM3812Shutdown(void); +void YM3812ResetChip(int which); +int YM3812Write(int which, int a, int v); +unsigned char YM3812Read(int which, int a); +int YM3812TimerOver(int which, int c); +void YM3812UpdateOne(int which, INT16 *buffer, int length); - /* Phase Generator */ - UINT32 Cnt; /* frequency count */ - UINT32 Incr; /* frequency step */ +void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); +void YM3812SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param); +void YM3812SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param); - /* Envelope Generator */ - UINT8 eg_type; /* percussive/non-percussive mode */ - UINT8 state; /* phase type */ - UINT32 TL; /* total level :TL << 3 */ - INT32 TLL; /* adjusted now TL */ - INT32 volume; /* envelope counter */ - UINT32 sl; /* sustain level :SL_TABLE[SL] */ - UINT32 delta_ar; /* envelope step for Attack */ - UINT32 delta_dr; /* envelope step for Decay */ - UINT32 delta_rr; /* envelope step for Release */ +#endif - UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ - /* LFO */ - UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ - UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ +#if BUILD_YM3526 - /* waveform select */ - unsigned int *wavetable; -}OPL_SLOT; +/* +** Initialize YM3526 emulator(s). +** +** 'num' is the number of virtual YM3526's to allocate +** 'clock' is the chip clock in Hz +** 'rate' is sampling rate +*/ +int YM3526Init(int num, int clock, int rate); +/* shutdown the YM3526 emulators*/ +void YM3526Shutdown(void); +void YM3526ResetChip(int which); +int YM3526Write(int which, int a, int v); +unsigned char YM3526Read(int which, int a); +int YM3526TimerOver(int which, int c); +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void YM3526UpdateOne(int which, INT16 *buffer, int length); -/* ---------- OPL one of channel ---------- */ -typedef struct fm_opl_channel { - OPL_SLOT SLOT[2]; - UINT8 FB; /* feedback shift value */ - INT32 *connect1; /* slot1 output pointer */ - INT32 op1_out[2]; /* slot1 output for feedback */ +void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); +void YM3526SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param); +void YM3526SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param); - /* phase generator state */ - UINT32 block_fnum; /* block+fnum */ - UINT32 fc; /* Freq. Increment base */ - UINT32 ksl_base; /* KeyScaleLevel Base step */ - UINT8 kcode; /* key code (for key scaling) */ +#endif - UINT8 CON; /* connection (algorithm) type */ -} OPL_CH; - -/* OPL state */ -typedef struct fm_opl_f { - /* FM channel slots */ - OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels */ - - UINT8 rhythm; /* Rhythm mode */ - - UINT32 eg_tab[16+64+16]; /* EG rate table: 16 (dummy) + 64 rates + 16 RKS */ - UINT32 fn_tab[1024]; /* fnumber -> increment counter */ - - /* LFO */ - UINT8 lfo_am_depth; - UINT8 lfo_pm_depth_range; - UINT32 lfo_am_cnt; - UINT32 lfo_am_inc; - UINT32 lfo_pm_cnt; - UINT32 lfo_pm_inc; - - UINT32 noise_rng; /* 23 bit noise shift register */ - UINT32 noise_p; /* current noise 'phase' */ - UINT32 noise_f; /* current noise period */ - - UINT8 wavesel; /* waveform select enable flag */ - - int T[2]; /* timer counters */ - UINT8 st[2]; /* timer enable */ #if BUILD_Y8950 - /* Delta-T ADPCM unit (Y8950) */ - YM_DELTAT *deltat; +#include "ymdeltat.h" - /* Keyboard / I/O interface unit*/ - UINT8 portDirection; - UINT8 portLatch; - OPL_PORTHANDLER_R porthandler_r; - OPL_PORTHANDLER_W porthandler_w; - int port_param; - OPL_PORTHANDLER_R keyboardhandler_r; - OPL_PORTHANDLER_W keyboardhandler_w; - int keyboard_param; -#endif - - /* external event callback handlers */ - OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ - int TimerParam; /* TIMER parameter */ - OPL_IRQHANDLER IRQHandler; /* IRQ handler */ - int IRQParam; /* IRQ parameter */ - OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ - int UpdateParam; /* stream update parameter */ - - UINT8 type; /* chip type */ - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - UINT8 statusmask; /* status mask */ - UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ - - int clock; /* master clock (Hz) */ - int rate; /* sampling rate (Hz) */ - double freqbase; /* frequency base */ - double TimerBase; /* Timer base time (==sampling time)*/ -} FM_OPL; - - -/* ---------- Generic interface section ---------- */ -#define OPL_TYPE_YM3526 (0) -#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) -#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) - -FM_OPL *OPLCreate(int type, int clock, int rate); -void OPLDestroy(FM_OPL *OPL); -void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); /* Y8950 port handlers */ -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); +void Y8950SetPortHandler(int which, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, int param); +void Y8950SetKeyboardHandler(int which, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, int param); +void Y8950SetDeltaTMemory(int which, void * deltat_rom, int deltat_rom_size ); -void OPLResetChip(FM_OPL *OPL); -int OPLWrite(FM_OPL *OPL,int a,int v); -unsigned char OPLRead(FM_OPL *OPL,int a); -int OPLTimerOver(FM_OPL *OPL,int c); +int Y8950Init (int num, int clock, int rate); +void Y8950Shutdown (void); +void Y8950ResetChip (int which); +int Y8950Write (int which, int a, int v); +unsigned char Y8950Read (int which, int a); +int Y8950TimerOver (int which, int c); +void Y8950UpdateOne (int which, INT16 *buffer, int length); + +void Y8950SetTimerHandler (int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); +void Y8950SetIRQHandler (int which, OPL_IRQHANDLER IRQHandler, int param); +void Y8950SetUpdateHandler (int which, OPL_UPDATEHANDLER UpdateHandler, int param); + +#endif - -/* YM3626/YM3812 local section */ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); - -void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); #endif diff --git a/src/hardware/gus.cpp b/src/hardware/gus.cpp new file mode 100644 index 0000000..160feac --- /dev/null +++ b/src/hardware/gus.cpp @@ -0,0 +1,23 @@ +#include +#include "dosbox.h" +#include "inout.h" +#include "mixer.h" +#include "dma.h" +#include "pic.h" +#include "hardware.h" +#include "setup.h" +#include "programs.h" + + + + + + +void GUS_Init(Section* sec) { + + + + +} + + diff --git a/src/hardware/joystick.cpp b/src/hardware/joystick.cpp index a5bd7f8..f99aea0 100644 --- a/src/hardware/joystick.cpp +++ b/src/hardware/joystick.cpp @@ -46,14 +46,14 @@ static Bit8u read_p201(Bit32u port) { if (stick[0].enabled) { if (stick[0].xcount) stick[0].xcount--; else ret&=~1; if (stick[0].ycount) stick[0].ycount--; else ret&=~2; - if (stick[0].button[0]) ret&=16; - if (stick[0].button[1]) ret&=32; + if (stick[0].button[0]) ret&=~16; + if (stick[0].button[1]) ret&=~32; } if (stick[1].enabled) { if (stick[1].xcount) stick[1].xcount--; else ret&=~4; if (stick[1].ycount) stick[1].ycount--; else ret&=~8; - if (stick[1].button[0]) ret&=64; - if (stick[1].button[1]) ret&=128; + if (stick[1].button[0]) ret&=~64; + if (stick[1].button[1]) ret&=~128; } return ret; } diff --git a/src/hardware/keyboard.cpp b/src/hardware/keyboard.cpp index f65f452..f408ac9 100644 --- a/src/hardware/keyboard.cpp +++ b/src/hardware/keyboard.cpp @@ -48,6 +48,7 @@ struct KeyBlock { KeyCommands command; bool read_active; bool enabled; + bool active; }; static KeyBlock keyb; @@ -87,7 +88,7 @@ void KEYBOARD_AddCode(Bit8u code) { keyb.buf[start]=code; keyb.read_active=true; } - if (keyb.buf_used>0) PIC_ActivateIRQ(1); + if (keyb.buf_used==1) PIC_AddIRQ(1,0); } static Bit8u read_p60(Bit32u port) { @@ -151,7 +152,12 @@ static void write_p61(Bit32u port,Bit8u val) { static void write_p64(Bit32u port,Bit8u val) { switch (val) { - case 0: + case 0xad: /* Activate keyboard */ + keyb.active=true; + break; + case 0xae: /* Deactivate keyboard */ + keyb.active=false; + break; default: LOG_DEBUG("Port 64 write with val %d",val); break; diff --git a/src/hardware/pcspeaker.cpp b/src/hardware/pcspeaker.cpp index 5043df4..f85f289 100644 --- a/src/hardware/pcspeaker.cpp +++ b/src/hardware/pcspeaker.cpp @@ -20,6 +20,7 @@ #include "dosbox.h" #include "mixer.h" #include "timer.h" +#include "setup.h" #ifndef PI @@ -30,20 +31,25 @@ #define SPKR_RATE 22050 #define SPKR_VOLUME 5000 -#define FREQ_SHIFT 16 -#define FREQ_MAX (2 << FREQ_SHIFT) +#define SPKR_SHIFT 16 + +#define SIN_ENT 1024 +#define SIN_MAX (SIN_ENT << SPKR_SHIFT) + +#define FREQ_MAX (2 << SPKR_SHIFT) #define FREQ_HALF (FREQ_MAX >> 1) - - struct Speaker { - Bit32u freq_add; - Bit32u freq_pos; + Bitu freq_add; + Bitu freq_pos; Bit16s volume; MIXER_Channel * chan; bool enabled; bool realsound; + bool sinewave; + Bitu mode; Bit16u buffer[SPKR_BUF]; + Bit16s table[SIN_ENT]; Bitu buf_pos; }; @@ -52,6 +58,7 @@ static Speaker spkr; void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) { + spkr.mode=mode; switch (mode) { case 0: if (cntr>72) cntr=72; @@ -59,8 +66,14 @@ void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) { if (spkr.buf_pos0) { - *(Bit16s*)(stream)=spkr.buffer[buf_pos >> 16]; - buf_pos+=buf_add; - stream+=2; + switch (spkr.mode) { + case 0: + /* 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; + } + break; } - } else { - /* Generate a square wave */ - while (len-->0) { + case 3: + if (spkr.sinewave) while (len-->0) { + spkr.freq_pos+=spkr.freq_add; + spkr.freq_pos&=(SIN_MAX-1); + *(Bit16s*)(stream)=spkr.table[spkr.freq_pos>>SPKR_SHIFT]; + stream+=2; + } else 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) { @@ -92,11 +113,26 @@ static void PCSPEAKER_CallBack(Bit8u * stream,Bit32u len) { } stream+=2; } + break; + case 4: + while (len-->0) { + if (spkr.freq_pos) { + *(Bit16s*)(stream)=spkr.volume; + spkr.freq_pos--; + } else { + *(Bit16s*)(stream)=-spkr.volume; + } + stream+=2; + } + break; } } void PCSPEAKER_Init(Section* sec) { MSG_Add("SPEAKER_CONFIGFILE_HELP","pcspeaker related options.\n"); + Section_prop * section=static_cast(sec); + if(!section->Get_bool("enabled")) return; + spkr.sinewave=section->Get_bool("sinewave"); spkr.chan=MIXER_AddChannel(&PCSPEAKER_CallBack,SPKR_RATE,"PC-SPEAKER"); MIXER_Enable(spkr.chan,false); MIXER_SetMode(spkr.chan,MIXER_16MONO); @@ -104,4 +140,8 @@ void PCSPEAKER_Init(Section* sec) { spkr.enabled=false; spkr.realsound=false; spkr.buf_pos=0; + /* Generate the sine wave */ + for (Bitu i=0;i= pic0_icws) pic0_icw_state=0; } - } static Bit8u read_p20(Bit32u port) { @@ -174,6 +203,13 @@ static void write_pa0(Bit32u port,Bit8u val) { pic1_icw_state=1; break; case 0x20: /* end of interrupt command */ + case 0x21: /* end of interrupt command */ + case 0x22: /* end of interrupt command */ + case 0x23: /* end of interrupt command */ + case 0x24: /* end of interrupt command */ + case 0x25: /* end of interrupt command */ + case 0x26: /* end of interrupt command */ + case 0x27: /* end of interrupt command */ /* clear highest current in service bit */ if (PIC_IRQActive>7 && PIC_IRQActive <16) { irqs[PIC_IRQActive].inservice=false; @@ -218,7 +254,6 @@ 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 */ @@ -292,7 +327,7 @@ void PIC_DeActivateIRQ(Bit32u irq) { } void PIC_runIRQs(void) { - Bit32u i; + Bitu i; if (!flags.intf) return; if (PIC_IRQActive!=PIC_NOIRQ) return; if (!PIC_IRQCheck) return; @@ -304,19 +339,166 @@ void PIC_runIRQs(void) { PIC_IRQCheck&=~(1 << i); Interrupt(irqs[i].vector); PIC_IRQActive=i; - PIC_IRQAgain=true; return; } } } } +static void AddEntry(PICEntry * entry) { + PICEntry * find_entry=pic.next_entry; + if (!find_entry) { + entry->next=0; + pic.next_entry=entry; + return; + } + if (find_entry->index>entry->index) { + pic.next_entry=entry; + entry->next=find_entry; + return; + } + while (find_entry) { + if (find_entry->next) { + /* See if the next index comes later than this one */ + if (find_entry->next->index>entry->index) { + entry->next=find_entry->next; + find_entry->next=entry; + return; + } else { + find_entry=find_entry->next; + } + } else { + entry->next=find_entry->next; + find_entry->next=entry; + return; + } + } +} + +void PIC_AddEvent(PIC_EventHandler handler,Bitu delay) { + if (!pic.free_entry) { + LOG_WARN("PIC:No free queue entries"); + return; + } + PICEntry * entry=pic.free_entry; + Bitu index=delay+PIC_Index(); + entry->index=index; + entry->event=handler; + entry->type=EVENT; + pic.free_entry=pic.free_entry->next; + AddEntry(entry); +} + +void PIC_AddIRQ(Bitu irq,Bitu delay) { + if (irq>15) E_Exit("PIC:Illegal IRQ"); + if (!pic.free_entry) { + LOG_WARN("PIC:No free queue entries"); + return; + } + PICEntry * entry=pic.free_entry; + Bitu index=delay+PIC_Index(); + entry->index=index; + entry->irq=irq; + entry->type=IRQ; + pic.free_entry=pic.free_entry->next; + AddEntry(entry); +} + + +void PIC_RemoveEvents(PIC_EventHandler handler) { + PICEntry * entry=pic.next_entry; + PICEntry * prev_entry; + prev_entry=0; + while (entry) { + switch (entry->type) { + case EVENT: + if (entry->event==handler) { + if (prev_entry) { + prev_entry->next=entry->next; + entry->next=pic.free_entry; + pic.free_entry=entry; + entry=prev_entry->next; + continue; + } else { + pic.next_entry=entry->next; + entry->next=pic.free_entry; + pic.free_entry=entry; + entry=pic.next_entry; + continue; + } + } + break; + } + prev_entry=entry; + entry=entry->next; + } +} + +Bitu PIC_RunQueue(void) { + Bitu ret; + /* Check to see if a new milisecond needs to be started */ + if (CPU_Cycles>0) { + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=0; + } + if (CPU_CycleLeft<=0) { + CPU_CycleLeft=CPU_CycleMax; + } + while (CPU_CycleLeft>0) { + /* Check the queue for an entry */ + Bitu index=PIC_Index(); + while (pic.next_entry && pic.next_entry->index<=index) { + PICEntry * entry=pic.next_entry; + pic.next_entry=entry->next; + switch (entry->type) { + case EVENT: + (entry->event)(); + break; + case IRQ: + PIC_ActivateIRQ(entry->irq); + break; + } + /* Put the entry in the free list */ + entry->next=pic.free_entry; + pic.free_entry=entry; + } + /* Check when to set the new cycle end */ + if (pic.next_entry) { + Bits cycles=PIC_MakeCycles(pic.next_entry->index-index); + if (!cycles) cycles=1; + if (cycles0) { + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=0; + } + if (ret) return ret; + } + /* Go through the list of scheduled irq's and lower their index with 1000 */ + PIC_Ticks++; + PICEntry * entry=pic.next_entry; + while (entry) { + if (entry->index>1000) entry->index-=1000; + else entry->index=0; + entry=entry->next; + } + return 0; +} 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; + PIC_Ticks=0; + Bitu i; for (i=0;i<=7;i++) { irqs[i].active=false; irqs[i].masked=true; @@ -338,6 +520,14 @@ void PIC_Init(Section* sec) { IO_RegisterReadHandler(0xa1,read_pa1,"Slave PIC Data"); IO_RegisterWriteHandler(0xa0,write_pa0,"Slave PIC Command"); IO_RegisterWriteHandler(0xa1,write_pa1,"Slave PIC Data"); + /* Initialize the pic queue */ + for (i=0;icntr; + + Bit64s micro=PIC_MicroCount()-p->start; switch (p->mode) { + case 0: + if (micro>p->micro) p->read_latch=p->write_latch; + else p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr)); + break; case 2: + micro%=p->micro; + p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr)); + break; case 3: - p->read_latch=(Bit16u)ticks; + micro%=p->micro; + micro*=2; + if (micro>p->micro) micro-=p->micro; + p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr)); break; default: LOG_ERROR("PIT:Illegal Mode %d for reading counter %d",p->mode,counter); - p->read_latch=(Bit16u)ticks; + micro%=p->micro; + p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr)); break; } } - static void write_latch(Bit32u port,Bit8u val) { - Bit32u counter=port-0x40; + Bitu counter=port-0x40; PIT_Block * p=&pit[counter]; switch (p->write_state) { case 0: @@ -104,21 +103,21 @@ static void write_latch(Bit32u port,Bit8u val) { if (p->write_state != 0) { if (p->write_latch == 0) p->cntr = 0x10000; else p->cntr = p->write_latch; - p->last_ticks=LastTicks; + p->start=PIC_MicroCount(); + p->micro=1000000/((float)PIT_TICK_RATE/(float)p->cntr); switch (counter) { case 0x00: /* Timer hooked to IRQ 0 */ - PIC_DeActivateIRQ(0); - timer_ticks=p->cntr << PIT_SHIFT; - timer_buildup=0; + PIC_RemoveEvents(PIT0_Event); + PIC_AddEvent(PIT0_Event,p->micro); 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 */ +// LOG_DEBUG("PIT 2 Timer at %.3g Hz mode %d",PIT_TICK_RATE/(double)p->cntr,p->mode); PCSPEAKER_SetCounter(p->cntr,p->mode); break; default: LOG_ERROR("PIT:Illegal timer selected for writing"); } - } } @@ -194,14 +193,10 @@ struct Timer { TIMER_TickHandler handler; } tick; struct{ - Bitu count; - Bitu total; + Bits left; + Bits total; TIMER_MicroHandler handler; } micro; - struct { - Bitu end; - TIMER_DelayHandler handler; - } delay; }; }; @@ -220,85 +215,51 @@ TIMER_Block * TIMER_RegisterMicroHandler(TIMER_MicroHandler handler,Bitu micro) Timer * new_timer=new(Timer); new_timer->type=T_MICRO; new_timer->micro.handler=handler; - new_timer->micro.total=micro; - new_timer->micro.count=0; Timers.push_front(new_timer); + TIMER_SetNewMicro(new_timer,micro); return (TIMER_Block *)new_timer; } -TIMER_Block * TIMER_RegisterDelayHandler(TIMER_DelayHandler handler,Bitu delay) { -//Todo maybe check for a too long delay - Timer * new_timer=new(Timer); - new_timer->type=T_DELAY; - new_timer->delay.handler=handler; - new_timer->delay.end=LastTicks+delay; - Timers.push_front(new_timer); - return (TIMER_Block *)new_timer; - -} void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro) { Timer * timer=(Timer *)block; if (timer->type!=T_MICRO) E_Exit("TIMER:Illegal handler type"); - timer->micro.count=0; timer->micro.total=micro; + Bitu index=PIC_Index(); + while ((1000-index)>micro) { + PIC_AddEvent(timer->micro.handler,micro); + micro+=micro; + index+=micro; + } + timer->micro.left=timer->micro.total-(1000-index); } -void TIMER_AddTicks(Bit32u ticks) { -/* Add pit ticks to the counter */ - timer_buildup+=ticks*pit_ticks; - if (timer_buildup>MAX_PASSED) timer_buildup=MAX_PASSED; +void TIMER_AddTick(void) { + Bits index; /* 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 * timers=(*i); switch (timers->type) { case T_TICK: - if (timer.ticks) timers->tick.handler(timer.ticks); + timers->tick.handler(1); break; case T_MICRO: - 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>timers->delay.end) { - std::list::iterator remove; - timers->delay.handler(); - remove=i++; - Timers.erase(remove); + index=1000; + while (index>=timers->micro.left) { + PIC_AddEvent(timers->micro.handler,timers->micro.left); + index-=timers->micro.left; + timers->micro.left=timers->micro.total; } + timers->micro.left-=index; break; default: E_Exit("TIMER:Illegal handler type"); - }; + } - }; - 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.height){ + LOG_VGA("Split at %d",stop); + goto drawnormal; + } + switch (vga.mode) { + case GFX_16: + buf=&vga.buffer[vga.config.real_start*8+vga.config.pel_panning]; + bufsplit=vga.buffer; + break; + case GFX_256U: + buf=&vga.mem.linear[vga.config.real_start*4+vga.config.pel_panning/2]; + bufsplit=vga.mem.linear; + break; + case GFX_256C: + buf=memory+0xa0000; + bufsplit=memory+0xa0000; + break; + default: + LOG_WARN("VGA:Unhandled split screen mode %d",vga.mode); + goto norender; + } + RENDER_Part(buf,0,0,vga.draw.width,stop); + RENDER_Part(bufsplit,0,stop,vga.draw.width,vga.draw.height-stop); + } else { +drawnormal: + switch (vga.mode) { + case GFX_2: + VGA_DrawGFX2_Fast(vga.buffer,vga.draw.width); + buf=vga.buffer; + break; + case GFX_4: + VGA_DrawGFX4_Fast(vga.buffer,vga.draw.width); + buf=vga.buffer; + break; + case TEXT_16: + VGA_DrawTEXT(vga.buffer,vga.draw.width); + buf=vga.buffer; + break; + case GFX_16: + buf=&vga.buffer[vga.config.real_start*8+vga.config.pel_panning]; + break; + case GFX_256C: + buf=memory+0xa0000; + break; + case GFX_256U: + buf=&vga.mem.linear[vga.config.real_start*4+vga.config.pel_panning/2]; + break; + } + RENDER_Part(buf,0,0,vga.draw.width,vga.draw.height); -void VGA_Render_GFX_2(Bit8u * * data); -void VGA_Render_GFX_4(Bit8u * * data); -void VGA_Render_GFX_16(Bit8u * * data); -void VGA_Render_GFX_256C(Bit8u * * data); -void VGA_Render_GFX_256U(Bit8u * * data); -void VGA_Render_TEXT_16(Bit8u * * data); + + } +norender: + RENDER_EndUpdate(); + + } + VGA_StartRetrace(); +} void VGA_FindSettings(void) { /* Sets up the correct memory handler from the vga.mode setting */ @@ -67,8 +126,10 @@ void VGA_FindSettings(void) { } else if (vga.config.cga_enabled) { /* 4 color cga */ //TODO Detect hercules modes, probably set them up in bios too - if (vga.config.pixel_double) vga.mode=GFX_4; - else vga.mode=GFX_2; + if (vga.seq.clocking_mode & 0x8) { + vga.mode=GFX_4; +// MEM_SetupPageHandlers(PAGE_COUNT(0x0b8000),PAGE_COUNT(0x10000),&VGA_GFX_4_ReadHandler,&VGA_GFX_4_WriteHandler); + } else vga.mode=GFX_2; //TODO Maybe also use a page handler for cga mode } else { /* 16 color ega */ @@ -83,69 +144,96 @@ void VGA_FindSettings(void) { } static void VGA_DoResize(void) { - vga.draw.resizing=false; - Bitu width,height,pitch; - RENDER_Handler * renderer; + /* Calculate the FPS for this screen */ + double fps; + Bitu vtotal=2 + (vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8) | ((vga.crtc.overflow & 0x20) << 4) ); + Bitu htotal=5 + vga.crtc.horizontal_total; + Bitu vdispend = 1 + (vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2)<<7) | ((vga.crtc.overflow & 0x40) << 3) ); + Bitu hdispend = 1 + (vga.crtc.horizontal_display_end); + //TODO Maybe check if blanking comes before display_end - height=vga.config.vdisplayend+1; - if (vga.config.vline_height>0) { - height/=(vga.config.vline_height+1); - } - if (vga.config.vline_double) height>>=1; - width=vga.config.hdisplayend; + double clock=(double)vga.config.clock; + /* Check for 8 for 9 character clock mode */ + if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9; + /* Check for pixel doubling, master clock/2 */ + if (vga.seq.clocking_mode & 0x8) clock/=2; + + LOG_VGA("H total %d, V Total %d",htotal,vtotal); + LOG_VGA("H D End %d, V D End %d",hdispend,vdispend); + fps=clock/(vtotal*htotal); + + vga.draw.resizing=false; + Bitu width,height,pitch,flags; + + flags=0; + vga.draw.lines=height=vdispend; + width=hdispend; + vga.draw.double_height=vga.config.vline_double; + vga.draw.double_width=(vga.seq.clocking_mode & 0x8)>0; + vga.draw.font_height=vga.config.vline_height+1; switch (vga.mode) { case GFX_256C: - renderer=&VGA_Render_GFX_256C; - width<<=2; - pitch=vga.config.scan_len*8; - break; case GFX_256U: + vga.draw.double_width=true; //Hack since 256 color modes use 2 clocks for a pixel + /* Don't know might do this different sometime, will have to do for now */ + if (!vga.draw.double_height) { + if (vga.config.vline_height&1) { + vga.draw.double_height=true; + vga.draw.font_height/=2; + } + } width<<=2; pitch=vga.config.scan_len*8; - renderer=&VGA_Render_GFX_256U; break; case GFX_16: width<<=3; pitch=vga.config.scan_len*16; - renderer=&VGA_Render_GFX_16; break; case GFX_4: width<<=3; - height<<=1; pitch=width; - renderer=&VGA_Render_GFX_4; break; case GFX_2: width<<=3; - height<<=1; pitch=width; - renderer=&VGA_Render_GFX_2; break; case TEXT_16: /* probably a 16-color text mode, got to detect mono mode somehow */ - width<<=3; /* 8 bit wide text font */ - height<<=4; /* 16 bit font height */ + width<<=3; /* 8 bit wide text font */ if (width>640) width=640; if (height>480) height=480; pitch=width; - renderer=&VGA_Render_TEXT_16; }; + if (vga.draw.double_height) { + flags|=DoubleHeight; + height/=2; + } + if (vga.draw.double_width) { + flags|=DoubleWidth; + /* Double width is dividing main clock, the width should be correct already for this */ + } + if (( width != vga.draw.width) || (height != vga.draw.height) || (pitch != vga.draw.pitch)) { + PIC_RemoveEvents(VGA_BlankTimer); + vga.draw.width=width; + vga.draw.height=height; + vga.draw.pitch=pitch; - vga.draw.width=width; - vga.draw.height=height; - RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),0,renderer); - + LOG_VGA("Width %d, Height %d",width,height); + LOG_VGA("Flags %X, fps %f",flags,fps); + RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),flags); + vga.draw.blank=(Bitu)(1000000/fps); + PIC_AddEvent(VGA_BlankTimer,vga.draw.blank); + } }; void VGA_StartResize(void) { if (!vga.draw.resizing) { vga.draw.resizing=true; /* Start a resize after 50 ms */ - TIMER_RegisterDelayHandler(VGA_DoResize,50); + PIC_AddEvent(VGA_DoResize,50000); } } - void VGA_Init(Section* sec) { vga.draw.resizing=false; VGA_SetupMemory(); diff --git a/src/hardware/vga.h b/src/hardware/vga.h index d43dc8e..24537a4 100644 --- a/src/hardware/vga.h +++ b/src/hardware/vga.h @@ -1,4 +1,4 @@ -/* + /* * Copyright (C) 2002 The DOSBox Team * * This program is free software; you can redistribute it and/or modify @@ -20,13 +20,18 @@ #define VGA_H_ #include +#include "dosbox.h" +#undef TEXT +#undef GRAPH +/* conflicts with int10.h */ enum { TEXT, GRAPH }; enum { GFX_256C,GFX_256U,GFX_16,GFX_4,GFX_2, TEXT_16 }; typedef struct { bool attrindex; + Bit16u cursor; } VGA_Internal; typedef struct { @@ -37,9 +42,11 @@ typedef struct { bool retrace; /* A retrace has started */ Bitu scan_len; -/* Screen resolution and memory mode */ - Bitu vdisplayend; - Bitu hdisplayend; +/* Some other screen related variables */ + Bitu line_compare; + + Bitu clock; + bool clock_half; bool chained; /* Enable or Disabled Chain 4 Mode */ bool gfxmode; /* Yes or No Easy no */ @@ -51,7 +58,6 @@ typedef struct { bool vline_double; Bit8u vline_height; - bool pixel_double; /* Pixel Scrolling */ Bit8u pel_panning; /* Amount of pixels to skip when starting horizontal line */ Bit8u hlines_skip; @@ -80,11 +86,16 @@ typedef struct { bool resizing; Bitu width; Bitu height; + Bitu pitch; + Bitu blank; + bool double_width; + bool double_height; + Bitu lines; + Bit8u * font; Bit8u font_height; - Bit8u cursor_enable; - Bit8u cursor_row; - Bit8u cursor_col; - Bit8u cursor_count; + struct { + Bitu row,col,sline,eline,count; + } cursor; } VGA_Draw; @@ -157,7 +168,6 @@ struct RGBEntry { Bit8u red; Bit8u green; Bit8u blue; - Bit8u attr_entry; }; typedef struct { @@ -165,9 +175,11 @@ typedef struct { Bit8u pel_mask; Bit8u pel_index; Bit8u state; - Bit8u index; + Bit8u write_index; + Bit8u read_index; Bitu first_changed; RGBEntry rgb[0x100]; + Bit8u attr[16]; } VGA_Dac; union VGA_Latch { @@ -196,8 +208,8 @@ typedef struct { VGA_Dac dac; VGA_Latch latch; VGA_Memory mem; -//Special little hack to let the memory run over into the buffer - Bit8u buffer[1024*1024]; +/* Extra buffer following main video ram with double data for overflowing of addresses */ + Bit8u buffer[1024*1024]; /* 256 kb vid ram with 16 colors and double addresses */ } VGA_Type; @@ -211,11 +223,10 @@ void VGA_StartResize(void); /* The Different Drawing functions */ void VGA_DrawTEXT(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX256_Fast(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX256_Full(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX16_Full(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu next_line); -void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu next_line); +void VGA_DrawGFX256U_Full(Bit8u * bitdata,Bitu next_line); +void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line); +void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu next_line); +void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu next_line); /* The Different Memory Read/Write Handlers */ Bit8u VGA_NormalReadHandler(Bit32u start); @@ -242,9 +253,10 @@ void VGA_SetupSEQ(void); /* Some Support Functions */ void VGA_DACSetEntirePalette(void); +void VGA_StartRetrace(void); extern VGA_Type vga; -extern Bit8u vga_rom_8[256 * 8]; +extern Bit8u vga_rom_08[256 * 8]; extern Bit8u vga_rom_14[256 * 14]; extern Bit8u vga_rom_16[256 * 16]; @@ -260,6 +272,5 @@ extern Bit32u Expand16BigTable[0x10000]; #define LOG_VGA #endif - #endif diff --git a/src/hardware/vga_attr.cpp b/src/hardware/vga_attr.cpp index 3d4c6b9..4bd4305 100644 --- a/src/hardware/vga_attr.cpp +++ b/src/hardware/vga_attr.cpp @@ -40,6 +40,7 @@ void write_p3c0(Bit32u port,Bit8u val) { case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val&=0x3f; attr(palette[attr(index)])=val; VGA_DAC_CombineColor(attr(index),val); /* @@ -48,10 +49,12 @@ void write_p3c0(Bit32u port,Bit8u val) { */ break; case 0x10: /* Mode Control Register */ - attr(mode_control)=val; - vga.config.gfxmode=val&1; - vga.config.vga_enabled=(val & 64)>0; - VGA_FindSettings(); + if (val != attr(mode_control)) { + attr(mode_control)=val; + vga.config.gfxmode=val&1; + vga.config.vga_enabled=(val & 0x40)>0; + VGA_FindSettings(); + } //TODO Monochrome mode //TODO 9 bit characters //TODO line wrapping split screen shit see bit 5 diff --git a/src/hardware/vga_crtc.cpp b/src/hardware/vga_crtc.cpp index 020866c..588f900 100644 --- a/src/hardware/vga_crtc.cpp +++ b/src/hardware/vga_crtc.cpp @@ -40,9 +40,10 @@ void write_p3d5(Bit32u port,Bit8u val) { /* 0-7 Horizontal Total Character Clocks-5 */ break; case 0x01: /* Horizontal Display End Register */ - crtc(horizontal_display_end)=val; - vga.config.hdisplayend=val+1; - VGA_StartResize(); + if (val != crtc(horizontal_display_end)) { + crtc(horizontal_display_end)=val; + VGA_StartResize(); + } /* 0-7 Number of Character Clocks Displayed -1 */ break; case 0x02: /* Start Horizontal Blanking Register */ @@ -75,7 +76,10 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x06: /* Vertical Total Register */ - crtc(vertical_total)=val; + if (val != crtc(vertical_total)) { + crtc(vertical_total)=val; + VGA_StartResize(); + } /* 0-7 Lower 8 bits of the Vertical Total. Bit 8 is found in 3d4h index 7 bit 0. Bit 9 is found in 3d4h index 7 bit 5. Note: For the VGA this value is the number of scan lines in the display -2. @@ -83,8 +87,11 @@ void write_p3d5(Bit32u port,Bit8u val) { break; case 0x07: /* Overflow Register */ crtc(overflow)=val; - vga.config.vdisplayend=(vga.config.vdisplayend&0xFF)|(((val>>1) & 1)<<8)|(((val>>6) & 1)<<9); - VGA_StartResize(); + vga.config.line_compare=(vga.config.line_compare & 0x2ff) | (val & 0x10) << 4; + if ((vga.crtc.overflow ^ val) & 0xef) { + crtc(overflow)=val; + VGA_StartResize(); + } else crtc(overflow)=val; /* 0 Bit 8 of Vertical Total (3d4h index 6) 1 Bit 8 of Vertical Display End (3d4h index 12h) @@ -110,10 +117,13 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x09: /* Maximum Scan Line Register */ - crtc(maximum_scan_line)=val; vga.config.vline_double=(val & 128)>1; vga.config.vline_height=(val & 0xf); - VGA_StartResize(); + vga.config.line_compare=(vga.config.line_compare & 0x1ff)|(val&0x40)<<3; + if ((vga.crtc.maximum_scan_line ^ val) & 0xbf) { + crtc(maximum_scan_line)=val; + VGA_StartResize(); + } else crtc(maximum_scan_line)=val; /* 0-4 Number of scan lines in a character row -1. In graphics modes this is the number of times (-1) the line is displayed before passing on to @@ -152,16 +162,16 @@ void write_p3d5(Bit32u port,Bit8u val) { case 0x0E: /*Cursor Location High Register */ crtc(cursor_location_high)=val; if (vga.config.scan_len<2) break; - vga.draw.cursor_row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2); - vga.draw.cursor_col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2); + vga.draw.cursor.row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2); + vga.draw.cursor.col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2); /* 0-7 Upper 8 bits of the address of the cursor */ break; case 0x0F: /* Cursor Location Low Register */ //TODO update cursor on screen crtc(cursor_location_low)=val; if (vga.config.scan_len<2) break; - vga.draw.cursor_row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2); - vga.draw.cursor_col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2); + vga.draw.cursor.row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2); + vga.draw.cursor.col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2); /* 0-7 Lower 8 bits of the address of the cursor */ break; case 0x10: /* Vertical Retrace Start Register */ @@ -186,9 +196,10 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x12: /* Vertical Display End Register */ - crtc(vertical_display_end)=val; - vga.config.vdisplayend=(vga.config.vdisplayend & 0x300)|val; - VGA_StartResize(); + if (val!=crtc(vertical_display_end)) { + crtc(vertical_display_end)=val; + VGA_StartResize(); + } /* 0-7 Lower 8 bits of Vertical Display End. The display ends when the line counter reaches this value. Bit 8 is found in 3d4h index 7 bit 1. @@ -196,9 +207,11 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x13: /* Offset register */ - crtc(offset)=val; - vga.config.scan_len=val; - VGA_StartResize(); + if (val!=crtc(offset)) { + crtc(offset)=val; + vga.config.scan_len=val; + VGA_StartResize(); + } /* 0-7 Number of bytes in a scanline / K. Where K is 2 for byte mode, 4 for word mode and 8 for Double Word mode. @@ -228,9 +241,11 @@ void write_p3d5(Bit32u port,Bit8u val) { */ break; case 0x17: /* Mode Control Register */ - crtc(mode_control)=val; - vga.config.cga_enabled=!((val&1)>0); - VGA_FindSettings(); + if (val!=crtc(mode_control)) { + crtc(mode_control)=val; + vga.config.cga_enabled=!((val&1)>0); + VGA_FindSettings(); + } /* 0 If clear use CGA compatible memory addressing system by substituting character row scan counter bit 0 for address bit 13, @@ -249,6 +264,7 @@ void write_p3d5(Bit32u port,Bit8u val) { break; case 0x18: /* Line Compare Register */ crtc(line_compare)=val; + vga.config.line_compare=(vga.config.line_compare & 0x300) | val; /* 0-7 Lower 8 bits of the Line Compare. When the Line counter reaches this value, the display address wraps to 0. Provides Split Screen diff --git a/src/hardware/vga_dac.cpp b/src/hardware/vga_dac.cpp index e6a5dcd..a4b400c 100644 --- a/src/hardware/vga_dac.cpp +++ b/src/hardware/vga_dac.cpp @@ -65,13 +65,13 @@ static Bit8u read_p3c6(Bit32u port) { static void write_p3c7(Bit32u port,Bit8u val) { - vga.dac.index=val; + vga.dac.read_index=val; vga.dac.pel_index=0; vga.dac.state=DAC_READ; } static void write_p3c8(Bit32u port,Bit8u val) { - vga.dac.index=val; + vga.dac.write_index=val; vga.dac.pel_index=0; vga.dac.state=DAC_WRITE; } @@ -79,36 +79,36 @@ static void write_p3c8(Bit32u port,Bit8u val) { static void write_p3c9(Bit32u port,Bit8u val) { switch (vga.dac.pel_index) { case 0: - vga.dac.rgb[vga.dac.index].red=val; + vga.dac.rgb[vga.dac.write_index].red=val; vga.dac.pel_index=1; break; case 1: - vga.dac.rgb[vga.dac.index].green=val; + vga.dac.rgb[vga.dac.write_index].green=val; vga.dac.pel_index=2; break; case 2: - vga.dac.rgb[vga.dac.index].blue=val; + vga.dac.rgb[vga.dac.write_index].blue=val; switch (vga.mode) { case GFX_256C: case GFX_256U: - RENDER_SetPal(vga.dac.index, - vga.dac.rgb[vga.dac.index].red << 2, - vga.dac.rgb[vga.dac.index].green << 2, - vga.dac.rgb[vga.dac.index].blue << 2 + RENDER_SetPal(vga.dac.write_index, + vga.dac.rgb[vga.dac.write_index].red << 2, + vga.dac.rgb[vga.dac.write_index].green << 2, + vga.dac.rgb[vga.dac.write_index].blue << 2 ); break; default: /* Check for attributes and DAC entry link */ - if (vga.dac.rgb[vga.dac.index].attr_entry>15) return; - if (vga.attr.palette[vga.dac.rgb[vga.dac.index].attr_entry]==vga.dac.index) { - RENDER_SetPal(vga.dac.rgb[vga.dac.index].attr_entry, - vga.dac.rgb[vga.dac.index].red << 2, - vga.dac.rgb[vga.dac.index].green << 2, - vga.dac.rgb[vga.dac.index].blue << 2 - ); + for (Bitu i=0;i<16;i++) { + if (vga.dac.attr[i]==vga.dac.write_index) { + RENDER_SetPal(i, + vga.dac.rgb[vga.dac.write_index].red << 2, + vga.dac.rgb[vga.dac.write_index].green << 2, + vga.dac.rgb[vga.dac.write_index].blue << 2); + } } } - vga.dac.index++; + vga.dac.write_index++; vga.dac.pel_index=0; break; default: @@ -120,16 +120,16 @@ static Bit8u read_p3c9(Bit32u port) { Bit8u ret; switch (vga.dac.pel_index) { case 0: - ret=vga.dac.rgb[vga.dac.index].red; + ret=vga.dac.rgb[vga.dac.read_index].red; vga.dac.pel_index=1; break; case 1: - ret=vga.dac.rgb[vga.dac.index].green; + ret=vga.dac.rgb[vga.dac.read_index].green; vga.dac.pel_index=2; break; case 2: - ret=vga.dac.rgb[vga.dac.index].blue; - vga.dac.index++; + ret=vga.dac.rgb[vga.dac.read_index].blue; + vga.dac.read_index++; vga.dac.pel_index=0; break; default: @@ -140,7 +140,8 @@ static Bit8u read_p3c9(Bit32u port) { void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) { /* Check if this is a new color */ - vga.dac.rgb[pal].attr_entry=attr; + vga.dac.attr[attr]=pal; + if (vga.mode != GFX_256U && vga.mode != GFX_256C) RENDER_SetPal(attr, vga.dac.rgb[pal].red << 2, vga.dac.rgb[pal].green << 2, @@ -154,6 +155,8 @@ void VGA_SetupDAC(void) { vga.dac.pel_mask=0xff; vga.dac.pel_index=0; vga.dac.state=DAC_READ; + vga.dac.read_index=0; + vga.dac.write_index=0; /* Setup the DAC IO port Handlers */ IO_RegisterWriteHandler(0x3c6,write_p3c6,"PEL Mask"); diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index 49d1a84..006b1e1 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -21,43 +21,11 @@ #include "video.h" #include "vga.h" +//TODO Make the full draw like the vga really does from video memory. -/* This Should draw a complete 16 colour screen */ -void VGA_Render_GFX_2(Bit8u * * data) { - *data=vga.buffer; - VGA_DrawGFX2_Full(vga.buffer,vga.draw.width); - vga.config.retrace=true; -} - -void VGA_Render_GFX_4(Bit8u * * data) { - *data=vga.buffer; - VGA_DrawGFX4_Full(vga.buffer,vga.draw.width); - vga.config.retrace=true; -} - -void VGA_Render_GFX_16(Bit8u * * data) { - *data=&vga.buffer[vga.config.display_start*8+vga.config.pel_panning]; - vga.config.retrace=true; -} - -void VGA_Render_GFX_256U(Bit8u * * data) { - *data=&vga.mem.linear[vga.config.display_start*4+vga.config.pel_panning]; - vga.config.retrace=true; -} - -void VGA_Render_GFX_256C(Bit8u * * data) { - *data=memory+0xa0000; - vga.config.retrace=true; -} - -void VGA_Render_TEXT_16(Bit8u * * data) { - *data=vga.buffer; - if (!vga.draw.resizing) VGA_DrawTEXT(vga.buffer,vga.draw.width); - vga.config.retrace=true; -} - -void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu pitch) { +void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu pitch) { Bit8u * reader=HostMake(0xB800,0); + Bit8u * flip=HostMake(0xB800,8*1024); Bit8u * draw; for (Bitu y=0;y>3;x++) { + for (Bit32u x=vga.draw.width>>3;x>0;x--) { Bit8u val=*(tempread++); *(draw+0)=(val>>7)&1; *(draw+1)=(val>>6)&1; @@ -81,14 +49,12 @@ void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu pitch) { draw+=8; } bitdata+=pitch; - }; - vga.config.retrace=true; + } } - - -void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) { - Bit8u * reader=HostMake(0xB800,0); +void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu pitch) { + Bit8u * reader=HostMake(0xB800,vga.config.display_start*2); + Bit8u * flip=HostMake(0xB800,8*1024); Bit8u * draw; for (Bitu y=0;y=flip) reader-=8*1024; + } draw=bitdata; for (Bit32u x=0;x>2;x++) { Bit8u val=*(tempread++); @@ -104,12 +71,10 @@ void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) { draw+=4; } bitdata+=pitch; - }; - vga.config.retrace=true; + } } /* Draw the screen using the lookup buffer */ -//TODO include split screen or something void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line) { Bit8u * reader=&vga.buffer[vga.config.display_start*8+vga.config.pel_panning]; for (Bitu y=0;y=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; - } - vga.draw.cursor_count++; - if (vga.draw.cursor_count>16) vga.draw.cursor_count=0; + if(!(vga.internal.cursor & 0x2000)) { + /* Draw a cursor */ + 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; + } + vga.draw.cursor.count++; + if (vga.draw.cursor.count>16) vga.draw.cursor.count=0; + } }; diff --git a/src/hardware/vga_gfx.cpp b/src/hardware/vga_gfx.cpp index ff7b6a1..a6e00d2 100644 --- a/src/hardware/vga_gfx.cpp +++ b/src/hardware/vga_gfx.cpp @@ -70,6 +70,7 @@ void write_p3cf(Bit32u port,Bit8u val) { case 3: /* Data Rotate */ gfx(data_rotate)=val; vga.config.data_rotate=val & 7; + if (vga.config.data_rotate) LOG_WARN("VGA:Data Rotate used %d",val &7); vga.config.raster_op=(val>>3) & 3; /* 0-2 Number of positions to rotate data right before it is written to diff --git a/src/hardware/vga_memory.cpp b/src/hardware/vga_memory.cpp index c0ed822..32af55b 100644 --- a/src/hardware/vga_memory.cpp +++ b/src/hardware/vga_memory.cpp @@ -92,20 +92,21 @@ INLINE static Bit32u ModeOperation(Bit8u val) { } Bit8u VGA_GFX_4_ReadHandler(Bit32u start) { - return vga.mem.linear[start]; + return vga.mem.linear[start-0xb8000]; } void VGA_GFX_4_WriteHandler(Bit32u start,Bit8u val) { - start-=0xa0000; + start-=0xb8000; vga.mem.linear[start]=val; - Bitu line=start / 320; - Bitu x=start % 320; - Bit8u * draw=&vga.buffer[start<<2]; + Bitu off; + if (start>0x2000) off=320*(((start-0x2000)/80)*2+1)+((start-0x2000) % 80)*4; + else off=320*(((start)/80)*2)+(start % 80)*4; + Bit32u * draw=(Bit32u *)&vga.buffer[off]; /* TODO Could also use a Bit32u lookup table for this */ - *(draw+0)=(val>>6)&3; - *(draw+1)=(val>>4)&3; - *(draw+2)=(val>>2)&3; - *(draw+3)=(val)&3; + *draw=CGAWriteTable[val]; + draw=(Bit32u *)&vga.buffer[off+0x4000*4]; + *draw=CGAWriteTable[val]; + } void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val) { diff --git a/src/hardware/vga_misc.cpp b/src/hardware/vga_misc.cpp index e2fa92e..9202e91 100644 --- a/src/hardware/vga_misc.cpp +++ b/src/hardware/vga_misc.cpp @@ -18,9 +18,10 @@ #include "dosbox.h" #include "inout.h" -#include "timer.h" +#include "pic.h" #include "vga.h" + static Bit8u flip=0; static Bit32u keep_vretrace; static bool keeping=false; @@ -34,22 +35,12 @@ Bit8u read_p3d5(Bit32u port); static Bit8u read_p3da(Bit32u port) { vga.internal.attrindex=false; if (vga.config.retrace) { - vga.config.retrace=false; - vga.config.real_start=vga.config.display_start; - keep_vretrace=LastTicks+1; - keeping=true; - flip=0; return 9; } - if (keeping) { - if (LastTicks>(keep_vretrace)) keeping=false; - return 9; - } else { - flip++; - if (flip>10) flip=0; - if (flip>5) return 1; - return 0; - } + flip++; + if (flip>10) flip=0; + if (flip>5) return 1; + return 0; /* 0 Either Vertical or Horizontal Retrace active if set 3 Vertical Retrace in progress if set @@ -58,6 +49,7 @@ static Bit8u read_p3da(Bit32u port) { static void write_p3d8(Bit32u port,Bit8u val) { + LOG_DEBUG("Write %2X to 3da",val); /* 3 Vertical Sync Select. If set Vertical Sync to the monitor is the logical OR of the vertical sync and the vertical display enable. @@ -66,7 +58,8 @@ static void write_p3d8(Bit32u port,Bit8u val) { static void write_p3c2(Bit32u port,Bit8u val) { p3c2data=val; - if (val & 1) { + + if (val & 0x1) { IO_RegisterWriteHandler(0x3d4,write_p3d4,"VGA:CRTC Index Select"); IO_RegisterReadHandler(0x3d4,read_p3d4,"VGA:CRTC Index Select"); IO_RegisterWriteHandler(0x3d5,write_p3d5,"VGA:CRTC Data Register"); @@ -75,7 +68,6 @@ static void write_p3c2(Bit32u port,Bit8u val) { IO_FreeReadHandler(0x3b4); IO_FreeWriteHandler(0x3b5); IO_FreeReadHandler(0x3b5); - } else { IO_RegisterWriteHandler(0x3b4,write_p3d4,"VGA:CRTC Index Select"); IO_RegisterReadHandler(0x3b4,read_p3d4,"VGA:CRTC Index Select"); @@ -86,6 +78,11 @@ static void write_p3c2(Bit32u port,Bit8u val) { IO_FreeWriteHandler(0x3d5); IO_FreeReadHandler(0x3d5); } + if (val & 0x4) vga.config.clock=28322000; + else vga.config.clock=25175000; + + VGA_StartResize(); + /* 0 If set Color Emulation. Base Address=3Dxh else Mono Emulation. Base Address=3Bxh. 2-3 Clock Select. 0: 25MHz, 1: 28MHz @@ -105,6 +102,17 @@ static Bit8u read_p3cc(Bit32u port) { } +static void EndRetrace(void) { + vga.config.retrace=false; +} + +void VGA_StartRetrace(void) { + /* Setup a timer to destroy the vertical retrace bit in a few microseconds */ + vga.config.real_start=vga.config.display_start; + vga.config.retrace=true; + PIC_AddEvent(EndRetrace,667); +} + void VGA_SetupMisc(void) { IO_RegisterReadHandler(0x3da,read_p3da,"VGA Input Status 1"); IO_RegisterReadHandler(0x3ba,read_p3da,"VGA Input Status 1"); diff --git a/src/hardware/vga_seq.cpp b/src/hardware/vga_seq.cpp index 9a7aa0c..15f0aa4 100644 --- a/src/hardware/vga_seq.cpp +++ b/src/hardware/vga_seq.cpp @@ -36,9 +36,10 @@ void write_p3c5(Bit32u port,Bit8u val) { seq(reset)=val; break; case 1: /* Clocking Mode */ - seq(clocking_mode)=val; - vga.config.pixel_double=(val & 8)>0; - VGA_FindSettings(); + if (val!=seq(clocking_mode)) { + seq(clocking_mode)=val; + VGA_StartResize(); + } /* TODO Figure this out :) 0 If set character clocks are 8 dots wide, else 9. 2 If set loads video serializers every other character diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index 64c8020..8369786 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -22,9 +22,10 @@ #include "callback.h" #include "inout.h" #include "mem.h" -#include "timer.h" +#include "pic.h" static Bitu call_int1a,call_int11,call_int8,call_int17,call_int12,call_int15,call_int1c; +static Bitu call_int1; static Bitu INT1A_Handler(void) { switch (reg_ah) { @@ -104,9 +105,19 @@ static Bitu INT8_Handler(void) { /* decrease floppy motor timer */ Bit8u val = mem_readb(BIOS_DISK_MOTOR_TIMEOUT); if (val>0) mem_writeb(BIOS_DISK_MOTOR_TIMEOUT,val-1); - + /* and running drive */ + mem_writeb(BIOS_DRIVE_RUNNING,mem_readb(BIOS_DRIVE_RUNNING) & 0xF0); + // Save ds,dx,ax + Bit16u oldds = SegValue(ds); + Bit16u olddx = reg_dx; + Bit16u oldax = reg_ax; + // run int 1c CALLBACK_RunRealInt(0x1c); IO_Write(0x20,0x20); + // restore old values + SegSet16(ds,oldds); + reg_dx = olddx; + reg_ax = oldax; return CBRET_NONE; }; @@ -159,7 +170,8 @@ static Bitu INT15_Handler(void) { 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); + PIC_RemoveEvents(&WaitFlagEvent); + PIC_AddEvent(&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? @@ -177,7 +189,11 @@ static Bitu INT15_Handler(void) { CALLBACK_SCF(false); break; case 0x90: /* OS HOOK - DEVICE BUSY */ - CALLBACK_SCF(true); + CALLBACK_SCF(false); + reg_ah=0; + break; + case 0x91: /* OS HOOK - DEVICE POST */ + CALLBACK_SCF(false); reg_ah=0; break; case 0xc2: /* BIOS PS2 Pointing Device Support */ @@ -197,12 +213,16 @@ static Bitu INT15_Handler(void) { CALLBACK_SCF(false); } return CBRET_NONE; -}; - -static void INT15_StartUp(void) { -/* TODO Start the time correctly */ -}; +} +static Bitu INT1_Single_Step(void) { + static bool warned=false; + if (!warned) { + warned=true; + LOG_WARN("INT 1:Single Step called"); + } + return CBRET_NONE; +} void BIOS_SetupKeyboard(void); void BIOS_SetupDisks(void); @@ -244,13 +264,20 @@ void BIOS_Init(Section* sec) { RealSetVec(0x17,CALLBACK_RealPointer(call_int17)); /* INT 1A TIME and some other functions */ call_int1a=CALLBACK_Allocate(); - CALLBACK_Setup(call_int1a,&INT1A_Handler,CB_IRET); + CALLBACK_Setup(call_int1a,&INT1A_Handler,CB_IRET_STI); RealSetVec(0x1A,CALLBACK_RealPointer(call_int1a)); /* INT 1C System Timer tick called from INT 8 */ - call_int1c=CALLBACK_Allocate(); + call_int1c=CALLBACK_Allocate(); CALLBACK_Setup(call_int1c,&INT1C_Handler,CB_IRET); RealSetVec(0x1C,CALLBACK_RealPointer(call_int1c)); + /* Some defeault CPU error interrupt handlers */ + call_int1=CALLBACK_Allocate(); + CALLBACK_Setup(call_int1,&INT1_Single_Step,CB_IRET); + RealSetVec(0x1,CALLBACK_RealPointer(call_int1)); + + /* Test for some hardware */ + if (IO_Read(0x378)!=0xff) real_writed(0x40,0x08,0x378); } diff --git a/src/ints/bios_disk.cpp b/src/ints/bios_disk.cpp index da24f79..cb53cb2 100644 --- a/src/ints/bios_disk.cpp +++ b/src/ints/bios_disk.cpp @@ -21,7 +21,7 @@ #include "bios.h" #include "regs.h" #include "mem.h" - +#include "dos_inc.h" /* for Drives[] */ static Bitu call_int13; static BIOS_Disk * Floppys[2]; @@ -31,11 +31,28 @@ static Bit8u last_status; static Bitu INT13_SmallHandler(void) { switch (reg_ah) { + case 0x0: + reg_ah=0x00; + CALLBACK_SCF(false); + LOG_DEBUG("reset disk return succesfull"); + break; case 0x02: /* Read Disk Sectors */ LOG_DEBUG("INT13:02:Read Disk Sectors not supported failing"); - reg_ah=0xff; + reg_ah=0x80; CALLBACK_SCF(true); break; + case 0x04: + if(Drives[reg_dl]!=NULL) { + reg_ah=0; + CALLBACK_SCF(false); + } + else{ + reg_ah=0x80; + CALLBACK_SCF(true); + } + LOG_DEBUG("INT 13:04 Verify sector used on %d, with result %d",reg_dl,reg_ah); + break; + case 0x08: /* Get Drive Parameters */ LOG_DEBUG("INT13:08:Get Drive parameters not supported failing"); reg_ah=0xff; diff --git a/src/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index 3fcc447..afeaafc 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -293,7 +293,7 @@ static Bitu INT16_Handler(void) { //TODO find a more elegant way to do this do { temp=get_key(); - if (temp==0) { flags.intf=true;CALLBACK_Idle();}; + if (temp==0) { CALLBACK_Idle();}; } while (temp==0); reg_ax=temp; break; @@ -354,7 +354,7 @@ void BIOS_SetupKeyboard(void) { /* Allocate a callback for int 0x16 and for standard IRQ 1 handler */ call_int16=CALLBACK_Allocate(); call_irq1=CALLBACK_Allocate(); - CALLBACK_Setup(call_int16,&INT16_Handler,CB_IRET); + CALLBACK_Setup(call_int16,&INT16_Handler,CB_IRET_STI); RealSetVec(0x16,CALLBACK_RealPointer(call_int16)); CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRET); RealSetVec(0x9,CALLBACK_RealPointer(call_irq1)); diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index 0a8cb52..24329d1 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -34,7 +34,7 @@ #define EMM_PAGEFRAME 0xE000 #define EMM_MAX_HANDLES 50 /* 255 Max */ #define EMM_PAGE_SIZE (16*1024) -#define EMM_MAX_PAGES (C_MEM_EMS_SIZE * 1024 / 16 ) +#define EMM_MAX_PAGES (32 * 1024 / 16 ) #define EMM_MAX_PHYS 4 /* 4 16kb pages in pageframe */ #define EMM_VERSION 0x40 @@ -83,7 +83,7 @@ struct EMM_Mapping { }; struct EMM_Page { - void * memory; + HostPt * memory; Bit16u handle; Bit16u next; }; @@ -91,7 +91,7 @@ struct EMM_Page { struct EMM_Handle { Bit16u first_page; Bit16u pages; - char name[9]; + char name[8]; bool saved_page_map; EMM_Mapping page_map[EMM_MAX_PHYS]; }; @@ -100,8 +100,21 @@ 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]; +static Bitu emm_page_count; Bitu call_int67; +struct MoveRegion { + Bit32u bytes; + Bit8u src_type; + Bit16u src_handle; + Bit16u src_offset; + Bit16u src_page_seg; + Bit8u dest_type; + Bit16u dest_handle; + Bit16u dest_offset; + Bit16u dest_page_seg; +}; + #if EMM_USEHANDLER Bit8u EMM_ReadHandler(PhysPt start) { start-=EMM_PAGEFRAME * 16; @@ -118,12 +131,18 @@ void EMM_WriteHandler(PhysPt start,Bit8u val) { static Bit16u EMM_GetFreePages(void) { Bit16u count=0; - for (Bitu index=0;index=EMM_MAX_HANDLES) return false; + if (emm_handles[handle].pages==NULL_HANDLE) return false; + return true; +} + static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) { /* Check for 0 page allocation */ if (!pages) return EMM_ZERO_PAGES; @@ -140,14 +159,14 @@ static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) { while (pages) { if (emm_pages[page].handle==NULL_HANDLE) { emm_pages[page].handle=handle; - emm_pages[page].memory=malloc(EMM_PAGE_SIZE); + emm_pages[page].memory=(HostPt *)malloc(EMM_PAGE_SIZE); if (!emm_pages[page].memory) E_Exit("EMM:Cannont allocate memory"); if (last!=NULL_PAGE) emm_pages[last].next=page; else emm_handles[handle].first_page=page; last=page; pages--; } else { - if (++page>=EMM_MAX_PAGES) E_Exit("EMM:Ran out of pages"); + if (++page>=emm_page_count) E_Exit("EMM:Ran out of pages"); } } return EMM_NO_ERROR; @@ -190,14 +209,14 @@ static Bit8u EMM_ReallocatePages(Bit16u handle,Bit16u & pages) { while (pages) { if (emm_pages[page].handle==NULL_HANDLE) { emm_pages[page].handle=handle; - emm_pages[page].memory=malloc(EMM_PAGE_SIZE); + emm_pages[page].memory=(HostPt *)malloc(EMM_PAGE_SIZE); if (!emm_pages[page].memory) E_Exit("EMM:Cannont allocate memory"); if (last!=NULL_PAGE) emm_pages[last].next=page; else emm_handles[handle].first_page=page; last=page; pages--; } else { - if (++page>=EMM_MAX_PAGES) E_Exit("EMM:Ran out of pages"); + if (++page>=emm_page_count) E_Exit("EMM:Ran out of pages"); } } pages=emm_handles[handle].pages; @@ -264,7 +283,7 @@ static Bit8u EMM_ReleaseMemory(Bit16u handle) { emm_handles[handle].first_page=NULL_PAGE; emm_handles[handle].pages=NULL_HANDLE; emm_handles[handle].saved_page_map=false; - memset(&emm_handles[handle].name,0,9); + memset(&emm_handles[handle].name,0,8); return EMM_NO_ERROR; } @@ -351,9 +370,143 @@ static Bit8u EMM_PartialPageMapping(void) { LOG_ERROR("EMS:Call %2X Subfunction %2X not supported",reg_ah,reg_al); return EMM_FUNC_NOSUP; } - return 0; + return EMM_NO_ERROR; } +static Bit8u HandleNameSearch(void) { + Bit16u handle=0;PhysPt data; + switch (reg_al) { + case 0x00: /* Get all handle names */ + reg_al=0;data=SegPhys(es)+reg_di; + for (handle=0;handle1) { + LOG_ERROR("EMS:Call %2X Subfunction %2X not supported",reg_ah,reg_al); + return EMM_FUNC_NOSUP; + } + LoadMoveRegion(SegPhys(ds)+reg_si,region); +/* Parse the region for information */ + PhysPt src_mem,dest_mem; + Bit16u src_page,dest_page;Bitu src_off,dest_off;Bitu src_remain,dest_remain; + if (!region.src_type) { + src_mem=region.src_page_seg*16+region.src_offset; + } else { + if (!ValidHandle(region.src_handle)) return EMM_INVALID_HANDLE; + if (emm_handles[region.src_handle].pages*EMM_PAGE_SIZE < (region.src_page_seg*EMM_PAGE_SIZE)+region.src_offset+region.bytes) return EMM_LOG_OUT_RANGE; + src_page=emm_handles[region.src_handle].first_page; + while (region.src_page_seg>0) { + src_page=emm_pages[src_page].next; + region.src_page_seg--; + } + src_off=region.src_offset; + src_remain=EMM_PAGE_SIZE-src_off; + } + if (!region.dest_type) { + dest_mem=region.dest_page_seg*16+region.dest_offset; + } else { + if (!ValidHandle(region.dest_handle)) return EMM_INVALID_HANDLE; + if (emm_handles[region.dest_handle].pages*EMM_PAGE_SIZE < (region.dest_page_seg*EMM_PAGE_SIZE)+region.dest_offset+region.bytes) return EMM_LOG_OUT_RANGE; + dest_page=emm_handles[region.dest_handle].first_page; + while (region.dest_page_seg>0) { + dest_page=emm_pages[dest_page].next; + region.dest_page_seg--; + } + dest_off=region.dest_offset; + dest_remain=EMM_PAGE_SIZE-dest_off; + } + Bitu toread; + while (region.bytes>0) { + if (region.bytes>EMM_PAGE_SIZE) toread=EMM_PAGE_SIZE; + else toread=region.bytes; + /* Read from the source */ + if (!region.src_type) { + MEM_BlockRead(src_mem,buf_src,toread); + } else { + if (toread=EMM_MAX_HANDLES || emm_handles[reg_bx].pages==NULL_HANDLE) {reg_ah=EMM_INVALID_HANDLE;break;} + if (!ValidHandle(reg_bx)) {reg_ah=EMM_INVALID_HANDLE;break;} reg_bx=emm_handles[reg_dx].pages; reg_ah=EMM_NO_ERROR; break; @@ -431,7 +583,6 @@ static Bitu INT67_Handler(void) { 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) { @@ -467,6 +618,13 @@ static Bitu INT67_Handler(void) { reg_ah=EMM_NO_ERROR; } break; + case 0x54: /* Handle Functions */ + reg_ah=HandleNameSearch(); + break; + case 0x57: /* Memory region */ + reg_ah=MemoryRegion(); + if (reg_ah) LOG_WARN("ems 57 move failed"); + break; case 0x58: // Get mappable physical array address array if (reg_al==0x00) { PhysPt data = SegPhys(es)+reg_di; @@ -498,6 +656,12 @@ void EMS_Init(Section* sec) { Section_prop * section=static_cast(sec); Bitu size=section->Get_int("emssize"); if (!size) return; + if ((size*(1024/16))>EMM_MAX_PAGES) { + LOG_DEBUG("EMS Max size is %d",EMM_MAX_PAGES/(1024/16)); + emm_page_count=EMM_MAX_PAGES; + } else { + emm_page_count=size*(1024/16); + } call_int67=CALLBACK_Allocate(); CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET); /* Register the ems device */ @@ -515,7 +679,7 @@ void EMS_Init(Section* sec) { RealSetVec(0x67,RealMake(seg,0)); /* Clear handle and page tables */ Bitu i; - for (i=0;itwidth*rnew)*(curmode->cheight/2)+cleft)*2; + PhysPt src=base+((curmode->twidth*rold)*(curmode->cheight/2)+cleft)*2; + Bitu copy=(cright-cleft)*2;Bitu nextline=curmode->twidth*2; + for (Bits i=0;icheight/2;i++) { + MEM_BlockCopy(dest,src,copy); + MEM_BlockCopy(dest+8*1024,src+8*1024,copy); + dest+=nextline;src+=nextline; + } +} + static INLINE void PLANAR4_CopyRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) { PhysPt src,dest;Bitu copy; dest=base+(curmode->twidth*rnew)*curmode->cheight+cleft; @@ -38,7 +49,6 @@ static INLINE void PLANAR4_CopyRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,B for (;copy>0;copy--) { for (Bitu x=0;xtwidth*row)*(curmode->cheight/2)+cleft)*2; + Bitu copy=(cright-cleft)*2;Bitu nextline=curmode->twidth*2; + for (Bits i=0;icheight/2;i++) { + for (Bitu x=0;xrlr) return; @@ -116,9 +137,10 @@ void INT10_ScrollWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8s nlines,Bit case MTEXT: case CTEXT: TEXT_CopyRow(curmode,cul,clr,start,start+nlines,base);break; + case CGA: + CGA_CopyRow(curmode,cul,clr,start,start+nlines,base);break; case PLANAR4: PLANAR4_CopyRow(curmode,cul,clr,start,start+nlines,base);break; - } } while (start!=end); /* Fill some lines */ @@ -134,6 +156,8 @@ filling: case MTEXT: case CTEXT: TEXT_FillRow(curmode,cul,clr,start,base,attr);break; + case CGA: + CGA_FillRow(curmode,cul,clr,start,base,attr);break; case PLANAR4: PLANAR4_FillRow(curmode,cul,clr,start,base,attr);break; } @@ -260,9 +284,6 @@ INLINE static void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit8u chr,Bit8u at } } - - - void INT10_WriteChar(Bit8u chr,Bit8u attr,Bit8u page,Bit16u count,bool showattr) { if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); Bit8u cur_row=CURSOR_POS_ROW(page); diff --git a/src/ints/int10_modes.cpp b/src/ints/int10_modes.cpp index 7932d2b..1f57897 100644 --- a/src/ints/int10_modes.cpp +++ b/src/ints/int10_modes.cpp @@ -20,6 +20,7 @@ #include "mem.h" #include "inout.h" #include "int10.h" +#include "mouse.h" //TODO Maybe also add PCJR Video Modes could be nice :) //TODO include some credits to bochs/plex86 bios i used for info/tables @@ -387,8 +388,7 @@ void INT10_SetVideoMode(Bit8u mode) { real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1); 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_SWITCHES,0x09); 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 @@ -410,4 +410,18 @@ void INT10_SetVideoMode(Bit8u mode) { INT10_SetActivePage(0); /* Set some interrupt vectors */ RealSetVec(0x43,int10_romarea.font_8_first); + /* Tell mouse resolution change */ + Mouse_SetResolution(vga_modes[line].swidth,vga_modes[line].sheight); }; + +void INT10_SetGfxControllerToDefault() +// reset gfx controller to default values +// needed for drawing mouse pointer +{ + Bit8u line=FindVideoMode(real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)&127); + // Set Grafx Ctl + for(Bit8u 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]); + } +}; \ No newline at end of file diff --git a/src/ints/mouse.cpp b/src/ints/mouse.cpp index ad3a084..50bcf6a 100644 --- a/src/ints/mouse.cpp +++ b/src/ints/mouse.cpp @@ -29,6 +29,9 @@ static Bitu call_int33,call_int74; +// forward +void WriteMouseIntVector(void); + struct button_event { Bit16u type; Bit16u buttons; @@ -40,6 +43,30 @@ struct button_event { #define POS_X (Bit16s)(mouse.x) #define POS_Y (Bit16s)(mouse.y) +#define CURSORX 16 +#define CURSORY 16 +#define HIGHESTBIT (1<<(CURSORX-1)) + +static Bit16u defaultTextAndMask = 0x77FF; +static Bit16u defaultTextXorMask = 0x7700; + +static Bit16u defaultScreenMask[CURSORY] = { + 0x3FFF, 0x1FFF, 0x0FFF, 0x07FF, + 0x03FF, 0x01FF, 0x00FF, 0x007F, + 0x003F, 0x001F, 0x01FF, 0x00FF, + 0x30FF, 0xF87F, 0xF87F, 0xFCFF +}; + +static Bit16u defaultCursorMask[CURSORY] = { + 0x0000, 0x4000, 0x6000, 0x7000, + 0x7800, 0x7C00, 0x7E00, 0x7F00, + 0x7F80, 0x7C00, 0x6C00, 0x4600, + 0x0600, 0x0300, 0x0300, 0x0000 +}; + +static Bit16u userdefScreenMask[CURSORY]; +static Bit16u userdefCursorMask[CURSORY]; + static struct { Bit16u buttons; Bit16u times_pressed[MOUSE_BUTTONS]; @@ -57,6 +84,22 @@ static struct { Bit32u events; Bit16u sub_seg,sub_ofs; Bit16u sub_mask; + + bool background; + Bit16s backposx, backposy; + Bit8u backData[CURSORX*CURSORY]; + Bit16u* screenMask; + Bit16u* cursorMask; + Bit16s clipx,clipy; + Bit16s hotx,hoty; + Bit16u textAndMask, textXorMask; + Bit16u resy; + + float mickeysPerPixel_x; + float mickeysPerPixel_y; + float pixelPerMickey_x; + float pixelPerMickey_y; + } mouse; #define X_MICKEY 8 @@ -79,17 +122,211 @@ INLINE void Mouse_AddEvent(Bit16u type) { PIC_ActivateIRQ(12); } -static void DrawCursor() { +// *************************************************************************** +// Mouse cursor - text mode +// *************************************************************************** + +void RestoreCursorBackgroundText() +{ if (mouse.shown<0) return; + + if (mouse.background) { + // Save old Cursorposition + Bit8u oldx = CURSOR_POS_ROW(0); + Bit8u oldy = CURSOR_POS_COL(0); + // Restore background + INT10_SetCursorPos ((Bit8u)mouse.backposy,(Bit8u)mouse.backposx,0); + INT10_WriteChar (mouse.backData[0],mouse.backData[1],0,1,true); + // Restore old cursor position + INT10_SetCursorPos (oldx,oldy,0); + mouse.background = false; + } +}; + +void DrawCursorText() +{ + // Restore Background + RestoreCursorBackgroundText(); + + // Save old Cursorposition + Bit8u oldx = CURSOR_POS_ROW(0); + Bit8u oldy = CURSOR_POS_COL(0); + + // Save Background + Bit16u result; + INT10_SetCursorPos (POS_Y>>3,POS_X>>3,0); + INT10_ReadCharAttr (&result,0); + mouse.backData[0] = result & 0xFF; + mouse.backData[1] = result>>8; + mouse.backposx = POS_X>>3; + mouse.backposy = POS_Y>>3; + mouse.background = true; + + // Write Cursor + result = (result & mouse.textAndMask) ^ mouse.textXorMask; + INT10_WriteChar (result&0xFF,result>>8,0,1,true); + + // Restore old cursor position + INT10_SetCursorPos (oldx,oldy,0); +}; + +// *************************************************************************** +// Mouse cursor - graphic mode +// *************************************************************************** + +static Bit8u gfxReg[9]; + +void SaveVgaRegisters() +{ + for (int i=0; i<9; i++) { + IO_Write (0x3CE,i); + gfxReg[i] = IO_Read(0x3CF); + }; + // Set default + INT10_SetGfxControllerToDefault(); +}; + +void RestoreVgaRegisters() +{ + for (int i=0; i<9; i++) { + IO_Write(0x3CE,i); + IO_Write(0x3CF,gfxReg[i]); + }; +}; + +void ClipCursorArea(Bit16s& x1, Bit16s& x2, Bit16s& y1, Bit16s& y2, Bit16u& addx1, Bit16u& addx2, Bit16u& addy) +{ + addx1 = addx2 = addy = 0; + // Clip up + if (y1<0) { + addy += (-y1); + y1 = 0; + } + // Clip down + if (y2>mouse.clipy) { + y2 = mouse.clipy; + }; + // Clip left + if (x1<0) { + addx1 += (-x1); + x1 = 0; + }; + // Clip right + if (x2>mouse.clipx) { + addx2 = x2 - mouse.clipx; + x2 = mouse.clipx; + }; +}; + +void RestoreCursorBackground() +{ + if (mouse.shown<0) return; + + SaveVgaRegisters(); + if (mouse.background) { + // Restore background + Bit16s x,y; + Bit16u addx1,addx2,addy; + Bit16u dataPos = 0; + Bit16s x1 = mouse.backposx; + Bit16s y1 = mouse.backposy; + Bit16s x2 = x1 + CURSORX - 1; + Bit16s y2 = y1 + CURSORY - 1; + + ClipCursorArea(x1, x2, y1, y2, addx1, addx2, addy); + + dataPos = addy * CURSORX; + for (y=y1; y<=y2; y++) { + dataPos += addx1; + for (x=x1; x<=x2; x++) { + INT10_PutPixel(x,y,0,mouse.backData[dataPos++]); + }; + dataPos += addx2; + }; + mouse.background = false; + }; + RestoreVgaRegisters(); +}; + +void DrawCursor() { + + if (mouse.shown<0) return; + + // Get Clipping ranges + VGAMODES * curmode=GetCurrentMode(); + if (!curmode) return; + + // In Textmode ? + if (curmode->type==TEXT) { + DrawCursorText(); + return; + } + + mouse.clipx = curmode->swidth-1; + mouse.clipy = curmode->sheight-1; + + RestoreCursorBackground(); + + SaveVgaRegisters(); + + // Save Background + Bit16s x,y; + Bit16u addx1,addx2,addy; + Bit16u dataPos = 0; + Bit16s x1 = POS_X - mouse.hotx; + Bit16s y1 = POS_Y - mouse.hoty; + Bit16s x2 = x1 + CURSORX - 1; + Bit16s y2 = y1 + CURSORY - 1; + + ClipCursorArea(x1,x2,y1,y2, addx1, addx2, addy); + + dataPos = addy * CURSORX; + for (y=y1; y<=y2; y++) { + dataPos += addx1; + for (x=x1; x<=x2; x++) { + INT10_GetPixel(x,y,0,&mouse.backData[dataPos++]); + }; + dataPos += addx2; + }; + mouse.background= true; + mouse.backposx = POS_X - mouse.hotx; + mouse.backposy = POS_Y - mouse.hoty; + + // Draw Mousecursor + dataPos = addy * CURSORX; + for (y=y1; y<=y2; y++) { + Bit16u scMask = mouse.screenMask[addy+y-y1]; + Bit16u cuMask = mouse.cursorMask[addy+y-y1]; + if (addx1>0) { scMask<<=addx1; cuMask<<=addx1; dataPos += addx1; }; + for (x=x1; x<=x2; x++) { + Bit8u pixel = 0; + // ScreenMask + if (scMask & HIGHESTBIT) pixel = mouse.backData[dataPos]; + scMask<<=1; + // CursorMask + if (cuMask & HIGHESTBIT) pixel = pixel ^ 0x0F; + cuMask<<=1; + // Set Pixel + INT10_PutPixel(x,y,0,pixel); + dataPos++; + }; + dataPos += addx2; + }; + RestoreVgaRegisters(); } void Mouse_CursorMoved(float x,float y) { - mouse.mickey_x+=x; - mouse.mickey_y+=y; - mouse.x+=x; + + float dx = x * mouse.pixelPerMickey_x; + float dy = y * mouse.pixelPerMickey_y; + + mouse.mickey_x += dx; + mouse.mickey_y += dy; + + mouse.x += dx; if (mouse.x>mouse.max_x) mouse.x=mouse.max_x;; if (mouse.xmouse.max_y) mouse.y=mouse.max_y;; if (mouse.y0) mouse.shown=0; + DrawCursor(); break; case 0x02: /* Hide Mouse */ - mouse.shown--; + { + VGAMODES * curmode=GetCurrentMode(); + if (curmode && curmode->type==GRAPH) RestoreCursorBackground(); + else RestoreCursorBackgroundText(); + mouse.shown--; + } break; case 0x03: /* Return position and Button Status */ reg_bx=mouse.buttons; @@ -184,6 +456,7 @@ static Bitu INT33_Handler(void) { case 0x04: /* Position Mouse */ mouse.x=(float)reg_cx; mouse.y=(float)reg_dx; + DrawCursor(); break; case 0x05: /* Return Button Press Data */ { @@ -212,18 +485,38 @@ static Bitu INT33_Handler(void) { break; } case 0x07: /* Define horizontal cursor range */ - mouse.min_x=reg_cx; - mouse.max_x=reg_dx; + if (reg_cxRun(); delete new_program; return CBRET_NONE; -}; +} /* Main functions used in all program */ diff --git a/src/misc/setup.cpp b/src/misc/setup.cpp index 8846a6c..76f6426 100644 --- a/src/misc/setup.cpp +++ b/src/misc/setup.cpp @@ -156,7 +156,7 @@ void Section_line::PrintData(FILE* outfile) { void Config::PrintConfig(const char* configfilename){ char temp[50]; - FILE* outfile=fopen(configfilename,"w+b"); + FILE* outfile=fopen(configfilename,"w+t"); if(outfile==NULL) return; for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ /* Print out the Section header */ @@ -325,6 +325,18 @@ bool CommandLine::FindStringBegin(char * begin,std::string & value, bool remove) return false; } +bool CommandLine::FindStringRemain(char * name,std::string & value) { + cmd_it it;value=""; + if (!FindEntry(name,it)) return false; + it++; + for (;it!=cmds.end();it++) { + value+=" "; + value+=(*it); + } + return true; +} + + int CommandLine::GetCount(void) { return cmds.size(); } @@ -369,3 +381,4 @@ CommandLine::CommandLine(char * name,char * cmdline) { } if (inword || inquote) cmds.push_back(str); } + diff --git a/src/platform/visualc/config.h b/src/platform/visualc/config.h index 043d02b..83fa3b1 100644 --- a/src/platform/visualc/config.h +++ b/src/platform/visualc/config.h @@ -1,6 +1,6 @@ #define INLINE __forceinline -#define VERSION "0.56" +#define VERSION "0.57" #define GCC_ATTRIBUTE(x) /* attribute not supported */ diff --git a/src/platform/visualc/dirent.c b/src/platform/visualc/dirent.c index 1f8df13..f6be792 100644 --- a/src/platform/visualc/dirent.c +++ b/src/platform/visualc/dirent.c @@ -7,6 +7,7 @@ */ #include "dirent.h" +#include "io.h" #ifdef WIN32 @@ -22,17 +23,14 @@ DIR * opendir(const char *dirname) { /* Stash the directory name */ strcpy(dir.pathName,dirname); + strcat(dir.pathName,"*.*"); /* set the handle to invalid and set the firstTime flag */ dir.handle = INVALID_HANDLE_VALUE; dir.firstTime = TRUE; - if (strcmp(dirname, ".") == 0) { - return &dir; - } - /* Change the current directory to the one requested */ - return (SetCurrentDirectory(dir.pathName) != 0) ? &dir : NULL; + return (access(dirname,0) ? NULL : &dir); } /** Close the current directory - return 0 if success */ @@ -60,7 +58,7 @@ struct dirent * readdir(DIR *dirp) { if (TRUE == dirp->firstTime) { /** Get the first entry in the directory */ - dirp->handle = FindFirstFile("*.*", &dirp->findFileData); + dirp->handle = FindFirstFile(dirp->pathName, &dirp->findFileData); dirp->firstTime = FALSE; if (INVALID_HANDLE_VALUE == dirp->handle) { diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index 1f7bed1..323a79b 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -79,7 +79,7 @@ void DOS_Shell::ParseLine(char * line) { char * fname1=0; /* Check for a leading @ */ - if (line[0]=='@') line[0]=' '; + if (line[0]=='@') line[0]=' '; line=trim(line); Bit32u num=0; /* Number of commands in this line */ @@ -96,9 +96,10 @@ void DOS_Shell::ParseLine(char * line) { void DOS_Shell::Run(void) { char input_line[CMD_MAXLINE]; std::string line; - if (cmd->FindString("/C",line,true)) { + + if (cmd->FindStringRemain("/C",line)) { strcpy(input_line,line.c_str()); - line.erase(); + ParseLine(input_line); return; } /* Start a normal shell and check for a first command init */ @@ -179,13 +180,15 @@ static char * init_line="/INIT AUTOEXEC.BAT"; void SHELL_Init() { /* Add messages */ + MSG_Add("SHELL_ILLEGAL_PATH","Illegal Path\n"); 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_CMD_RMDIR_ERROR","Unable to remove: %s\n"); + MSG_Add("SHELL_CMD_DEL_ERROR","Unable to delete: %s\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"); @@ -197,12 +200,22 @@ void SHELL_Init() { 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_STARTUP","DOSBox Shell v" VERSION "\n" + "DOSBox doesn't not run protected mode games!\n" + "For supported shell commands type: HELP\n" +#if! defined (WIN32) + "DOSBox only works with upcase filenames as dos is case-insensitive.\n" + "You can use the UPCASE command for this, but please be careful.\n" +#endif + "For more information read the README file in DOSBox directory.\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"); @@ -216,9 +229,15 @@ void SHELL_Init() { 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"); - + MSG_Add("SHELL_CMD_NO_WILD","This is a simple version of the command, no wildcards allowed!\n"); + MSG_Add("SHELL_CMD_RENAME_HELP","Renames files.\n"); + MSG_Add("SHELL_CMD_DELETE_HELP","Removes files.\n"); /* Regular startup */ call_shellstop=CALLBACK_Allocate(); + /* Setup the startup CS:IP to kill the last running machine when exitted */ + RealPt newcsip=CALLBACK_RealPointer(call_shellstop); + SegSet16(cs,RealSeg(newcsip)); + reg_ip=RealOff(newcsip); CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET); PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart); diff --git a/src/shell/shell_batch.cpp b/src/shell/shell_batch.cpp index fdec91b..304f598 100644 --- a/src/shell/shell_batch.cpp +++ b/src/shell/shell_batch.cpp @@ -20,7 +20,6 @@ #include #include "shell_inc.h" -#include "cpu.h" BatchFile::BatchFile(DOS_Shell * host,char * name, char * cmd_line) { @@ -50,7 +49,7 @@ emptyline: n=1; DOS_ReadFile(file_handle,&c,&n); if (n>0) { - if (c>31) + if (c>31 || c==0x1b) *cmd_write++=c; } } while (c!='\n' && n); diff --git a/src/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index fee0e18..5b0004b 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -28,6 +28,8 @@ static SHELL_Cmd cmd_list[]={ "CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP", // "COPY", 0, &DOS_Shell::CMD_COPY, "Copy Files.", "DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP", + "DEL", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP", + "DELETE", 0, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_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", @@ -38,7 +40,8 @@ static SHELL_Cmd cmd_list[]={ "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", - + "RENAME", 0, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP", + "REN", 1, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP", /* "CHDIR", 0, &DOS_Shell::CMD_CHDIR, "Change Directory", "MKDIR", 0, &DOS_Shell::CMD_MKDIR, "Make Directory", @@ -56,6 +59,7 @@ void DOS_Shell::DoCommand(char * line) { if (*line==32) break; if (*line=='/') break; if ((*line=='.') && (*(line+1)=='.')) break; +// if ((*line=='.') && (*(line+1)==0)) break; *cmd_write++=*line++; } *cmd_write=0; @@ -80,6 +84,33 @@ void DOS_Shell::CMD_CLS(char * args) { CALLBACK_RunRealInt(0x10); }; +void DOS_Shell::CMD_DELETE(char * args) { + char * rem=ScanCMDRemain(args); + if (rem) { + WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem); + return; + } + char full[DOS_PATHLENGTH]; + if (!DOS_Canonicalize(args,full)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH"));return; } +//TODO Maybe support confirmation for *.* like dos does. + bool res=DOS_FindFirst(args,0xff); + if (!res) { + WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),args);return; + } + //end can't be 0, but if it is we'll get a nice crash, who cares :) + char * end=strrchr(full,'\\')+1;*end=0; + char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u time,date;Bit8u attr; + DOS_DTA dta(dos.dta); + while (res) { + dta.GetResult(name,size,date,time,attr); + if (!(attr & (DOS_ATTR_DIRECTORY|DOS_ATTR_READ_ONLY))) { + strcpy(end,name); + if (!DOS_UnlinkFile(full)) WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),full); + } + res=DOS_FindNext(); + } +} + void DOS_Shell::CMD_HELP(char * args){ /* Print the help */ WriteOut(MSG_Get("SHELL_CMD_HELP")); @@ -91,6 +122,17 @@ void DOS_Shell::CMD_HELP(char * args){ } +void DOS_Shell::CMD_RENAME(char * args){ + if(!*args) {SyntaxError();return;} + if((strchr(args,'*')!=NULL) || (strchr(args,'?')!=NULL) ) { WriteOut(MSG_Get("SHELL_CMD_NO_WILD"));return;} + char * arg2 =StripWord(args); + DOS_Rename(args,arg2); +} + + + + + void DOS_Shell::CMD_ECHO(char * args) { if (!*args) { if (echo) { WriteOut(MSG_Get("SHELL_CMD_ECHO_ON"));} @@ -187,7 +229,7 @@ void DOS_Shell::CMD_DIR(char * args) { /* Make a full path in the args */ if (!DOS_Canonicalize(args,path)) { - WriteOut(MSG_Get("SHELL_CMD_DIR_PATH_ERROR")); + WriteOut(MSG_Get("SHELL_CMD_ILLEGAL_PATH")); return; } *(strrchr(path,'\\')+1)=0; @@ -250,7 +292,7 @@ void DOS_Shell::CMD_DIR(char * args) { //TODO Free Space Bitu free_space=1024*1024*100; if (Drives[drive]) { - Bit16u bytes_sector;Bit16u sectors_cluster;Bit16u total_clusters;Bit16u free_clusters; + Bit16u bytes_sector;Bit8u 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; } @@ -385,3 +427,4 @@ nextfile: void DOS_Shell::CMD_REM(char * args) { } + diff --git a/src/shell/shell_inc.h b/src/shell/shell_inc.h index 2396b01..e21f323 100644 --- a/src/shell/shell_inc.h +++ b/src/shell/shell_inc.h @@ -66,6 +66,7 @@ public: void CMD_CLS(char * args); void CMD_COPY(char * args); void CMD_DIR(char * args); + void CMD_DELETE(char * args); void CMD_ECHO(char * args); void CMD_EXIT(char * args); void CMD_MKDIR(char * args); @@ -76,6 +77,7 @@ public: void CMD_GOTO(char * args); void CMD_TYPE(char * args); void CMD_REM(char * args); + void CMD_RENAME(char * args); void SyntaxError(void); /* The shell's variables */ diff --git a/src/shell/shell_misc.cpp b/src/shell/shell_misc.cpp index c300d8b..63a4516 100644 --- a/src/shell/shell_misc.cpp +++ b/src/shell/shell_misc.cpp @@ -47,6 +47,7 @@ void DOS_Shell::InputCommand(char * line) { Bitu str_len=0;Bitu str_index=0; while (size) { + dos.echo=false; DOS_ReadFile(input_handle,&c,&n); if (!n) { size=0; //Kill the while loop @@ -164,10 +165,18 @@ void DOS_Shell::Execute(char * name,char * args) { cmd.buffer[strlen(line)]=0xd; /* Copy command line in stack block too */ MEM_BlockWrite(SegPhys(ss)+reg_sp+0x100,&cmd,128); + /* Parse FCB (first two parameters) and put them into the current DOS_PSP */ + Bit8u add; + FCB_Parsename(dos.psp,0x5C,0x00,cmd.buffer,&add); + FCB_Parsename(dos.psp,0x6C,0x00,&cmd.buffer[add],&add); + block.exec.fcb1=RealMake(dos.psp,0x5C); + block.exec.fcb2=RealMake(dos.psp,0x6C); /* 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 */ + Bit32u oldeip=reg_eip; + Bit16u oldcs=SegValue(cs); RealPt newcsip=CALLBACK_RealPointer(call_shellstop); SegSet16(cs,RealSeg(newcsip)); reg_ip=RealOff(newcsip); @@ -181,7 +190,10 @@ void DOS_Shell::Execute(char * name,char * args) { reg_bx=reg_sp; flags.intf=false; CALLBACK_RunRealInt(0x21); + /* Restore CS:IP and the stack */ reg_sp+=0x200; + reg_eip=oldeip; + SegSet16(cs,oldcs); } } diff --git a/visualc/dosbox.dsp b/visualc/dosbox.dsp index e4d31a7..9fd8aed 100644 --- a/visualc/dosbox.dsp +++ b/visualc/dosbox.dsp @@ -271,6 +271,10 @@ SOURCE=..\include\render.h # End Source File # Begin Source File +SOURCE=..\src\gui\render_support.h +# End Source File +# Begin Source File + SOURCE=..\src\gui\sdlmain.cpp # End Source File # Begin Source File @@ -335,6 +339,14 @@ SOURCE=..\src\hardware\adlib.cpp # End Source File # Begin Source File +SOURCE=..\src\hardware\cmos.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\hardware\disney.cpp +# End Source File +# Begin Source File + SOURCE=..\src\hardware\dma.cpp # End Source File # Begin Source File @@ -343,6 +355,10 @@ SOURCE=..\src\hardware\gameblaster.cpp # End Source File # Begin Source File +SOURCE=..\src\hardware\gus.cpp +# End Source File +# Begin Source File + SOURCE=..\src\hardware\hardware.cpp # End Source File # Begin Source File