DOSBox 0.57

This commit is contained in:
Carl.Kenner 2009-05-02 21:27:47 +00:00
parent 44c0450545
commit 0e247f1518
98 changed files with 4761 additions and 1847 deletions

View File

@ -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 0.56
- added support for a configclass/configfile - added support for a configclass/configfile
- added support for writing out the configclass into a configfile - added support for writing out the configclass into a configfile

96
NEWS
View File

@ -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 a configclass/configfile
- added support for writing out the configclass into a configfile - added support for writing out the configclass into a configfile
- removed the language file and made it internal - removed the language file and made it internal
@ -18,31 +59,34 @@
- Added more cpu instructions and changed the string operations. - Added more cpu instructions and changed the string operations.
- Added classes for most of the internal dos structures. - Added classes for most of the internal dos structures.
- Rewrote most of the fcb calls to use normal dos calls. - Rewrote most of the fcb calls to use normal dos calls.
0.55
- fixed the errors/warnings in prefix_66.h and prefix_66_of.h (decimal too large becomming unsigned).
0.55: - fixed compilation error on FreeBSD when #disable_joystick was defined
- changed basedir handling. (linux/winXP) - int10_writechar has been updated to move the cursor position.
- added some FCB-calls - changed the basedir routines to use the current working dir instead of argv[0]. This will fix and brake things :)
- improved support for user mousehandlers - illegal command, now displays the command
- fixed EGA graphics - wildcmp updated to be case insensitive
- fixed VGA graphics - added fcb:open,close,findfirst, findnext.
- fixed the displaying of text in some graphics modes - fixed rename in drive_local
- fixed write with size 0 - added new features to the debugger: breakpoint support / data view / command line
- changed memory management. - partial support of list of lists (dos info block)
- added full emm 3.2 support. - full emm 3.2 support
- fixed and cleaned up the cpu flags. - partial emm 4.0 support
changed interrupt handler. - fixes to graphics core fonts (text in sierra games is now correct)
- speeded up the graphics. - improved support for user mousehandlers
- speeded up the cpu-core - fixed EGA graphics
- added new features to the debugger: breakpoint support / data view / command line - fixed VGA graphics
- partial support of list of lists (dos info block) - fixed write with size 0
- partial emm 4.0 support - changed memory management.
- fixes to graphics core fonts (text in sierra games is now correct) - fixed and cleaned up the cpu flags.
- changed dma - changed interrupt handler.
- improved dma streams from emm memory - speeded up the graphics.
- added some cga videomodes - speeded up the cpu-core
- added more funtions to the keyboard handler - changed dma
- improved dma streams from emm memory
- added some cga videomodes
- added more funtions to the keyboard handler
0.50: 0.50:
-added F3 to repeat the last typed command. -added F3 to repeat the last typed command.

3
README
View File

@ -1,4 +1,4 @@
DOSBox v0.56 DOSBox v0.57
Usage: 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. Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator.
The Bochs and DOSemu projects which I used for information. The Bochs and DOSemu projects which I used for information.
Freedos for ideas in making my shell. Freedos for ideas in making my shell.
The Beta Testers.
Contact: Contact:
======== ========

1
THANKS
View File

@ -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. The Bochs and DOSemu projects which I used for information.
Freedos for ideas in making my shell. Freedos for ideas in making my shell.
All the people who submitted a bug. All the people who submitted a bug.
The Beta Testers.

20
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # 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 # Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc. # Free Software Foundation, Inc.
@ -272,8 +272,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='dosbox' PACKAGE_NAME='dosbox'
PACKAGE_TARNAME='dosbox' PACKAGE_TARNAME='dosbox'
PACKAGE_VERSION='0.56' PACKAGE_VERSION='0.57'
PACKAGE_STRING='dosbox 0.56' PACKAGE_STRING='dosbox 0.57'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
ac_unique_file="README" 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. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF 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]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -853,7 +853,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of dosbox 0.56:";; short | recursive ) echo "Configuration of dosbox 0.57:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -946,7 +946,7 @@ fi
test -n "$ac_init_help" && exit 0 test -n "$ac_init_help" && exit 0
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
dosbox configure 0.56 dosbox configure 0.57
generated by GNU Autoconf 2.53a generated by GNU Autoconf 2.53a
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 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 This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. 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 generated by GNU Autoconf 2.53a. Invocation command line was
$ $0 $@ $ $0 $@
@ -1579,7 +1579,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE=dosbox PACKAGE=dosbox
VERSION=0.56 VERSION=0.57
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -4706,7 +4706,7 @@ _ASBOX
} >&5 } >&5
cat >&5 <<_CSEOF 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 generated by GNU Autoconf 2.53a. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -4768,7 +4768,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\ ac_cs_version="\\
dosbox config.status 0.56 dosbox config.status 0.57
configured by $0, generated by GNU Autoconf 2.53a, configured by $0, generated by GNU Autoconf 2.53a,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"

View File

@ -1,5 +1,5 @@
dnl Init. dnl Init.
AC_INIT(dosbox,0.56) AC_INIT(dosbox,0.57)
AC_CONFIG_SRCDIR(README) AC_CONFIG_SRCDIR(README)
dnl Detect the canonical host and target build environment dnl Detect the canonical host and target build environment

View File

@ -24,7 +24,7 @@
typedef Bitu (*CallBack_Handler)(void); typedef Bitu (*CallBack_Handler)(void);
extern CallBack_Handler CallBack_Handlers[]; extern CallBack_Handler CallBack_Handlers[];
enum { CB_RETF,CB_IRET }; enum { CB_RETF,CB_IRET,CB_IRET_STI };
#define CB_MAX 1024 #define CB_MAX 1024
#define CB_SEG 0xC800 #define CB_SEG 0xC800

View File

@ -19,20 +19,23 @@
#ifndef __CPU_H #ifndef __CPU_H
#define __CPU_H #define __CPU_H
#include <dosbox.h> #include "dosbox.h"
#include <regs.h> #include "regs.h"
#include <mem.h> #include "mem.h"
/* Some common Defines */ /* Some common Defines */
/* A CPU Handler */ /* A CPU Handler */
typedef Bitu (CPU_Decoder)(Bits count); typedef Bitu (CPU_Decoder)(void);
extern CPU_Decoder * cpudecoder; 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 //CPU Stuff
void SetCPU16bit(); void SetCPU16bit();
//Types of Flag changing instructions //Types of Flag changing instructions
enum { enum {
t_ADDb=0,t_ADDw,t_ADDd, t_ADDb=0,t_ADDw,t_ADDd,
@ -63,9 +66,6 @@ enum {
t_NOTDONE, t_NOTDONE,
}; };
enum { rep_NONE,rep_Z,rep_NZ };
void Interrupt(Bit8u num); void Interrupt(Bit8u num);
//Flag Handling //Flag Handling

View File

@ -27,5 +27,6 @@ bool DEBUG_ExitLoop(void);
extern Bitu cycle_count; extern Bitu cycle_count;
#ifdef C_HEAVY_DEBUG #ifdef C_HEAVY_DEBUG
bool DEBUG_HeavyIsBreakpoint(); bool DEBUG_HeavyIsBreakpoint(void);
void DEBUG_HeavyWriteLogInstruction(void);
#endif #endif

View File

@ -63,6 +63,7 @@ struct DOS_Block {
Bit8u current_drive; Bit8u current_drive;
bool verify; bool verify;
bool breakcheck; bool breakcheck;
bool echo; // if set to true dev_con::read will echo input
struct { struct {
RealPt indosflag; RealPt indosflag;
RealPt mediaid; RealPt mediaid;
@ -119,7 +120,7 @@ bool DOS_ChangeDir(char * dir);
bool DOS_MakeDir(char * dir); bool DOS_MakeDir(char * dir);
bool DOS_RemoveDir(char * dir); bool DOS_RemoveDir(char * dir);
bool DOS_Rename(char * oldname,char * newname); 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); bool DOS_GetFileAttr(char * name,Bit16u * attr);
/* IOCTL Stuff */ /* IOCTL Stuff */
@ -140,22 +141,25 @@ bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks);
bool DOS_FreeMemory(Bit16u segment); bool DOS_FreeMemory(Bit16u segment);
void DOS_FreeProcessMemory(Bit16u pspseg); void DOS_FreeProcessMemory(Bit16u pspseg);
Bit16u DOS_GetMemory(Bit16u pages); Bit16u DOS_GetMemory(Bit16u pages);
void DOS_SetMemAllocStrategy(Bit16u strat);
Bit16u DOS_GetMemAllocStrategy(void);
/* FCB stuff */ /* 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_FCBClose(Bit16u seg,Bit16u offset);
bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset); bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset);
bool DOS_FCBFindNext(Bit16u seg,Bit16u offset); bool DOS_FCBFindNext(Bit16u seg,Bit16u offset);
Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset, Bit16u numBlocks); 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); 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_FCBGetFileSize(Bit16u seg,Bit16u offset,Bit16u numRec);
bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset); bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset);
bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset); bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset);
void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset); void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset);
Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change); 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 */ /* Extra DOS Interrupts */
void DOS_SetupMisc(void); void DOS_SetupMisc(void);
@ -418,8 +422,9 @@ private:
extern DOS_InfoBlock dos_infoblock;; extern DOS_InfoBlock dos_infoblock;;
INLINE Bit8u RealHandle(Bit16u handle) { INLINE Bit8u RealHandle(Bit16u handle) {
DOS_PSP psp(dos.psp); DOS_PSP psp(dos.psp);
return psp.GetFileHandle((Bit8u)handle); return psp.GetFileHandle(handle);
} }
#endif #endif

View File

@ -84,7 +84,7 @@ public:
virtual bool FindNext(DOS_DTA & dta)=0; virtual bool FindNext(DOS_DTA & dta)=0;
virtual bool GetFileAttr(char * name,Bit16u * attr)=0; virtual bool GetFileAttr(char * name,Bit16u * attr)=0;
virtual bool Rename(char * oldname,char * newname)=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 FileExists(const char* name)=0;
virtual bool FileStat(const char* name, FileStat_Block * const stat_block)=0; virtual bool FileStat(const char* name, FileStat_Block * const stat_block)=0;
virtual Bit8u GetMediaByte(void)=0; virtual Bit8u GetMediaByte(void)=0;

View File

@ -26,4 +26,5 @@ void Mouse_ButtonPressed(Bit8u button);
void Mouse_ButtonReleased(Bit8u button); void Mouse_ButtonReleased(Bit8u button);
void Mouse_AutoLock(bool enable); void Mouse_AutoLock(bool enable);
void Mouse_SetResolution(Bit16u width, Bit16u height);

View File

@ -19,7 +19,12 @@
#ifndef __PIC_H #ifndef __PIC_H
#define __PIC_H #define __PIC_H
#include "cpu.h"
typedef void (PIC_EOIHandler) (void); typedef void (PIC_EOIHandler) (void);
typedef void (* PIC_EventHandler)(void);
#define PIC_MAXIRQ 15 #define PIC_MAXIRQ 15
#define PIC_NOIRQ 0xFF #define PIC_NOIRQ 0xFF
@ -27,7 +32,20 @@ typedef void (PIC_EOIHandler) (void);
extern Bitu PIC_IRQCheck; extern Bitu PIC_IRQCheck;
extern Bitu PIC_IRQActive; 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); 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_RegisterIRQ(Bit32u irq,PIC_EOIHandler handler,char * name);
void PIC_FreeIRQ(Bit32u irq); 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 #endif

View File

@ -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); void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue);

View File

@ -30,13 +30,14 @@ public:
CommandLine(int argc,char * argv[]); CommandLine(int argc,char * argv[]);
CommandLine(char * name,char * cmdline); CommandLine(char * name,char * cmdline);
const char * GetFileName(){ return file_name.c_str();} const char * GetFileName(){ return file_name.c_str();}
bool FindExist(char * name,bool remove=false); bool FindExist(char * name,bool remove=false);
bool FindHex(char * name,int & value,bool remove=false); bool FindHex(char * name,int & value,bool remove=false);
bool FindInt(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 FindString(char * name,std::string & value,bool remove=false);
bool FindCommand(int which,std::string & value); bool FindCommand(int which,std::string & value);
bool FindStringBegin(char * begin,std::string & value, bool remove=false); bool FindStringBegin(char * begin,std::string & value, bool remove=false);
bool FindStringRemain(char * name,std::string & value);
int GetCount(void); int GetCount(void);
private: private:
typedef std::list<std::string>::iterator cmd_it; typedef std::list<std::string>::iterator cmd_it;

View File

@ -45,15 +45,13 @@ bool ScanCMDHex(char * cmd,char * check,Bits * result);
char * StripWord(char * cmd); char * StripWord(char * cmd);
INLINE char * upcase(char * str) { INLINE char * upcase(char * str) {
char * oldstr=str; for (char* idx = str; *idx ; idx++) *idx = toupper(*idx);
while (*str) *str++=toupper(*str); return str;
return oldstr;
} }
INLINE char * lowcase(char * str) { INLINE char * lowcase(char * str) {
char * oldstr=str; for(char* idx = str; *idx ; idx++) *idx = tolower(*idx);
while (*str) *str++=tolower(*str); return str;
return oldstr;
} }

View File

@ -21,15 +21,12 @@
/* underlying clock rate in HZ */ /* underlying clock rate in HZ */
#include <SDL.h> #include <SDL.h>
extern Bit32u LastTicks;
#define PIT_TICK_RATE 1193182 #define PIT_TICK_RATE 1193182
#define GetTicks() SDL_GetTicks() #define GetTicks() SDL_GetTicks()
typedef void (*TIMER_TickHandler)(Bitu ticks); typedef void (*TIMER_TickHandler)(Bitu ticks);
typedef void (*TIMER_MicroHandler)(void); typedef void (*TIMER_MicroHandler)(void);
typedef void (*TIMER_DelayHandler)(void);
typedef void TIMER_Block; typedef void TIMER_Block;
@ -38,18 +35,12 @@ typedef void TIMER_Block;
TIMER_Block * TIMER_RegisterTickHandler(TIMER_TickHandler handler); TIMER_Block * TIMER_RegisterTickHandler(TIMER_TickHandler handler);
/* Register a function to be called every x microseconds */ /* Register a function to be called every x microseconds */
TIMER_Block * TIMER_RegisterMicroHandler(TIMER_MicroHandler handler,Bitu micro); 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 */ /* Set the microseconds value to a new value */
void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro); void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro);
/* This will add 1 milliscond to all timers */
/* This function should be called very often to support very high res timers void TIMER_AddTick(void);
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);
#endif #endif

View File

@ -20,9 +20,7 @@
#define __VIDEO_H #define __VIDEO_H
typedef void (GFX_DrawHandler)(Bit8u * vidstart); typedef void (* GFX_ModeCallBack)(Bitu width,Bitu height,Bitu bpp,Bitu pitch,Bitu flags);
/* Used to reply to the renderer what size to set */
typedef void (GFX_ResizeHandler)(Bitu * width,Bitu * height);
struct GFX_PalEntry { struct GFX_PalEntry {
Bit8u r; Bit8u r;
@ -31,20 +29,25 @@ struct GFX_PalEntry {
Bit8u unused; Bit8u unused;
}; };
struct GFX_Info { #define GFX_FIXED_BPP 0x01
Bitu width,height,bpp,pitch; #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_Events(void);
void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries); 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_Start(void);
void GFX_Stop(void); void GFX_Stop(void);
void GFX_SwitchFullScreen(void); void GFX_SwitchFullScreen(void);
void * GFX_StartUpdate(void);
void GFX_EndUpdate(void);
#endif #endif

View File

@ -17,18 +17,15 @@
*/ */
#ifndef _SETTINGS_H_ #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_DEBUG 0
#define C_HEAVY_DEBUG 0 #define C_HEAVY_DEBUG 0
/* Enable the logging of extra information for debugging to the console */ /* Enable the logging of extra information for debugging to the console */
#define C_LOGGING 0 #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 */ /* Enable some big compile-time increasing inlines, great for speed though */
#define C_EXTRAINLINE 0 #define C_EXTRAINLINE 0
@ -38,12 +35,6 @@
/* Maximum memory range in megabytes */ /* Maximum memory range in megabytes */
#define C_MEM_MAX_SIZE 12 #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 */ /* Enable debug messages for several modules, requires C_LOGGING */
#define DEBUG_SBLASTER 0 /* SoundBlaster Debugging*/ #define DEBUG_SBLASTER 0 /* SoundBlaster Debugging*/
#define DEBUG_DMA 0 /* DMA Debugging */ #define DEBUG_DMA 0 /* DMA Debugging */

View File

@ -23,7 +23,7 @@
#include "callback.h" #include "callback.h"
#include "mem.h" #include "mem.h"
#include "cpu.h" #include "cpu.h"
#include "pic.h"
/* CallBack are located at 0xC800:0 /* CallBack are located at 0xC800:0
And they are 16 bytes each and you can define them to behave in certain ways like a 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) { void CALLBACK_Idle(void) {
/* this makes the cpu execute instructions to handle irq's and then come back */ /* 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); Bit16u oldcs=SegValue(cs);
Bit32u oldeip=reg_eip; Bit32u oldeip=reg_eip;
SegSet16(cs,CB_SEG); SegSet16(cs,CB_SEG);
@ -59,10 +61,13 @@ void CALLBACK_Idle(void) {
DOSBOX_RunMachine(); DOSBOX_RunMachine();
reg_eip=oldeip; reg_eip=oldeip;
SegSet16(cs,oldcs); SegSet16(cs,oldcs);
flags.intf=oldintf;
if (CPU_CycleLeft<300) CPU_CycleLeft=1;
else CPU_CycleLeft-=300;
} }
static Bitu default_handler(void) { static Bitu default_handler(void) {
LOG_WARN("Illegal Unhandled Interrupt Called %d",lastint); LOG_WARN("Illegal Unhandled Interrupt Called %X",lastint);
return CBRET_NONE; return CBRET_NONE;
}; };
@ -116,17 +121,25 @@ bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type) {
if (callback>=CB_MAX) return false; if (callback>=CB_MAX) return false;
switch (type) { switch (type) {
case CB_RETF: 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_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_writew((Bit16u)CB_SEG,(callback<<4)+2,callback); //The immediate word
real_writeb((Bit16u)CB_SEG,(callback<<4)+4,(Bit8u)0xCB); //A RETF Instruction real_writeb((Bit16u)CB_SEG,(callback<<4)+4,(Bit8u)0xCB); //A RETF Instruction
break; break;
case CB_IRET: 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_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_writew((Bit16u)CB_SEG,(callback<<4)+2,callback); //The immediate word
real_writeb((Bit16u)CB_SEG,(callback<<4)+4,(Bit8u)0xCF); //An IRET Instruction real_writeb((Bit16u)CB_SEG,(callback<<4)+4,(Bit8u)0xCF); //An IRET Instruction
break; 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: default:
E_Exit("CALLBACK:Setup:Illegal type %d",type); E_Exit("CALLBACK:Setup:Illegal type %d",type);

View File

@ -375,10 +375,10 @@
flags.cf=get_CF();flags.type=t_RCLd; \ flags.cf=get_CF();flags.type=t_RCLd; \
flags.var2.b=op2;flags.var1.d=load(op1); \ flags.var2.b=op2;flags.var1.d=load(op1); \
if (flags.var2.b==1) { \ if (flags.var2.b==1) { \
flags.result.d=flags.var1.d << 1 | flags.cf; \ flags.result.d=(flags.var1.d << 1) | flags.cf; \
} else { \ } else { \
flags.result.d=(flags.var1.d << flags.var2.b) | \ 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.var1.d >> (33-flags.var2.b)); \
} \ } \
flags.cf=((flags.var1.d >> (32-flags.var2.b)) & 1); \ flags.cf=((flags.var1.d >> (32-flags.var2.b)) & 1); \

View File

@ -66,7 +66,8 @@ restart:
case 0x16: /* PUSH SS */ case 0x16: /* PUSH SS */
Push_16(SegValue(ss));break; Push_16(SegValue(ss));break;
case 0x17: /* POP SS */ case 0x17: /* POP SS */
SegSet16(ss,Pop_16());break; SegSet16(ss,Pop_16());
goto restart;
case 0x18: /* SBB Eb,Gb */ case 0x18: /* SBB Eb,Gb */
RMEbGb(SBBB);break; RMEbGb(SBBB);break;
case 0x19: /* SBB Ew,Gw */ case 0x19: /* SBB Ew,Gw */
@ -292,7 +293,16 @@ restart:
#include "prefix_66.h" #include "prefix_66.h"
break; break;
case 0x67: /* Address Size Prefix */ 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; NOTDONE;
#endif
break; break;
#endif #endif
case 0x68: /* PUSH Iw */ case 0x68: /* PUSH Iw */
@ -538,7 +548,7 @@ restart:
case 0x28: /* MOV Ew,GS */ case 0x28: /* MOV Ew,GS */
val=SegValue(gs);break; val=SegValue(gs);break;
default: default:
val=0; val=0;
E_Exit("CPU:8c:Illegal RM Byte"); E_Exit("CPU:8c:Illegal RM Byte");
} }
if (rm >= 0xc0 ) {GetEArw;*earw=val;} if (rm >= 0xc0 ) {GetEArw;*earw=val;}
@ -566,7 +576,9 @@ restart:
E_Exit("CPU:Illegal MOV CS Call"); E_Exit("CPU:Illegal MOV CS Call");
break; break;
case 0x10: /* MOV SS,Ew */ case 0x10: /* MOV SS,Ew */
SegSet16(ss,val);break; SegSet16(ss,val);
goto restart;
break;
case 0x18: /* MOV DS,Ew */ case 0x18: /* MOV DS,Ew */
SegSet16(ds,val);break; SegSet16(ds,val);break;
case 0x20: /* MOV FS,Ew */ case 0x20: /* MOV FS,Ew */
@ -654,26 +666,22 @@ restart:
} }
case 0xa0: /* MOV AL,Ob */ case 0xa0: /* MOV AL,Ob */
{ {
GetEADirect; reg_al=LoadMb(GetEADirect[prefix.mark]());
reg_al=LoadMb(eaa);
} }
break; break;
case 0xa1: /* MOV AX,Ow */ case 0xa1: /* MOV AX,Ow */
{ {
GetEADirect; reg_ax=LoadMw(GetEADirect[prefix.mark]());
reg_ax=LoadMw(eaa);
} }
break; break;
case 0xa2: /* MOV Ob,AL */ case 0xa2: /* MOV Ob,AL */
{ {
GetEADirect; SaveMb(GetEADirect[prefix.mark](),reg_al);
SaveMb(eaa,reg_al);
} }
break; break;
case 0xa3: /* MOV Ow,AX */ case 0xa3: /* MOV Ow,AX */
{ {
GetEADirect; SaveMw(GetEADirect[prefix.mark](),reg_ax);
SaveMw(eaa,reg_ax);
} }
break; break;
case 0xa4: /* MOVSB */ case 0xa4: /* MOVSB */
@ -856,10 +864,15 @@ restart:
} }
break; break;
case 0xcc: /* INT3 */ case 0xcc: /* INT3 */
#if C_DEBUG
SAVEIP;
if (DEBUG_Breakpoint()) {
LOADIP;
return 1;
}
LOADIP;
#endif
INTERRUPT(3); INTERRUPT(3);
#if C_DEBUG
return 1;
#endif
break; break;
case 0xcd: /* INT Ib */ case 0xcd: /* INT Ib */
{ {
@ -948,6 +961,7 @@ restart:
case 0xde: /* FPU ESC 6 */ case 0xde: /* FPU ESC 6 */
case 0xdf: /* FPU ESC 7 */ case 0xdf: /* FPU ESC 7 */
{ {
LOG_WARN("FPU used");
Bit8u rm=Fetchb(); Bit8u rm=Fetchb();
if (rm<0xc0) GetEAa; if (rm<0xc0) GetEAa;
} }
@ -966,9 +980,15 @@ restart:
else ADDIPFAST(1); else ADDIPFAST(1);
break; break;
case 0xe3: /* JCXZ */ case 0xe3: /* JCXZ */
if (!reg_cx) ADDIPFAST(Fetchbs()); {
else ADDIPFAST(1); Bitu test;
break; 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 */ case 0xe4: /* IN AL,Ib */
{ Bit16u port=Fetchb();reg_al=IO_Read(port);} { Bit16u port=Fetchb();reg_al=IO_Read(port);}
break; break;
@ -1024,11 +1044,11 @@ restart:
E_Exit("CPU:F1:Not Handled"); E_Exit("CPU:F1:Not Handled");
break; break;
case 0xf2: /* REPNZ */ case 0xf2: /* REPNZ */
count-=Repeat_Normal(false,false,count); Repeat_Normal(false,false);
break; continue;
case 0xf3: /* REPZ */ case 0xf3: /* REPZ */
count-=Repeat_Normal(true,false,count); Repeat_Normal(true,false);
break; continue;
case 0xf4: /* HLT */ case 0xf4: /* HLT */
break; break;
case 0xf5: /* CMC */ case 0xf5: /* CMC */
@ -1318,6 +1338,5 @@ restart:
default: default:
NOTDONE; NOTDONE;
break; break;
} }

View File

@ -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_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(); reg_ebx=Pop_32();reg_edx=Pop_32();reg_ecx=Pop_32();reg_eax=Pop_32();
break; break;
case 0x68: /* PUSH Id */
Push_32(Fetchd());break;
case 0x64: /* SEG FS: */ case 0x64: /* SEG FS: */
SegPrefix_66(fs);break; SegPrefix_66(fs);break;
case 0x65: /* SEG GS: */ case 0x65: /* SEG GS: */
SegPrefix_66(gs);break; 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 */ case 0x69: /* IMUL Gd,Ed,Id */
{ {
GetRMrd; GetRMrd;
@ -267,6 +278,15 @@ switch(Fetchb()) {
case 0x8c: case 0x8c:
LOG_WARN("CPU:66:8c looped back"); LOG_WARN("CPU:66:8c looped back");
break; 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 */ case 0x8f: /* POP Ed */
{ {
GetRM; GetRM;
@ -276,25 +296,25 @@ switch(Fetchb()) {
} }
case 0x90: /* NOP */ case 0x90: /* NOP */
break; break;
case 0x91: /* XCHG CX,AX */ case 0x91: /* XCHG ECX,EAX */
{ Bit32u temp=reg_eax;reg_eax=reg_ecx;reg_ecx=temp; } { Bit32u temp=reg_eax;reg_eax=reg_ecx;reg_ecx=temp; }
break; break;
case 0x92: /* XCHG DX,AX */ case 0x92: /* XCHG EDX,EAX */
{ Bit32u temp=reg_eax;reg_eax=reg_edx;reg_edx=temp; } { Bit32u temp=reg_eax;reg_eax=reg_edx;reg_edx=temp; }
break; break;
case 0x93: /* XCHG BX,AX */ case 0x93: /* XCHG EBX,EAX */
{ Bit32u temp=reg_eax;reg_eax=reg_ebx;reg_ebx=temp; } { Bit32u temp=reg_eax;reg_eax=reg_ebx;reg_ebx=temp; }
break; break;
case 0x94: /* XCHG SP,AX */ case 0x94: /* XCHG ESP,EAX */
{ Bit32u temp=reg_eax;reg_eax=reg_esp;reg_esp=temp; } { Bit32u temp=reg_eax;reg_eax=reg_esp;reg_esp=temp; }
break; break;
case 0x95: /* XCHG BP,AX */ case 0x95: /* XCHG EBP,EAX */
{ Bit32u temp=reg_eax;reg_eax=reg_ebp;reg_ebp=temp; } { Bit32u temp=reg_eax;reg_eax=reg_ebp;reg_ebp=temp; }
break; break;
case 0x96: /* XCHG SI,AX */ case 0x96: /* XCHG ESI,EAX */
{ Bit32u temp=reg_eax;reg_eax=reg_esi;reg_esi=temp; } { Bit32u temp=reg_eax;reg_eax=reg_esi;reg_esi=temp; }
break; break;
case 0x97: /* XCHG DI,AX */ case 0x97: /* XCHG EDI,EAX */
{ Bit32u temp=reg_eax;reg_eax=reg_edi;reg_edi=temp; } { Bit32u temp=reg_eax;reg_eax=reg_edi;reg_edi=temp; }
break; break;
case 0x98: /* CWD */ case 0x98: /* CWD */
@ -321,14 +341,12 @@ switch(Fetchb()) {
} }
case 0xa1: /* MOV EAX,Ow */ case 0xa1: /* MOV EAX,Ow */
{ {
GetEADirect; reg_eax=LoadMd(GetEADirect[prefix.mark]());
reg_eax=LoadMd(eaa);
} }
break; break;
case 0xa3: /* MOV Ow,EAX */ case 0xa3: /* MOV Ow,EAX */
{ {
GetEADirect; SaveMd(GetEADirect[prefix.mark](),reg_eax);
SaveMd(eaa,reg_eax);
} }
break; break;
case 0xa5: /* MOVSD */ case 0xa5: /* MOVSD */
@ -383,6 +401,18 @@ switch(Fetchb()) {
reg_edi=Fetchd();break; reg_edi=Fetchd();break;
case 0xc1: /* GRP2 Ed,Ib */ case 0xc1: /* GRP2 Ed,Ib */
GRP2D(Fetchb());break; 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 */ case 0xc7: /* MOV Ed,Id */
{ {
GetRM; GetRM;
@ -396,12 +426,12 @@ switch(Fetchb()) {
GRP2D(reg_cl);break; GRP2D(reg_cl);break;
case 0xf2: /* REPNZ */ case 0xf2: /* REPNZ */
prefix.count++; prefix.count++;
count-=Repeat_Normal(false,true,count); Repeat_Normal(false,true);
break; continue;
case 0xf3: /* REPZ */ case 0xf3: /* REPZ */
prefix.count++; prefix.count++;
count-=Repeat_Normal(true,true,count); Repeat_Normal(true,true);
break; continue;
case 0xf7: /* GRP3 Ed(,Id) */ case 0xf7: /* GRP3 Ed(,Id) */
{ {
union { Bit64u u;Bit64s s;} temp; union { Bit64u u;Bit64s s;} temp;
@ -436,18 +466,18 @@ switch(Fetchb()) {
case 0x20: /* MUL EAX,Ed */ case 0x20: /* MUL EAX,Ed */
{ {
flags.type=t_MUL; 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);} 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); flags.cf=flags.of=(reg_edx !=0);
break; break;
} }
case 0x28: /* IMUL EAX,Ed */ case 0x28: /* IMUL EAX,Ed */
{ {
flags.type=t_MUL; flags.type=t_MUL;
if (rm >= 0xc0 ) {GetEArd;temp.s=(Bit64s)reg_eax * (Bit64s)(*eards);} if (rm >= 0xc0 ) {GetEArd;temp.s=((Bit64s)((Bit32s)reg_eax) * (Bit64s)(*eards));}
else {GetEAa;temp.s=(Bit64s)reg_eax * (Bit64s)LoadMds(eaa);} else {GetEAa;temp.s=((Bit64s)((Bit32s)reg_eax) * (Bit64s)(LoadMds(eaa)));}
reg_eax=Bit32u(temp.u & 0xffffffff);reg_edx=(Bit32u)(temp.u >> 32); reg_eax=Bit32u(temp.s & 0xffffffff);reg_edx=(Bit32u)(temp.s >> 32);
if ( (reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) { if ( (reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) {
flags.cf=flags.of=false; flags.cf=flags.of=false;
} else if ( (reg_edx==0x00000000) && (reg_eax<0x80000000) ) { } else if ( (reg_edx==0x00000000) && (reg_eax<0x80000000) ) {

View File

@ -33,6 +33,14 @@ switch (Fetchb()) {
else {GetEAa;DSHRD(eaa,*rmrd,Fetchb(),LoadMd,SaveMd);} else {GetEAa;DSHRD(eaa,*rmrd,Fetchb(),LoadMd,SaveMd);}
break; 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 */ case 0xb6: /* MOVZX Gd,Eb */
{ {
GetRMrd; GetRMrd;
@ -44,8 +52,8 @@ switch (Fetchb()) {
{ {
GetRMrd; GetRMrd;
Bit64s res; Bit64s res;
if (rm >= 0xc0 ) {GetEArd;res=(Bit64s)(*rmrd) * (Bit64s)(*eards);} if (rm >= 0xc0 ) {GetEArd;res=((Bit64s)((Bit32s)*rmrd) * (Bit64s)((Bit32s)*eards));}
else {GetEAa;res=(Bit64s)(*rmrd) * (Bit64s)LoadMds(eaa);} else {GetEAa;res=((Bit64s)((Bit32s)*rmrd) * (Bit64s)LoadMds(eaa));}
*rmrd=(Bit32s)(res); *rmrd=(Bit32s)(res);
flags.type=t_MUL; flags.type=t_MUL;
if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {flags.cf=false;flags.of=false;} if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {flags.cf=false;flags.of=false;}
@ -108,6 +116,56 @@ switch (Fetchb()) {
flags.type=t_CF; flags.type=t_CF;
break; 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 */ case 0xbe: /* MOVSX Gd,Eb */
{ {
GetRMrd; GetRMrd;

View File

@ -59,6 +59,12 @@ switch(Fetchb()) {
/* 0x21 MOV Rd,DRx (386) */ /* 0x21 MOV Rd,DRx (386) */
/* 0x22 MOV CRx,Rd (386) */ /* 0x22 MOV CRx,Rd (386) */
/* 0x23 MOV DRx,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) */ /* 0x24 MOV Rd,TRx (386) */
/* 0x26 MOV TRx,Rd (386) */ /* 0x26 MOV TRx,Rd (386) */
/* 0x30 WRMSR (P5) */ /* 0x30 WRMSR (P5) */
@ -251,7 +257,12 @@ switch(Fetchb()) {
} }
/* 0xb0 CMPXCHG Eb,Gb */ /* 0xb0 CMPXCHG Eb,Gb */
/* 0xb1 CMPXCHG Ew,Gw */ /* 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 */ case 0xb3: /* BTR Ew,Gw */
{ {
GetRMrw; GetRMrw;
@ -389,7 +400,6 @@ switch(Fetchb()) {
flags.type=t_UNKNOWN; flags.type=t_UNKNOWN;
break; break;
} }
/* 0xbd BSR Gw,Ew */
case 0xbe: /* MOVSX Gw,Eb */ case 0xbe: /* MOVSX Gw,Eb */
{ {
GetRMrw; GetRMrw;

View File

@ -16,4 +16,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
decode_end:
SAVEIP; SAVEIP;

View File

@ -95,22 +95,26 @@ static INLINE Bit32u Pop_32() {
from=SegBase(ds)+reg_si; \ from=SegBase(ds)+reg_si; \
} }
#include "helpers.h" #include "helpers.h"
#include "table_ea.h" #include "table_ea.h"
#include "../modrm.h" #include "../modrm.h"
#include "instructions.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; PhysPt base_si,base_di;
Bit16s direct; Bit16s direct;
if (flags.df) direct=-1; if (flags.df) direct=-1;
else direct=1; else direct=1;
base_di=SegBase(es); base_di=SegBase(es);
if (prefix.mark & PREFIX_ADDR) E_Exit("Unhandled 0x67 prefixed string op");
rep_again: rep_again:
if (prefix.mark & PREFIX_SEG) { if (prefix.mark & PREFIX_SEG) {
base_si=(prefix.segbase); base_si=(prefix.segbase);
@ -138,21 +142,32 @@ rep_again:
prefix.mark|=PREFIX_SEG; prefix.mark|=PREFIX_SEG;
prefix.count++; prefix.count++;
goto rep_again; 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 */ case 0x66: /* Size Prefix */
prefix.count++; prefix.count++;
prefix_66=!prefix_66; prefix_66=!prefix_66;
goto rep_again; goto rep_again;
case 0x6c: /* REP INSB */ 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)); SaveMb(base_di+reg_di,IO_Read(reg_dx));
reg_di+=direct; reg_di+=direct;
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0x6d: /* REP INSW/D */ case 0x6d: /* REP INSW/D */
if (prefix_66) { if (prefix_66) {
direct*=4; 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+0,IO_Read(reg_dx+0));
SaveMb(base_di+reg_di+1,IO_Read(reg_dx+1)); SaveMb(base_di+reg_di+1,IO_Read(reg_dx+1));
SaveMb(base_di+reg_di+2,IO_Read(reg_dx+2)); SaveMb(base_di+reg_di+2,IO_Read(reg_dx+2));
@ -161,25 +176,26 @@ rep_again:
} }
} else { } else {
direct*=2; 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+0,IO_Read(reg_dx+0));
SaveMb(base_di+reg_di+1,IO_Read(reg_dx+1)); SaveMb(base_di+reg_di+1,IO_Read(reg_dx+1));
reg_di+=direct; reg_di+=direct;
} }
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0x6e: /* REP OUTSB */ 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)); IO_Write(reg_dx,LoadMb(base_si+reg_si));
reg_si+=direct; reg_si+=direct;
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0x6f: /* REP OUTSW/D */ case 0x6f: /* REP OUTSW/D */
if (prefix_66) { if (prefix_66) {
direct*=4; 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+0,LoadMb(base_si+reg_si+0));
IO_Write(reg_dx+1,LoadMb(base_si+reg_si+1)); IO_Write(reg_dx+1,LoadMb(base_si+reg_si+1));
IO_Write(reg_dx+2,LoadMb(base_si+reg_si+2)); IO_Write(reg_dx+2,LoadMb(base_si+reg_si+2));
@ -188,161 +204,152 @@ rep_again:
} }
} else { } else {
direct*=2; 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+0,LoadMb(base_si+reg_si+0));
IO_Write(reg_dx+1,LoadMb(base_si+reg_si+1)); IO_Write(reg_dx+1,LoadMb(base_si+reg_si+1));
reg_si+=direct; reg_si+=direct;
} }
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0xa4: /* REP MOVSB */ 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)); SaveMb(base_di+reg_di,LoadMb(base_si+reg_si));
reg_si+=direct;reg_di+=direct; reg_si+=direct;reg_di+=direct;
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0xa5: /* REP MOVSW/D */ case 0xa5: /* REP MOVSW/D */
if (prefix_66) { if (prefix_66) {
direct*=4; 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)); SaveMd(base_di+reg_di,LoadMd(base_si+reg_si));
reg_si+=direct;reg_di+=direct; reg_si+=direct;reg_di+=direct;
} }
} else { } else {
direct*=2; 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)); SaveMw(base_di+reg_di,LoadMw(base_si+reg_si));
reg_si+=direct;reg_di+=direct; reg_si+=direct;reg_di+=direct;
} }
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0xa6: /* REP CMPSB */ case 0xa6: /* REP CMPSB */
{ {
if (!reg_cx) goto stopit;Bit8u op1,op2; Bit8u op1,op2;
for (;(reg_cx && count>0);) { 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); op1=LoadMb(base_si+reg_si);op2=LoadMb(base_di+reg_di);
reg_cx--,count--;reg_si+=direct;reg_di+=direct; reg_cx--;reg_si+=direct;reg_di+=direct;
if ((op1==op2)!=testz) break; if ((op1==op2)!=testz || !reg_cx) { CMPB(op1,op2,LoadRb,0);goto normalexit; }
} }
CMPB(op1,op2,LoadRb,0); CMPB(op1,op2,LoadRb,0);
if ((op1==op2)!=testz) goto stopit;
if (reg_cx && count<=0) goto countzero;
} }
break; break;
case 0xa7: /* REP CMPSW */ case 0xa7: /* REP CMPSW */
{ {
if (!reg_cx) goto stopit; if (!reg_cx) { CPU_Cycles--;goto normalexit; }
if (prefix_66) { if (prefix_66) {
direct*=4; direct*=4;Bit32u op1,op2;
Bit32u op1,op2; for (;CPU_Cycles>0;CPU_Cycles--) {
for (;(reg_cx && count>0);) {
op1=LoadMd(base_si+reg_si);op2=LoadMd(base_di+reg_di); op1=LoadMd(base_si+reg_si);op2=LoadMd(base_di+reg_di);
reg_cx--,count--;reg_si+=direct;reg_di+=direct; reg_cx--;reg_si+=direct;reg_di+=direct;
if ((op1==op2)!=testz) break; if ((op1==op2)!=testz || !reg_cx) { CMPD(op1,op2,LoadRd,0);goto normalexit; }
} }
CMPD(op1,op2,LoadRd,0); CMPD(op1,op2,LoadRd,0);
if ((op1==op2)!=testz) goto stopit;
} else { } else {
direct*=2; direct*=2;Bit16u op1,op2;
Bit16u op1,op2; for (;CPU_Cycles>0;CPU_Cycles--) {
for (;(reg_cx && count>0);) {
op1=LoadMw(base_si+reg_si);op2=LoadMw(base_di+reg_di); op1=LoadMw(base_si+reg_si);op2=LoadMw(base_di+reg_di);
reg_cx--,count--;reg_si+=direct;reg_di+=direct; reg_cx--,reg_si+=direct;reg_di+=direct;
if ((op1==op2)!=testz) break; if ((op1==op2)!=testz || !reg_cx) { CMPW(op1,op2,LoadRw,0);goto normalexit; }
} }
CMPW(op1,op2,LoadRw,0); CMPW(op1,op2,LoadRw,0);
if ((op1==op2)!=testz) goto stopit;
} }
if (reg_cx && count<=0) goto countzero;
} }
break; break;
case 0xaa: /* REP STOSB */ 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); SaveMb(base_di+reg_di,reg_al);
reg_di+=direct; reg_di+=direct;
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0xab: /* REP STOSW */ case 0xab: /* REP STOSW */
if (prefix_66) { if (prefix_66) {
direct*=4; 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); SaveMd(base_di+reg_di,reg_eax);
reg_di+=direct; reg_di+=direct;
} }
} else { } else {
direct*=2; 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); SaveMw(base_di+reg_di,reg_ax);
reg_di+=direct; reg_di+=direct;
} }
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0xac: /* REP LODSB */ 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_al=LoadMb(base_si+reg_si);
reg_si+=direct; reg_si+=direct;
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0xad: /* REP LODSW */ case 0xad: /* REP LODSW */
if (prefix_66) { if (prefix_66) {
direct*=4; 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_eax=LoadMd(base_si+reg_si);
reg_si+=direct; reg_si+=direct;
} }
} else { } else {
direct*=2; 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_ax=LoadMw(base_si+reg_si);
reg_si+=direct; reg_si+=direct;
} }
} }
if (reg_cx && count<=0) goto countzero;
break; break;
case 0xae: /* REP SCASB */ case 0xae: /* REP SCASB */
{ {
if (!reg_cx) goto stopit;Bit8u op2; Bit8u op2;
for (;(reg_cx && count>0);) { if (!reg_cx) { CPU_Cycles--;goto normalexit; }
for (;CPU_Cycles>0;CPU_Cycles--) {
op2=LoadMb(base_di+reg_di); op2=LoadMb(base_di+reg_di);
reg_cx--,count--;reg_di+=direct; reg_cx--;reg_di+=direct;
if ((reg_al==op2)!=testz) break; if ((reg_al==op2)!=testz || !reg_cx) { CMPB(reg_al,op2,LoadRb,0);goto normalexit; }
} }
CMPB(reg_al,op2,LoadRb,0); CMPB(reg_al,op2,LoadRb,0);
if ((reg_al==op2)!=testz) goto stopit;
if (reg_cx && count<=0) goto countzero;
} }
break; break;
case 0xaf: /* REP SCASW */ case 0xaf: /* REP SCASW */
{ {
if (!reg_cx) goto stopit; if (!reg_cx) { CPU_Cycles--;goto normalexit; }
if (prefix_66) { if (prefix_66) {
direct*=4; direct*=4;Bit32u op2;
Bit32u op2; for (;CPU_Cycles>0;CPU_Cycles--) {
for (;(reg_cx && count>0);) {
op2=LoadMd(base_di+reg_di); op2=LoadMd(base_di+reg_di);
reg_cx--,count--;reg_di+=direct; reg_cx--;reg_di+=direct;
if ((reg_eax==op2)!=testz) break; if ((reg_eax==op2)!=testz || !reg_cx) { CMPD(reg_eax,op2,LoadRd,0);goto normalexit; }
} }
CMPD(reg_eax,op2,LoadRd,0); CMPD(reg_eax,op2,LoadRd,0);
if ((reg_eax==op2)!=testz) goto stopit;
} else { } else {
direct*=2; direct*=2;Bit16u op2;
Bit16u op2; for (;CPU_Cycles>0;CPU_Cycles--) {
for (;(reg_cx && count>0);) {
op2=LoadMw(base_di+reg_di); op2=LoadMw(base_di+reg_di);
reg_cx--,count--;reg_di+=direct; reg_cx--;reg_di+=direct;
if ((reg_ax==op2)!=testz) break; if ((reg_ax==op2)!=testz || !reg_cx) { CMPW(reg_ax,op2,LoadRw,0);goto normalexit; }
} }
CMPW(reg_ax,op2,LoadRw,0); CMPW(reg_ax,op2,LoadRw,0);
if ((reg_ax==op2)!=testz) goto stopit;
} }
if (reg_cx && count<=0) goto countzero;
} }
break; break;
default: default:
@ -350,13 +357,10 @@ rep_again:
LOG_DEBUG("Unhandled REP Prefix %X",Fetchb()); LOG_DEBUG("Unhandled REP Prefix %X",Fetchb());
} }
stopit: /* If we end up here it's because the CPU_Cycles counter is 0, so restart instruction */
PrefixReset;
return count_remain-count;
countzero:
IPPoint-=(prefix.count+2); /* Rep instruction and whatever string instruction */ IPPoint-=(prefix.count+2); /* Rep instruction and whatever string instruction */
normalexit:
PrefixReset; PrefixReset;
return count_remain;
} }
//flags.io and nt shouldn't be compiled for 386 //flags.io and nt shouldn't be compiled for 386
@ -376,7 +380,10 @@ countzero:
PIC_runIRQs(); \ PIC_runIRQs(); \
LOADIP; \ 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 #else
@ -394,7 +401,10 @@ countzero:
PIC_runIRQs(); \ PIC_runIRQs(); \
LOADIP; \ 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 #endif

View File

@ -19,6 +19,8 @@
/* Some variables for EA Loolkup */ /* Some variables for EA Loolkup */
typedef EAPoint (*GetEATable[256])(void); typedef EAPoint (*GetEATable[256])(void);
typedef EAPoint (*EA_LookupHandler)(void);
static GetEATable * lookupEATable; static GetEATable * lookupEATable;
#define PREFIX_NONE 0x0 #define PREFIX_NONE 0x0
@ -35,6 +37,7 @@ static struct {
/* Gets initialized at the bottem, can't seem to declare forward references */ /* Gets initialized at the bottem, can't seem to declare forward references */
static GetEATable * EAPrefixTable[4]; static GetEATable * EAPrefixTable[4];
#define SegPrefix(blah) \ #define SegPrefix(blah) \
prefix.segbase=SegBase(blah); \ prefix.segbase=SegBase(blah); \
prefix.mark|=PREFIX_SEG; \ prefix.mark|=PREFIX_SEG; \
@ -55,29 +58,6 @@ static GetEATable * EAPrefixTable[4];
prefix.count=0; \ prefix.count=0; \
lookupEATable=EAPrefixTable[PREFIX_NONE]; 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 */ /* 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); } 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_00_n(void) { PrefixReset;return SegBase(ds)+reg_eax; }
static EAPoint EA_32_01_n(void) { return SegBase(ds)+reg_ecx; } static EAPoint EA_32_01_n(void) { PrefixReset;return SegBase(ds)+reg_ecx; }
static EAPoint EA_32_02_n(void) { return SegBase(ds)+reg_edx; } static EAPoint EA_32_02_n(void) { PrefixReset;return SegBase(ds)+reg_edx; }
static EAPoint EA_32_03_n(void) { return SegBase(ds)+reg_ebx; } static EAPoint EA_32_03_n(void) { PrefixReset;return SegBase(ds)+reg_ebx; }
static EAPoint EA_32_04_n(void) { return Sib(0);} static EAPoint EA_32_04_n(void) { PrefixReset;return Sib(0);}
static EAPoint EA_32_05_n(void) { return SegBase(ds)+Fetchd(); } static EAPoint EA_32_05_n(void) { PrefixReset;return SegBase(ds)+Fetchd(); }
static EAPoint EA_32_06_n(void) { return SegBase(ss)+reg_esi; } static EAPoint EA_32_06_n(void) { PrefixReset;return SegBase(ds)+reg_esi; }
static EAPoint EA_32_07_n(void) { return SegBase(ds)+reg_edi; } 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_40_n(void) { PrefixReset;return SegBase(ds)+reg_eax+Fetchbs(); }
static EAPoint EA_32_41_n(void) { return SegBase(ds)+reg_ecx+Fetchbs(); } static EAPoint EA_32_41_n(void) { PrefixReset;return SegBase(ds)+reg_ecx+Fetchbs(); }
static EAPoint EA_32_42_n(void) { return SegBase(ds)+reg_edx+Fetchbs(); } static EAPoint EA_32_42_n(void) { PrefixReset;return SegBase(ds)+reg_edx+Fetchbs(); }
static EAPoint EA_32_43_n(void) { return SegBase(ds)+reg_ebx+Fetchbs(); } static EAPoint EA_32_43_n(void) { PrefixReset;return SegBase(ds)+reg_ebx+Fetchbs(); }
static EAPoint EA_32_44_n(void) { return Sib(1)+Fetchbs();} static EAPoint EA_32_44_n(void) { PrefixReset;return Sib(1)+Fetchbs();}
static EAPoint EA_32_45_n(void) { return SegBase(ss)+reg_ebp+Fetchbs(); } static EAPoint EA_32_45_n(void) { PrefixReset;return SegBase(ss)+reg_ebp+Fetchbs(); }
static EAPoint EA_32_46_n(void) { return SegBase(ds)+reg_esi+Fetchbs(); } static EAPoint EA_32_46_n(void) { PrefixReset;return SegBase(ds)+reg_esi+Fetchbs(); }
static EAPoint EA_32_47_n(void) { return SegBase(ds)+reg_edi+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_80_n(void) { PrefixReset;return SegBase(ds)+reg_eax+Fetchds(); }
static EAPoint EA_32_81_n(void) { return SegBase(ds)+reg_ecx+Fetchds(); } static EAPoint EA_32_81_n(void) { PrefixReset;return SegBase(ds)+reg_ecx+Fetchds(); }
static EAPoint EA_32_82_n(void) { return SegBase(ds)+reg_edx+Fetchds(); } static EAPoint EA_32_82_n(void) { PrefixReset;return SegBase(ds)+reg_edx+Fetchds(); }
static EAPoint EA_32_83_n(void) { return SegBase(ds)+reg_ebx+Fetchds(); } static EAPoint EA_32_83_n(void) { PrefixReset;return SegBase(ds)+reg_ebx+Fetchds(); }
static EAPoint EA_32_84_n(void) { return Sib(2)+Fetchds();} static EAPoint EA_32_84_n(void) { PrefixReset;return Sib(2)+Fetchds();}
static EAPoint EA_32_85_n(void) { return SegBase(ss)+reg_ebp+Fetchds(); } static EAPoint EA_32_85_n(void) { PrefixReset;return SegBase(ss)+reg_ebp+Fetchds(); }
static EAPoint EA_32_86_n(void) { return SegBase(ds)+reg_esi+Fetchds(); } static EAPoint EA_32_86_n(void) { PrefixReset;return SegBase(ds)+reg_esi+Fetchds(); }
static EAPoint EA_32_87_n(void) { return SegBase(ds)+reg_edi+Fetchds(); } static EAPoint EA_32_87_n(void) { PrefixReset;return SegBase(ds)+reg_edi+Fetchds(); }
static GetEATable GetEA_32_n={ static GetEATable GetEA_32_n={
/* 00 */ /* 00 */
@ -327,7 +307,8 @@ INLINE EAPoint Sib_s(Bitu mode) {
case 7: /* EDI Base */ case 7: /* EDI Base */
base=prefix.segbase+reg_edi;break; base=prefix.segbase+reg_edi;break;
} }
base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); PrefixReset; base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6);
PrefixReset;
return base; 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_41_s(void) { segprefixed_32(reg_ecx+Fetchbs()); }
static EAPoint EA_32_42_s(void) { segprefixed_32(reg_edx+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_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_45_s(void) { segprefixed_32(reg_ebp+Fetchbs()); }
static EAPoint EA_32_46_s(void) { segprefixed_32(reg_esi+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()); } 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_81_s(void) { segprefixed_32(reg_ecx+Fetchds()); }
static EAPoint EA_32_82_s(void) { segprefixed_32(reg_edx+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_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_85_s(void) { segprefixed_32(reg_ebp+Fetchds()); }
static EAPoint EA_32_86_s(void) { segprefixed_32(reg_esi+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()); } 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 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};

View File

@ -30,21 +30,24 @@ Flag_Info flags;
CPU_Regs cpu_regs; CPU_Regs cpu_regs;
Segment Segs[6]; Segment Segs[6];
Bitu cpu_cycles;
Bits CPU_Cycles=0;
Bits CPU_CycleLeft=0;
Bits CPU_CycleMax=1500;
CPU_Decoder * cpudecoder; CPU_Decoder * cpudecoder;
static void CPU_CycleIncrease(void) { static void CPU_CycleIncrease(void) {
Bitu old_cycles=cpu_cycles; Bitu old_cycles=CPU_CycleMax;
cpu_cycles=(Bitu)(cpu_cycles*1.2); CPU_CycleMax=(Bitu)(CPU_CycleMax*1.2);
if (cpu_cycles==old_cycles) cpu_cycles++; if (CPU_CycleMax==old_cycles) CPU_CycleMax++;
LOG_MSG("CPU:%d cycles",cpu_cycles); LOG_MSG("CPU:%d cycles",CPU_CycleMax);
} }
static void CPU_CycleDecrease(void) { static void CPU_CycleDecrease(void) {
cpu_cycles=(Bitu)(cpu_cycles/1.2); CPU_CycleMax=(Bitu)(CPU_CycleMax/1.2);
if (!cpu_cycles) cpu_cycles=1; if (!CPU_CycleMax) CPU_CycleMax=1;
LOG_MSG("CPU:%d cycles",cpu_cycles); LOG_MSG("CPU:%d cycles",CPU_CycleMax);
} }
Bit8u lastint; Bit8u lastint;
@ -67,10 +70,10 @@ void Interrupt(Bit8u num) {
case 0x11: case 0x11:
case 0x12: case 0x12:
case 0x13: case 0x13:
case 0x16:
case 0x15: case 0x15:
case 0x1A: case 0x16:
case 0x17: case 0x17:
case 0x1A:
case 0x1C: case 0x1C:
case 0x21: case 0x21:
case 0x2a: case 0x2a:
@ -80,6 +83,10 @@ void Interrupt(Bit8u num) {
case 0x74: case 0x74:
break; break;
case 0xcd: 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"); E_Exit("Call to interrupt 0xCD this is BAD");
case 0x03: case 0x03:
#if C_DEBUG #if C_DEBUG
@ -163,13 +170,15 @@ void CPU_Init(Section* sec) {
flags.io=0; flags.io=0;
SetCPU16bit(); SetCPU16bit();
cpu_cycles=section->Get_int("cycles");
if (!cpu_cycles) cpu_cycles=300;
KEYBOARD_AddEvent(KBD_f11,CTRL_PRESSED,CPU_CycleDecrease); KEYBOARD_AddEvent(KBD_f11,CTRL_PRESSED,CPU_CycleDecrease);
KEYBOARD_AddEvent(KBD_f12,CTRL_PRESSED,CPU_CycleIncrease); KEYBOARD_AddEvent(KBD_f12,CTRL_PRESSED,CPU_CycleIncrease);
reg_al=0; CPU_Cycles=0;
reg_ah=0; CPU_CycleMax=section->Get_int("cycles");;
MSG_Add("CPU_CONFIGFILE_HELP","The amount of cycles to execute each loop. Lowering this setting will slowdown dosbox\n"); 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");
} }

View File

@ -46,7 +46,6 @@ bool get_CF(void) {
case t_RCLd: case t_RCLd:
return flags.cf; return flags.cf;
break; break;
case t_ADDb: case t_ADDb:
return (flags.result.b<flags.var1.b); return (flags.result.b<flags.var1.b);
case t_ADDw: case t_ADDw:
@ -131,12 +130,11 @@ bool get_CF(void) {
case t_TESTb: case t_TESTb:
case t_TESTw: case t_TESTw:
case t_TESTd: case t_TESTd:
return false; /* Set to false */
case t_DIV: case t_DIV:
return false; return false; /* Unkown */
default: default:
E_Exit("get_CF Unknown %d",flags.type); LOG_WARN("get_CF Unknown %d",flags.type);
} }
return 0; return 0;
} }
@ -166,7 +164,6 @@ again:
case t_CF: case t_CF:
type=flags.prev_type; type=flags.prev_type;
goto again; goto again;
case t_ADDb: case t_ADDb:
case t_ADCb: case t_ADCb:
case t_SBBb: case t_SBBb:
@ -223,15 +220,16 @@ again:
case t_SHRd: case t_SHRd:
case t_SARb: case t_SARb:
case t_SARw: case t_SARw:
case t_SARd:
case t_DSHLw: case t_DSHLw:
case t_DSHLd: case t_DSHLd:
case t_DSHRw: case t_DSHRw:
case t_DSHRd: case t_DSHRd:
case t_DIV: case t_DIV:
case t_MUL: case t_MUL:
return false; /* undefined */ return false; /* Unkown */
default: default:
E_Exit("get_AF Unknown %d",flags.type); LOG_WARN("get_AF Unknown %d",flags.type);
} }
return 0; return 0;
} }
@ -314,9 +312,9 @@ again:
return (flags.result.d==0); return (flags.result.d==0);
case t_DIV: case t_DIV:
case t_MUL: case t_MUL:
return false; return false; /* Unkown */
default: default:
E_Exit("get_ZF Unknown %d",flags.type); LOG_WARN("get_ZF Unknown %d",flags.type);
} }
return false; return false;
} }
@ -344,7 +342,6 @@ again:
case t_CF: case t_CF:
type=flags.prev_type; type=flags.prev_type;
goto again; goto again;
case t_ADDb: case t_ADDb:
case t_ORb: case t_ORb:
case t_ADCb: case t_ADCb:
@ -399,9 +396,9 @@ again:
return (flags.result.d>=0x80000000); return (flags.result.d>=0x80000000);
case t_DIV: case t_DIV:
case t_MUL: case t_MUL:
return false; return false; /* Unkown */
default: default:
E_Exit("get_SF Unkown %d",flags.type); LOG_WARN("get_SF Unkown %d",flags.type);
} }
return false; return false;
@ -419,6 +416,9 @@ again:
case t_RCLb: case t_RCLb:
case t_RCLw: case t_RCLw:
case t_RCLd: case t_RCLd:
case t_SARb:
case t_SARw:
case t_SARd:
return flags.of; return flags.of;
case t_CF: case t_CF:
type=flags.prev_type; type=flags.prev_type;
@ -523,9 +523,6 @@ again:
return (flags.result.w >= 0x4000); return (flags.result.w >= 0x4000);
case t_SHRd: case t_SHRd:
return (flags.result.d >= 0x40000000); return (flags.result.d >= 0x40000000);
case t_SARb:
case t_SARw:
case t_SARd:
case t_ORb: case t_ORb:
case t_ORw: case t_ORw:
case t_ORd: case t_ORd:
@ -538,10 +535,11 @@ again:
case t_TESTb: case t_TESTb:
case t_TESTw: case t_TESTw:
case t_TESTd: case t_TESTd:
return false; /* Return false */
case t_DIV: case t_DIV:
return false; return false; /* Unkown */
default: default:
E_Exit("get_OF Unkown %d",flags.type); LOG_WARN("get_OF Unkown %d",flags.type);
} }
return false; return false;
} }

View File

@ -55,49 +55,55 @@ extern Bitu cycle_count;
/* Enable parts of the cpu emulation */ /* Enable parts of the cpu emulation */
#define CPU_386 //Enable 386 instructions #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 #if C_FPU
#define CPU_FPU //Enable FPU escape instructions #define CPU_FPU //Enable FPU escape instructions
#endif #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" #include "core_16/start.h"
do { while (CPU_Cycles>0) {
#if C_DEBUG #if C_DEBUG
cycle_count++; cycle_count++;
#endif #endif
#if C_HEAVY_DEBUG #if C_HEAVY_DEBUG
SAVEIP; SAVEIP;
if (DEBUG_HeavyIsBreakpoint()) return CBRET_NONE; if (DEBUG_HeavyIsBreakpoint()) return 1;
#endif #endif
#include "core_16/main.h" #include "core_16/main.h"
} while (--count>0); if (prefix.count) {
PrefixReset;
//DEBUG_HeavyWriteLogInstruction();
LOG_DEBUG("Prefix for non prefixed instruction");
}
CPU_Cycles--;
}
#include "core_16/stop.h" #include "core_16/stop.h"
return CBRET_NONE; return CBRET_NONE;
} }
static Bitu CPU_Real_16_Slow_Decode_Special(Bits count) { static Bitu CPU_Real_16_Slow_Decode_Trap(void) {
while (count>0) {
if (flags.tf) { Bits oldCycles = CPU_Cycles;
Interrupt(3); CPU_Cycles = 1;
cpudecoder=&CPU_Real_16_Slow_Decode; CPU_Real_16_Slow_Decode();
return CBRET_NONE;
} // LOG_DEBUG("TRAP: Trap Flag executed");
CPU_Real_16_Slow_Decode(1); INTERRUPT(1);
if (!flags.tf) {
cpudecoder=&CPU_Real_16_Slow_Decode; CPU_Cycles = oldCycles-1;
return CBRET_NONE; cpudecoder = &CPU_Real_16_Slow_Decode;
};
count--;
}
return CBRET_NONE; return CBRET_NONE;
} }
void CPU_Real_16_Slow_Start(void) { void CPU_Real_16_Slow_Start(void) {
cpudecoder=&CPU_Real_16_Slow_Decode; cpudecoder=&CPU_Real_16_Slow_Decode;
EAPrefixTable[0]=&GetEA_16_n; EAPrefixTable[0]=&GetEA_16_n;
EAPrefixTable[1]=&GetEA_16_s; EAPrefixTable[1]=&GetEA_16_s;

View File

@ -34,7 +34,7 @@
#include "mixer.h" #include "mixer.h"
#include "debug_inc.h" #include "debug_inc.h"
#include "timer.h" #include "timer.h"
#include "..\shell\shell_inc.h" #include "../shell/shell_inc.h"
#ifdef WIN32 #ifdef WIN32
void WIN32_Console(); void WIN32_Console();
@ -48,6 +48,7 @@ class DEBUG;
DEBUG* pDebugcom = 0; DEBUG* pDebugcom = 0;
bool exitLoop = false; bool exitLoop = false;
bool logHeavy = false;
static struct { static struct {
Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip; Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip;
@ -91,7 +92,7 @@ static Bit16u dataSeg,dataOfs;
bool skipFirstInstruction = false; 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 #define BPINT_ALL 0x100
@ -104,21 +105,24 @@ public:
void SetAddress (PhysPt adr) { location = adr; type = BKPNT_PHYSICAL; }; void SetAddress (PhysPt adr) { location = adr; type = BKPNT_PHYSICAL; };
void SetInt (Bit8u _intNr, Bit16u ah) { intNr = _intNr, ahValue = ah; type = BKPNT_INTERRUPT; }; void SetInt (Bit8u _intNr, Bit16u ah) { intNr = _intNr, ahValue = ah; type = BKPNT_INTERRUPT; };
void SetOnce (bool _once) { once = _once; }; void SetOnce (bool _once) { once = _once; };
void SetType (EBreakpoint _type) { type = _type; };
void SetValue (Bit8u value) { ahValue = value; };
bool IsActive (void) { return active; }; bool IsActive (void) { return active; };
void Activate (bool _active); void Activate (bool _active);
EBreakpoint GetType (void) { return type; }; EBreakpoint GetType (void) { return type; };
bool GetOnce (void) { return once; }; 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; }; Bit16u GetSegment (void) { return segment; };
Bit32u GetOffset (void) { return offset; }; Bit32u GetOffset (void) { return offset; };
Bit8u GetIntNr (void) { if (GetType()==BKPNT_INTERRUPT) return intNr; else return 0; }; Bit8u GetIntNr (void) { if (GetType()==BKPNT_INTERRUPT) return intNr; else return 0; };
Bit16u GetValue (void) { if (GetType()==BKPNT_INTERRUPT) return ahValue; else return 0; }; Bit16u GetValue (void) { if (GetType()!=BKPNT_PHYSICAL) return ahValue; else return 0; };
// statics // statics
static CBreakpoint* AddBreakpoint (Bit16u seg, Bit32u off, bool once); static CBreakpoint* AddBreakpoint (Bit16u seg, Bit32u off, bool once);
static CBreakpoint* AddIntBreakpoint (Bit8u intNum, Bit16u ah, 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 void ActivateBreakpoints (PhysPt adr, bool activate);
static bool CheckBreakpoint (PhysPt adr); static bool CheckBreakpoint (PhysPt adr);
static bool CheckIntBreakpoint (PhysPt adr, Bit8u intNr, Bit16u ahValue); static bool CheckIntBreakpoint (PhysPt adr, Bit8u intNr, Bit16u ahValue);
@ -145,6 +149,7 @@ private:
bool once; bool once;
static std::list<CBreakpoint*> BPoints; static std::list<CBreakpoint*> BPoints;
public:
static CBreakpoint* ignoreOnce; static CBreakpoint* ignoreOnce;
}; };
@ -192,9 +197,18 @@ CBreakpoint* CBreakpoint::AddIntBreakpoint(Bit8u intNum, Bit16u ah, bool once)
return bp; 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) void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
{ {
ignoreOnce = 0;
// activate all breakpoints // activate all breakpoints
std::list<CBreakpoint*>::iterator i; std::list<CBreakpoint*>::iterator i;
CBreakpoint* bp; CBreakpoint* bp;
@ -202,7 +216,7 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
bp = static_cast<CBreakpoint*>(*i); bp = static_cast<CBreakpoint*>(*i);
// Do not activate, when bp is an actual adress // Do not activate, when bp is an actual adress
if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) {
ignoreOnce = bp; // Do not activate :)
continue; continue;
} }
bp->Activate(activate); bp->Activate(activate);
@ -212,26 +226,45 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
bool CBreakpoint::CheckBreakpoint(PhysPt adr) bool CBreakpoint::CheckBreakpoint(PhysPt adr)
// Checks if breakpoint is valid an should stop execution // 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 // Search matching breakpoint
std::list<CBreakpoint*>::iterator i; std::list<CBreakpoint*>::iterator i;
CBreakpoint* bp; CBreakpoint* bp;
for(i=BPoints.begin(); i != BPoints.end(); i++) { for(i=BPoints.begin(); i != BPoints.end(); i++) {
bp = static_cast<CBreakpoint*>(*i); bp = static_cast<CBreakpoint*>(*i);
if ((bp->GetType()==BKPNT_PHYSICAL) && bp->IsActive() && (bp->GetLocation()==adr)) { if ((bp->GetType()==BKPNT_PHYSICAL) && bp->IsActive() && (bp->GetLocation()==adr)) {
// Ignore Once ?
if (ignoreOnce==bp) {
ignoreOnce=0;
bp->Activate(true);
return false;
};
// Found, // Found,
if (bp->GetOnce()) { if (bp->GetOnce()) {
// delete it, if it should only be used once // delete it, if it should only be used once
(BPoints.erase)(i); (BPoints.erase)(i);
bp->Activate(false); bp->Activate(false);
delete bp; delete bp;
} } else {
ignoreOnce = bp;
};
return true; 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; return false;
}; };
@ -239,11 +272,6 @@ bool CBreakpoint::CheckBreakpoint(PhysPt adr)
bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue) bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue)
// Checks if interrupt breakpoint is valid an should stop execution // 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 // Search matching breakpoint
std::list<CBreakpoint*>::iterator i; std::list<CBreakpoint*>::iterator i;
CBreakpoint* bp; CBreakpoint* bp;
@ -251,13 +279,21 @@ bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue)
bp = static_cast<CBreakpoint*>(*i); bp = static_cast<CBreakpoint*>(*i);
if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) { if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) {
if ((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) { if ((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) {
// Ignoie it once ?
if (ignoreOnce==bp) {
ignoreOnce=0;
bp->Activate(true);
return false;
};
// Found // Found
if (bp->GetOnce()) { if (bp->GetOnce()) {
// delete it, if it should only be used once // delete it, if it should only be used once
(BPoints.erase)(i); (BPoints.erase)(i);
bp->Activate(false); bp->Activate(false);
delete bp; delete bp;
} } else {
ignoreOnce = bp;
}
return true; return true;
} }
}; };
@ -292,6 +328,7 @@ bool CBreakpoint::DeleteByIndex(Bit16u index)
delete bp; delete bp;
return true; return true;
} }
nr++;
}; };
return false; return false;
}; };
@ -353,14 +390,15 @@ void CBreakpoint::ShowList(void)
for(i=BPoints.begin(); i != BPoints.end(); i++) { for(i=BPoints.begin(); i != BPoints.end(); i++) {
CBreakpoint* bp = static_cast<CBreakpoint*>(*i); CBreakpoint* bp = static_cast<CBreakpoint*>(*i);
if (bp->GetType()==BKPNT_PHYSICAL) { 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++; nr++;
} else if (bp->GetType()==BKPNT_INTERRUPT) { } else if (bp->GetType()==BKPNT_INTERRUPT) {
if (bp->GetValue()==BPINT_ALL) wprintw(dbg.win_out,"%02X. BPINT %02X\n",nr,bp->GetIntNr()); 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()); else wprintw(dbg.win_out,"%02X. BPINT %02X AH=%02X\n",nr,bp->GetIntNr(),bp->GetValue());
nr++; 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); wrefresh(dbg.win_out);
@ -591,6 +629,47 @@ Bit32u GetHexValue(char* str, char*& hex)
return value; 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) bool ParseCommand(char* str)
{ {
char* found = str; char* found = str;
@ -604,6 +683,17 @@ bool ParseCommand(char* str)
LOG_DEBUG("DEBUG: Set breakpoint at %04X:%04X",seg,ofs); LOG_DEBUG("DEBUG: Set breakpoint at %04X:%04X",seg,ofs);
return true; 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"); found = strstr(str,"BPINT");
if (found) { // Add Interrupt Breakpoint if (found) { // Add Interrupt Breakpoint
found+=5; found+=5;
@ -666,6 +756,30 @@ bool ParseCommand(char* str)
LOG_DEBUG("DEBUG: Logfile LOGCPU.TXT created."); LOG_DEBUG("DEBUG: Logfile LOGCPU.TXT created.");
return true; 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 "); found = strstr(str,"INTT ");
if (found) { // Create Cpu log file if (found) { // Create Cpu log file
found+=4; found+=4;
@ -688,6 +802,15 @@ bool ParseCommand(char* str)
Interrupt(intNr); Interrupt(intNr);
return true; 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=='?')) { if ((*str=='H') || (*str=='?')) {
wprintw(dbg.win_out,"Debugger keys:\n"); wprintw(dbg.win_out,"Debugger keys:\n");
wprintw(dbg.win_out,"--------------------------------------------------------------------------\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,"BP [segment]:[offset] - Set breakpoint\n");
wprintw(dbg.win_out,"BPINT [intNr] * - Set interrupt 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"); 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,"BPLIST - List breakpoints\n");
wprintw(dbg.win_out,"BPDEL [bpNr] / * - Delete breakpoint nr / all\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,"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,"INT [nr] / INTT [nr] - Execute / Trace into Iinterrupt\n");
wprintw(dbg.win_out,"LOG [num] - Write cpu log file\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"); wprintw(dbg.win_out,"H - Help\n");
wrefresh(dbg.win_out); wrefresh(dbg.win_out);
return TRUE; return TRUE;
@ -744,22 +875,28 @@ Bit32u DEBUG_CheckKeys(void) {
if (key>0) { if (key>0) {
switch (toupper(key)) { switch (toupper(key)) {
case '1': case '1':
ret=(*cpudecoder)(100); CPU_Cycles = 100;
ret=(*cpudecoder)();
break; break;
case '2': case '2':
ret=(*cpudecoder)(500); CPU_Cycles = 500;
ret=(*cpudecoder)();
break; break;
case '3': case '3':
ret=(*cpudecoder)(1000); CPU_Cycles = 1000;
ret=(*cpudecoder)();
break; break;
case '4': case '4':
ret=(*cpudecoder)(5000); CPU_Cycles = 5000;
ret=(*cpudecoder)();
break; break;
case '5': case '5':
ret=(*cpudecoder)(10000); CPU_Cycles = 10000;
ret=(*cpudecoder)();
break; break;
case 'q': case 'q':
ret=(*cpudecoder)(5); CPU_Cycles = 5;
ret=(*cpudecoder)();
break; break;
case 'D': dataSeg = SegValue(ds); case 'D': dataSeg = SegValue(ds);
dataOfs = reg_si; dataOfs = reg_si;
@ -813,14 +950,18 @@ Bit32u DEBUG_CheckKeys(void) {
if (StepOver()) return 0; if (StepOver()) return 0;
else { else {
skipFirstInstruction = true; // for heavy debugger skipFirstInstruction = true; // for heavy debugger
Bitu ret=(*cpudecoder)(1); CPU_Cycles = 1;
Bitu ret=(*cpudecoder)();
SetCodeWinStart(); SetCodeWinStart();
CBreakpoint::ignoreOnce = 0;
} }
break; break;
case KEY_F(11): // trace into case KEY_F(11): // trace into
skipFirstInstruction = true; // for heavy debugger skipFirstInstruction = true; // for heavy debugger
ret = (*cpudecoder)(1); CPU_Cycles = 1;
ret = (*cpudecoder)();
SetCodeWinStart(); SetCodeWinStart();
CBreakpoint::ignoreOnce = 0;
break; break;
// default: // default:
@ -868,10 +1009,20 @@ static void DEBUG_RaiseTimerIrq(void) {
PIC_ActivateIRQ(0); 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) { static bool DEBUG_Log_Loop(int count) {
char buffer[512]; char buffer[512];
getcwd(buffer,512);
FILE* f = fopen("LOGCPU.TXT","wt"); FILE* f = fopen("LOGCPU.TXT","wt");
if (!f) return false; if (!f) return false;
@ -884,23 +1035,17 @@ static bool DEBUG_Log_Loop(int count) {
// Get disasm // Get disasm
Bit16u csValue = SegValue(cs); Bit16u csValue = SegValue(cs);
Bit32u eipValue = reg_eip; 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; LogInstruction(csValue,eipValue,buffer);
ret=(*cpudecoder)(1);
// Get register values
char buffer[512];
sprintf(buffer,"%04X:%08X %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X\n",csValue,eipValue,dline,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(ds),SegValue(es),SegValue(fs),SegValue(gs),SegValue(ss),get_CF(),get_ZF(),get_SF(),get_OF(),get_AF(),get_PF());
fprintf(f,"%s",buffer); fprintf(f,"%s",buffer);
CPU_Cycles = 1;
ret=(*cpudecoder)();
count--; count--;
if (count==0) break; if (count==0) break;
} while (!ret && PIC_IRQAgain); } while (!ret);
if (ret) break; if (ret) break;
} while (count>0); } while (count>0);
@ -920,15 +1065,42 @@ public:
void Run(void) void Run(void)
{ {
char filename[128]; char filename[128];
char args[128]; char args[256];
cmd->FindCommand(1,temp_line); cmd->FindCommand(1,temp_line);
strncpy(filename,temp_line.c_str(),128); strncpy(filename,temp_line.c_str(),128);
cmd->FindCommand(2,temp_line); // Read commandline
strncpy(args,temp_line.c_str(),128); 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 // Start new shell and execute prog
active = true; active = true;
DOS_Shell shell; // Save cpu state....
shell.Execute(filename,args); 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: private:
@ -954,6 +1126,9 @@ void DEBUG_SetupConsole(void)
{ {
#ifdef WIN32 #ifdef WIN32
WIN32_Console(); WIN32_Console();
#else
printf("\e[8;50;80t"); //resize terminal
fflush(NULL);
#endif #endif
memset((void *)&dbg,0,sizeof(dbg)); memset((void *)&dbg,0,sizeof(dbg));
debugging=false; debugging=false;
@ -987,8 +1162,53 @@ void DEBUG_Init(Section* sec) {
#if C_HEAVY_DEBUG #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) bool DEBUG_HeavyIsBreakpoint(void)
{ {
// LogInstruction
if (logHeavy) DEBUG_HeavyLogInstruction();
if (skipFirstInstruction) { if (skipFirstInstruction) {
skipFirstInstruction = false; skipFirstInstruction = false;
return false; return false;

View File

@ -344,7 +344,7 @@ static char *groups[][8] = { /* group 0 is group 3 for %Ev set */
{ "rol", "ror", "rcl", "rcr", { "rol", "ror", "rcl", "rcr",
"shl", "shr", "shl", "sar" }, "shl", "shr", "shl", "sar" },
/* 2 */ /* v v*/ /* 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" }, "mul %Ec", "imul %Ec", "div %Ec", "idiv %Ec" },
/* 3 */ /* 3 */
{ "inc %Eb", "dec %Eb", 0, 0, { "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 getbyte_mac;
static PhysPt startPtr;
static UINT8 getbyte(void) { static UINT8 getbyte(void) {
return mem_readb(getbyte_mac++); return mem_readb(getbyte_mac++);
@ -662,7 +662,7 @@ static void reg_name(int regnum, char size)
uprintf("st(%d)", regnum); uprintf("st(%d)", regnum);
return; return;
} }
if (((size == 'v') && (opsize == 32)) || (size == 'd')) if ((((size == 'c') || (size == 'v')) && (opsize == 32)) || (size == 'd'))
uputchar('e'); uputchar('e');
if ((size=='q' || size == 'b' || size=='c') && !wordop) { if ((size=='q' || size == 'b' || size=='c') && !wordop) {
uputchar("acdbacdb"[regnum]); uputchar("acdbacdb"[regnum]);
@ -822,6 +822,8 @@ static void floating_point(int e1)
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Main table driver */ /* Main table driver */
#define INSTRUCTION_SIZE (int)getbyte_mac - (int)startPtr
static void percent(char type, char subtype) static void percent(char type, char subtype)
{ {
INT32 vofs = 0; INT32 vofs = 0;
@ -864,13 +866,13 @@ static void percent(char type, char subtype)
switch (bytes(subtype)) { /* sizeof offset value */ switch (bytes(subtype)) { /* sizeof offset value */
case 1: case 1:
vofs = (INT8)getbyte(); vofs = (INT8)getbyte();
name = addr_to_hex(vofs+instruction_offset,0); name = addr_to_hex(vofs+instruction_offset+INSTRUCTION_SIZE,0);
break; break;
case 2: case 2:
vofs = getbyte(); vofs = getbyte();
vofs += getbyte()<<8; vofs += getbyte()<<8;
vofs = (INT16)vofs; vofs = (INT16)vofs;
name = addr_to_hex(vofs+instruction_offset,0); name = addr_to_hex(vofs+instruction_offset+INSTRUCTION_SIZE,0);
break; break;
#if 0 #if 0
/* i386 */ /* i386 */
@ -879,7 +881,7 @@ static void percent(char type, char subtype)
vofs |= (UINT32)getbyte() << 8; vofs |= (UINT32)getbyte() << 8;
vofs |= (UINT32)getbyte() << 16; vofs |= (UINT32)getbyte() << 16;
vofs |= (UINT32)getbyte() << 24; vofs |= (UINT32)getbyte() << 24;
name = addr_to_hex(vofs+instruction_offset,1); name = addr_to_hex(vofs+instruction_offset+INSTRUCTION_SIZE,1);
break; break;
#endif #endif
} }
@ -1077,6 +1079,7 @@ Bitu DasmI386(char* buffer, PhysPt pc, Bitu cur_ip, bool bit32)
instruction_offset = cur_ip; instruction_offset = cur_ip;
/* input buffer */ /* input buffer */
startPtr = pc;
getbyte_mac = pc; getbyte_mac = pc;
/* output buffer */ /* output buffer */

View File

@ -122,6 +122,10 @@ void DBGUI_StartUp(void) {
noecho(); /* don't echo input */ noecho(); /* don't echo input */
nodelay(dbg.win_main,true); nodelay(dbg.win_main,true);
keypad(dbg.win_main,true); keypad(dbg.win_main,true);
#ifndef WIN32
resizeterm(50,80);
touchwin(dbg.win_main);
#endif
cycle_count=0; cycle_count=0;
MakePairs(); MakePairs();
MakeSubWindows(); MakeSubWindows();

View File

@ -16,6 +16,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 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 { class device_CON : public DOS_Device {
public: public:
device_CON(); device_CON();
@ -23,17 +28,36 @@ public:
bool Write(Bit8u * data,Bit16u * size); bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type); bool Seek(Bit32u * pos,Bit32u type);
bool Close(); bool Close();
void ClearAnsi(void);
Bit16u GetInformation(void); Bit16u GetInformation(void);
private: private:
Bit8u cache; 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) { bool device_CON::Read(Bit8u * data,Bit16u * size) {
Bit16u oldax=reg_ax; Bit16u oldax=reg_ax;
Bit16u count=0; Bit16u count=0;
if ((cache) && (*size)) { if ((cache) && (*size)) {
data[count++]=cache; data[count++]=cache;
cache=0; if(dos.echo) {
INT10_TeletypeOutput(cache,7,false,0);
}
cache=0;
} }
while (*size>count) { while (*size>count) {
reg_ah=0; reg_ah=0;
@ -41,11 +65,26 @@ bool device_CON::Read(Bit8u * data,Bit16u * size) {
switch(reg_al) { switch(reg_al) {
case 13: case 13:
data[count++]=0x0D; data[count++]=0x0D;
// if (*size>count) data[count++]=0x0A; if (*size>count) data[count++]=0x0A; // it's only expanded if there is room for it. (NO cache)
// else cache=0x0A; *size=count;
*size=count;
reg_ax=oldax; 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; 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: default:
data[count++]=reg_al; data[count++]=reg_al;
break; break;
@ -54,27 +93,247 @@ bool device_CON::Read(Bit8u * data,Bit16u * size) {
if (*size>count) data[count++]=reg_ah; if (*size>count) data[count++]=reg_ah;
else cache=reg_ah; else cache=reg_ah;
break; break;
}
}
if(dos.echo) { //what to do if *size==1 and character is BS ?????
INT10_TeletypeOutput(reg_al,7,false,0);
}
} }
*size=count; *size=count;
reg_ax=oldax; reg_ax=oldax;
return true; return true;
} }
extern void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page);
bool device_CON::Write(Bit8u * data,Bit16u * size) { bool device_CON::Write(Bit8u * data,Bit16u * size) {
Bit16u count=0; Bit16u count=0;
while (*size>count) { Bitu i;
Bit8s col,row;
static bool ansiwarned=false;
INT10_TeletypeOutput(data[count],7,false,0); while (*size>count) {
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; *size=count;
return true; return true;
} }
bool device_CON::Seek(Bit32u * pos,Bit32u type) { bool device_CON::Seek(Bit32u * pos,Bit32u type) {
return false; // seek is valid
*pos = 0;
return true;
} }
bool device_CON::Close() { bool device_CON::Close() {
@ -89,9 +348,23 @@ Bit16u device_CON::GetInformation(void) {
return 0x8093; /* Key Available */ return 0x8093; /* Key Available */
}; };
device_CON::device_CON() { device_CON::device_CON() {
name="CON"; name="CON";
cache=0; cache=0;
ansi.esc=false;
ansi.sci=false;
ansi.attr=0x7;
ansi.numberofarg=0;
for(Bit8u i=0; i<NUMBER_ANSI_DATA;i++) ansi.data[i]=0;
ansi.ncols=real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); //should be updated once set/reset mode is implemented
ansi.nrows=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS);
ansi.saverow=0;
ansi.savecol=0;
} }
void device_CON::ClearAnsi(void){
for(Bit8u i=0; i<NUMBER_ANSI_DATA;i++) ansi.data[i]=0;
ansi.esc=false;
ansi.sci=false;
ansi.numberofarg=0;
}

View File

@ -32,7 +32,7 @@ DOS_Block dos;
DOS_InfoBlock dos_infoblock; DOS_InfoBlock dos_infoblock;
Bit8u dos_copybuf[0x10000]; Bit8u dos_copybuf[0x10000];
static Bitu call_20,call_21; static Bitu call_20,call_21,call_27,call_28,call_29;
void DOS_SetError(Bit16u code) { void DOS_SetError(Bit16u code) {
dos.errorcode=code; dos.errorcode=code;
@ -43,15 +43,14 @@ static Bitu DOS_21Handler(void) {
char name1[DOSNAMEBUF+1]; char name1[DOSNAMEBUF+1];
char name2[DOSNAMEBUF+1]; char name2[DOSNAMEBUF+1];
switch (reg_ah) { switch (reg_ah) {
case 0x00: /* Terminate Program */
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
case 0x01: /* Read character from STDIN, with echo */ case 0x01: /* Read character from STDIN, with echo */
{ {
Bit8u c;Bit16u n=1; Bit8u c;Bit16u n=1;
dos.echo=true;
DOS_ReadFile(STDIN,&c,&n); DOS_ReadFile(STDIN,&c,&n);
reg_al=c; reg_al=c;
DOS_WriteFile(STDOUT,&c,&n); dos.echo=false;
} }
break; break;
case 0x02: /* Write character to STDOUT */ case 0x02: /* Write character to STDOUT */
@ -71,6 +70,7 @@ static Bitu DOS_21Handler(void) {
{ {
//TODO Make this better according to standards //TODO Make this better according to standards
if (!DOS_GetSTDINStatus()) { if (!DOS_GetSTDINStatus()) {
reg_al=0;
CALLBACK_SZF(true); CALLBACK_SZF(true);
break; break;
} }
@ -95,7 +95,7 @@ static Bitu DOS_21Handler(void) {
reg_al=c; reg_al=c;
break; break;
}; };
case 0x08: /* Direct Character Input, without echo */ case 0x08: /* Direct Character Input, without echo (checks for breaks officially :)*/
{ {
Bit8u c;Bit16u n=1; Bit8u c;Bit16u n=1;
DOS_ReadFile (STDIN,&c,&n); DOS_ReadFile (STDIN,&c,&n);
@ -161,10 +161,10 @@ static Bitu DOS_21Handler(void) {
break; break;
case 0x0e: /* Select Default Drive */ case 0x0e: /* Select Default Drive */
DOS_SetDefaultDrive(reg_dl); DOS_SetDefaultDrive(reg_dl);
reg_al=26; reg_al=DOS_DRIVES;
break; break;
case 0x0f: /* Open File using FCB */ case 0x0f: /* Open File using FCB */
if(DOS_FCBOpenCreate(SegValue(ds),reg_dx)){ if(DOS_FCBOpen(SegValue(ds),reg_dx)){
reg_al=0; reg_al=0;
}else{ }else{
reg_al=0xff; reg_al=0xff;
@ -204,13 +204,12 @@ static Bitu DOS_21Handler(void) {
LOG_DEBUG("DOS:0x14 FCB-Read used, result:al=%d",reg_al); LOG_DEBUG("DOS:0x14 FCB-Read used, result:al=%d",reg_al);
break; break;
case 0x15: /* Sequential write to FCB */ case 0x15: /* Sequential write to FCB */
if (DOS_FCBWrite(SegValue(ds),reg_dx,0)) reg_al = 0x00; reg_al=DOS_FCBWrite(SegValue(ds),reg_dx,0);
else reg_al = 0x01;
LOG_DEBUG("DOS:0x15 FCB-Write used, result:al=%d",reg_al); LOG_DEBUG("DOS:0x15 FCB-Write used, result:al=%d",reg_al);
break; break;
case 0x16: /* Create or truncate file using FCB */ case 0x16: /* Create or truncate file using FCB */
if (DOS_FCBOpenCreate(SegValue(ds),reg_dx)) reg_al = 0x00; if (DOS_FCBCreate(SegValue(ds),reg_dx)) reg_al = 0x00;
else reg_al = 0x01; else reg_al = 0xFF;
LOG_DEBUG("DOS:0x16 FCB-Create used, result:al=%d",reg_al); LOG_DEBUG("DOS:0x16 FCB-Create used, result:al=%d",reg_al);
break; break;
case 0x17: /* Rename file using FCB */ case 0x17: /* Rename file using FCB */
@ -218,18 +217,17 @@ static Bitu DOS_21Handler(void) {
else reg_al = 0xFF; else reg_al = 0xFF;
break; break;
case 0x1b: /* Get allocation info for default drive */ case 0x1b: /* Get allocation info for default drive */
if (!DOS_GetAllocationInfo(0,&reg_cx,&reg_ax,&reg_dx)) reg_al=0xff; if (!DOS_GetAllocationInfo(0,&reg_cx,&reg_al,&reg_dx)) reg_al=0xff;
break; break;
case 0x1c: /* Get allocation info for specific drive */ case 0x1c: /* Get allocation info for specific drive */
if (!DOS_GetAllocationInfo(reg_dl,&reg_cx,&reg_ax,&reg_dx)) reg_al=0xff; if (!DOS_GetAllocationInfo(reg_dl,&reg_cx,&reg_al,&reg_dx)) reg_al=0xff;
break; break;
case 0x21: /* Read random record from FCB */ case 0x21: /* Read random record from FCB */
reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,1,true); reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,1,true);
LOG_DEBUG("DOS:0x21 FCB-Random read used, result:al=%d",reg_al); LOG_DEBUG("DOS:0x21 FCB-Random read used, result:al=%d",reg_al);
break; break;
case 0x22: /* Write random record to FCB */ case 0x22: /* Write random record to FCB */
if (DOS_FCBRandomWrite(SegValue(ds),reg_dx,1,true)) reg_al = 0x00; reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,1,true);
else reg_al = 0x01;
LOG_DEBUG("DOS:0x28 FCB-Random write used, result:al=%d",reg_al); LOG_DEBUG("DOS:0x28 FCB-Random write used, result:al=%d",reg_al);
break; break;
case 0x23: /* Get file size for FCB */ case 0x23: /* Get file size for FCB */
@ -241,30 +239,21 @@ static Bitu DOS_21Handler(void) {
break; break;
case 0x27: /* Random block read from FCB */ case 0x27: /* Random block read from FCB */
reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,reg_cx,false); reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,reg_cx,false);
LOG_DEBUG("DOS:0x27 FCB-Random read used, result:al=%d",reg_al); LOG_DEBUG("DOS:0x27 FCB-Random(block) read used, result:al=%d",reg_al);
break; break;
case 0x28: /* Random Block write to FCB */ case 0x28: /* Random Block write to FCB */
if (DOS_FCBRandomWrite(SegValue(ds),reg_dx,reg_cx,false)) reg_al = 0x00; reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,reg_cx,false);
else reg_al = 0x01; LOG_DEBUG("DOS:0x28 FCB-Random(block) write used, result:al=%d",reg_al);
LOG_DEBUG("DOS:0x28 FCB-Random write used, result:al=%d",reg_al);
break; break;
case 0x29: /* Parse filename into FCB */ case 0x29: /* Parse filename into FCB */
{ Bit8u difference; { Bit8u difference;
char string[1024]; char string[1024];
MEM_StrCopy(SegPhys(ds)+reg_si,string,1024); MEM_StrCopy(SegPhys(ds)+reg_si,string,1024);
reg_al=FCB_Parsename(SegValue(es),reg_di,reg_al ,string, &difference); reg_al=FCB_Parsename(SegValue(es),reg_di,reg_al ,string, &difference);
reg_di+=difference; reg_si+=difference;
} }
LOG_DEBUG("DOS:29:FCB Parse Filename, result:al=%d",reg_al); LOG_DEBUG("DOS:29:FCB Parse Filename, result:al=%d",reg_al);
break; break;
case 0x18: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x1d: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x1e: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x20: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x6b: /* NULL Function */
case 0x61: /* UNUSED */
reg_al=0;
break;
case 0x19: /* Get current default drive */ case 0x19: /* Get current default drive */
reg_al=DOS_GetDefaultDrive(); reg_al=DOS_GetDefaultDrive();
break; break;
@ -276,6 +265,7 @@ static Bitu DOS_21Handler(void) {
} }
break; break;
case 0x1f: /* Get drive parameter block for default drive */ case 0x1f: /* Get drive parameter block for default drive */
case 0x32: /* Get drive parameter block for specific drive */ case 0x32: /* Get drive parameter block for specific drive */
E_Exit("DOS:Unhandled call %02X",reg_ah); E_Exit("DOS:Unhandled call %02X",reg_ah);
break; /* TODO maybe but hardly think a game needs this */ break; /* TODO maybe but hardly think a game needs this */
@ -286,13 +276,17 @@ static Bitu DOS_21Handler(void) {
DOS_NewPSP(reg_dx,DOS_PSP(dos.psp).GetSize()); DOS_NewPSP(reg_dx,DOS_PSP(dos.psp).GetSize());
break; break;
case 0x2a: /* Get System Date */ case 0x2a: /* Get System Date */
reg_al=0; /* It's always sunday TODO find that correct formula */ {
reg_cx=dos.date.year; int a = (14 - dos.date.month)/12;
reg_dh=dos.date.month; int y = dos.date.year - a;
reg_dl=dos.date.day; int m = dos.date.month + 12*a - 2;
reg_al=(dos.date.day+y+(y/4)-(y/100)+(y/400)+(31*m)/12) % 7;
reg_cx=dos.date.year;
reg_dh=dos.date.month;
reg_dl=dos.date.day;
}
break; break;
case 0x2b: /* Set System Date */ case 0x2b: /* Set System Date */
//TODO Check for months with less then 31 days
if (reg_cx<1980) { reg_al=0xff;break;} if (reg_cx<1980) { reg_al=0xff;break;}
if ((reg_dh>12) || (reg_dh==0)) { reg_al=0xff;break;} if ((reg_dh>12) || (reg_dh==0)) { reg_al=0xff;break;}
if ((reg_dl>31) || (reg_dl==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 ticks=mem_readd(BIOS_TIMER);
Bit32u seconds=(ticks*10)/182; Bit32u seconds=(ticks*10)/182;
reg_ch=(Bit8u)(seconds/3600); reg_ch=(Bit8u)(seconds/3600);
reg_cl=(Bit8u)(seconds % 3600)/60; reg_cl=(Bit8u)((seconds % 3600)/60);
reg_dh=(Bit8u)(seconds % 60); reg_dh=(Bit8u)(seconds % 60);
reg_dl=(Bit8u)(ticks % 19)*5; reg_dl=(Bit8u)((ticks % 20)*5); /* 0-19 ->0-95 */
} }
break; break;
case 0x2d: /* Set System Time */ case 0x2d: /* Set System Time */
@ -367,7 +361,8 @@ static Bitu DOS_21Handler(void) {
break; break;
case 0x36: /* Get Free Disk Space */ case 0x36: /* Get Free Disk Space */
{ {
Bit16u bytes,sectors,clusters,free; Bit16u bytes,clusters,free;
Bit8u sectors;
if (DOS_GetFreeDiskSpace(reg_dl,&bytes,&sectors,&clusters,&free)) { if (DOS_GetFreeDiskSpace(reg_dl,&bytes,&sectors,&clusters,&free)) {
reg_ax=sectors; reg_ax=sectors;
reg_bx=free; reg_bx=free;
@ -459,7 +454,7 @@ static Bitu DOS_21Handler(void) {
case 0x3f: /* READ Read from file or device */ case 0x3f: /* READ Read from file or device */
{ {
Bit16u toread=reg_cx; 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)) { if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread); MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread);
reg_ax=toread; reg_ax=toread;
@ -468,12 +463,12 @@ static Bitu DOS_21Handler(void) {
reg_ax=dos.errorcode; reg_ax=dos.errorcode;
CALLBACK_SCF(true); CALLBACK_SCF(true);
} }
dos.echo=false;
break; break;
} }
case 0x40: /* WRITE Write to file or device */ case 0x40: /* WRITE Write to file or device */
{ {
Bit16u towrite=reg_cx; 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); MEM_BlockRead(SegPhys(ds)+reg_dx,dos_copybuf,towrite);
if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) { if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) {
reg_ax=towrite; reg_ax=towrite;
@ -604,8 +599,11 @@ static Bitu DOS_21Handler(void) {
} }
break; break;
//TODO Check for use of execution state AL=5 //TODO Check for use of execution state AL=5
case 0x00:
reg_ax=0x4c00; /* Terminate Program */
case 0x4c: /* EXIT Terminate with return code */ case 0x4c: /* EXIT Terminate with return code */
{
{
if (DOS_Terminate(false)) { if (DOS_Terminate(false)) {
/* This can't ever return false normally */ /* This can't ever return false normally */
} else { } else {
@ -652,9 +650,10 @@ static Bitu DOS_21Handler(void) {
//TODO Think hard how shit this is gonna be //TODO Think hard how shit this is gonna be
//And will any game ever use this :) //And will any game ever use this :)
case 0x53: /* Translate BIOS parameter block to drive parameter block */ 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 */ case 0x54: /* Get verify flag */
E_Exit("Unhandled Dos 21 call %02X",reg_ah); reg_al=dos.verify?1:0;
break; break;
case 0x55: /* Create Child PSP*/ case 0x55: /* Create Child PSP*/
DOS_NewPSP(reg_dx,reg_si); DOS_NewPSP(reg_dx,reg_si);
@ -686,9 +685,10 @@ static Bitu DOS_21Handler(void) {
case 0x58: /* Get/Set Memory allocation strategy */ case 0x58: /* Get/Set Memory allocation strategy */
switch (reg_al) { switch (reg_al) {
case 0: /* Get Strategy */ case 0: /* Get Strategy */
reg_ax=0; //Low memory first fit reg_ax=DOS_GetMemAllocStrategy();
break; break;
case 1: /* Set Strategy */ case 1: /* Set Strategy */
DOS_SetMemAllocStrategy(reg_bx);
break; break;
default: default:
LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al); LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al);
@ -733,8 +733,8 @@ static Bitu DOS_21Handler(void) {
} }
break; break;
} }
case 0x5c: /* FLOCK File region locking */ case 0x5c: /* FLOCK File region locking */
case 0x5d: /* Network Functions */
case 0x5e: /* More Network Functions */ case 0x5e: /* More Network Functions */
case 0x5f: /* And Even More Network Functions */ case 0x5f: /* And Even More Network Functions */
E_Exit("DOS:Unhandled call %02X",reg_ah); E_Exit("DOS:Unhandled call %02X",reg_ah);
@ -752,10 +752,6 @@ static Bitu DOS_21Handler(void) {
case 0x62: /* Get Current PSP Address */ case 0x62: /* Get Current PSP Address */
reg_bx=dos.psp; reg_bx=dos.psp;
break; 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 */ case 0x64: /* Set device driver lookahead flag */
E_Exit("Unhandled Dos 21 call %02X",reg_ah); E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break; break;
@ -792,9 +788,6 @@ static Bitu DOS_21Handler(void) {
LOG_DEBUG("DOS:67:Set Handle Count not working"); LOG_DEBUG("DOS:67:Set Handle Count not working");
CALLBACK_SCF(false); CALLBACK_SCF(false);
break; break;
case 0x68: /* FFLUSH Commit file */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x69: /* Get/Set disk serial number */ case 0x69: /* Get/Set disk serial number */
{ {
switch(reg_al) { switch(reg_al) {
@ -817,11 +810,21 @@ static Bitu DOS_21Handler(void) {
CALLBACK_SCF(true); CALLBACK_SCF(true);
LOG_WARN("DOS:Windows long file name support call %2X",reg_al); LOG_WARN("DOS:Windows long file name support call %2X",reg_al);
break; break;
case 0xE0: case 0x68: /* FFLUSH Commit file */
LOG_DEBUG("DOS:E0:Unhandled, what should this call do?"); case 0x63: /* Weirdo double byte stuff (fails but say it succeeded) available only in MSDOS 2.25 */
break; 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: 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; break;
}; };
return CBRET_NONE; return CBRET_NONE;
@ -837,6 +840,22 @@ static Bitu DOS_20Handler(void) {
return CBRET_NONE; 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,&para)) 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) { void DOS_Init(Section* sec) {
MSG_Add("DOS_CONFIGFILE_HELP","Setting a memory size to 0 will disable it.\n"); 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)); RealSetVec(0x20,CALLBACK_RealPointer(call_20));
call_21=CALLBACK_Allocate(); 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)); 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_SetupFiles(); /* Setup system File tables */
DOS_SetupDevices(); /* Setup dos devices */ DOS_SetupDevices(); /* Setup dos devices */
DOS_SetupTables(); DOS_SetupTables();
@ -855,8 +886,16 @@ void DOS_Init(Section* sec) {
DOS_SetupPrograms(); DOS_SetupPrograms();
DOS_SetupMisc(); /* Some additional dos interrupts */ DOS_SetupMisc(); /* Some additional dos interrupts */
DOS_SetDefaultDrive(25); DOS_SetDefaultDrive(25);
/* Execute the file that should be */
dos.version.major=5; dos.version.major=5;
dos.version.minor=0; 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);
}

View File

@ -318,7 +318,7 @@ void DOS_FCB::SetRandom(Bit32u _random) {
} }
void DOS_FCB::FileOpen(Bit8u _fhandle) { void DOS_FCB::FileOpen(Bit8u _fhandle) {
sSave(sFCB,drive,GetDrive()); sSave(sFCB,drive,GetDrive()+1);
sSave(sFCB,file_handle,_fhandle); sSave(sFCB,file_handle,_fhandle);
sSave(sFCB,cur_block,0); sSave(sFCB,cur_block,0);
sSave(sFCB,rec_size,128); sSave(sFCB,rec_size,128);

View File

@ -208,7 +208,7 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
Bitu headersize,imagesize; Bitu headersize,imagesize;
DOS_ParamBlock block(block_pt); DOS_ParamBlock block(block_pt);
block.LoadData(); 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); E_Exit("DOS:Not supported execute mode %d for file %s",flags,name);
} }
/* Check for EXE or COM File */ /* 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); pos=headersize;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
while (imagesize>0x7FFF) { while (imagesize>0x7FFF) {
readsize=0x8000;DOS_ReadFile(fhandle,loadaddress,&readsize); 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; loadaddress+=0x8000;imagesize-=0x8000;
} }
if (imagesize>0) { if (imagesize>0) {
readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadaddress,&readsize); 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 */ /* Relocate the exe image */
Bit16u relocate; Bit16u relocate;
@ -302,6 +302,20 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
csip=RealMake(loadseg+head.initCS,head.initIP); csip=RealMake(loadseg+head.initCS,head.initIP);
sssp=RealMake(loadseg+head.initSS,head.initSP); 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) { if (flags==LOADNGO) {
/* Get Caller's program CS:IP of the stack and set termination address to that */ /* 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))); RealSetVec(0x22,RealMake(mem_readw(SegPhys(ss)+reg_sp+2),mem_readw(SegPhys(ss)+reg_sp)));

View File

@ -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 '!': case '%': case '{': case '}': case '`': case '~':
case '_': case '-': case '.': case '*': case '?': case '&': case '_': case '-': case '.': case '*': case '?': case '&':
case '\'':
upname[w++]=c; upname[w++]=c;
break; break;
default: default:
@ -150,8 +151,10 @@ bool DOS_GetCurrentDir(Bit8u drive,char * buffer) {
} }
bool DOS_ChangeDir(char * dir) { bool DOS_ChangeDir(char * dir) {
Bit8u drive;char fulldir[DOS_PATHLENGTH]; Bit8u drive;char fulldir[DOS_PATHLENGTH];
if (!DOS_MakeName(dir,fulldir,&drive)) return false; if (!DOS_MakeName(dir,fulldir,&drive)) return false;
if (Drives[drive]->TestDir(fulldir)) { if (Drives[drive]->TestDir(fulldir)) {
strcpy(Drives[drive]->curdir,fulldir); strcpy(Drives[drive]->curdir,fulldir);
return true; return true;
@ -202,14 +205,14 @@ bool DOS_FindFirst(char * search,Bit16u attr) {
} }
dta.SetupSearch(drive,(Bit8u)attr,pattern); dta.SetupSearch(drive,(Bit8u)attr,pattern);
if (Drives[drive]->FindFirst(dir,dta)) return true; if (Drives[drive]->FindFirst(dir,dta)) return true;
DOS_SetError(DOSERR_FILE_NOT_FOUND); DOS_SetError(DOSERR_NO_MORE_FILES);
return false; return false;
} }
bool DOS_FindNext(void) { bool DOS_FindNext(void) {
DOS_DTA dta(dos.dta); DOS_DTA dta(dos.dta);
if (Drives[dta.GetSearchDrive()]->FindNext(dta)) return true; if (Drives[dta.GetSearchDrive()]->FindNext(dta)) return true;
DOS_SetError(DOSERR_FILE_NOT_FOUND); DOS_SetError(DOSERR_NO_MORE_FILES);
return false; return false;
} }
@ -397,7 +400,7 @@ bool DOS_Canonicalize(char * name,char * big) {
return true; 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(); if (drive==0) drive=DOS_GetDefaultDrive();
else drive--; else drive--;
if ((drive>DOS_DRIVES) || (!Drives[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){ static bool FCB_MakeName2 (DOS_FCB & fcb, char* outname, Bit8u* outdrive){
char short_name[DOS_FCBNAME]; char short_name[DOS_FCBNAME];
@ -626,7 +628,16 @@ static void SaveFindResult(DOS_FCB & find_fcb) {
fcb.SetSizeDateTime(size,date,time); 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); DOS_FCB fcb(seg,offset);
char shortname[DOS_FCBNAME];Bit16u handle; char shortname[DOS_FCBNAME];Bit16u handle;
fcb.GetName(shortname); fcb.GetName(shortname);
@ -687,7 +698,7 @@ Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset,Bit16u recno) {
return FCB_READ_PARTIAL; 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); DOS_FCB fcb(seg,offset);
Bit8u fhandle,cur_rec;Bit16u cur_block,rec_size; 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) { 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); DOS_FCB fcb(seg,offset);
Bit32u random;Bit16u old_block;Bit8u old_rec;Bit8u error; Bit32u random;Bit16u old_block;Bit8u old_rec;Bit8u error;
/* Set the correct record from the random data */ /* Set the correct record from the random data */
fcb.GetRandom(random); fcb.GetRandom(random);
if (restore) fcb.GetRecord(old_block,old_rec);
fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127)); fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127));
if (restore) fcb.GetRecord(old_block,old_rec);//store this for after the read.
// Read records // Read records
for (int i=0; i<numRec; i++) { for (int i=0; i<numRec; i++) {
error = DOS_FCBRead(seg,offset,i); error = DOS_FCBRead(seg,offset,i);
@ -724,30 +741,31 @@ Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) {
Bit16u new_block;Bit8u new_rec; Bit16u new_block;Bit8u new_rec;
fcb.GetRecord(new_block,new_rec); fcb.GetRecord(new_block,new_rec);
if (restore) fcb.SetRecord(old_block,old_rec); if (restore) fcb.SetRecord(old_block,old_rec);
/* Update the random record pointer with new position */ /* Update the random record pointer with new position only when restore is false*/
fcb.SetRandom(new_block*128+new_rec); if(!restore) fcb.SetRandom(new_block*128+new_rec);
return error; return error;
} }
bool DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) { Bit8u DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) {
/* see FCB_RandomRead */
DOS_FCB fcb(seg,offset); DOS_FCB fcb(seg,offset);
Bit32u random;Bit16u old_block;Bit8u old_rec;bool noerror; Bit32u random;Bit16u old_block;Bit8u old_rec;Bit8u error;
/* Set the correct record from the random data */ /* Set the correct record from the random data */
fcb.GetRandom(random); fcb.GetRandom(random);
if (restore) fcb.GetRecord(old_block,old_rec);
fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127)); fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127));
if (restore) fcb.GetRecord(old_block,old_rec);
/* Write records */ /* Write records */
for (int i=0; i<numRec; i++) { for (int i=0; i<numRec; i++) {
noerror = DOS_FCBWrite(seg,offset,i); error = DOS_FCBWrite(seg,offset,i);// dos_fcbwrite return 0 false when true...
if (!noerror) break; if (error!=0x00) break;
} }
Bit16u new_block;Bit8u new_rec; Bit16u new_block;Bit8u new_rec;
fcb.GetRecord(new_block,new_rec); fcb.GetRecord(new_block,new_rec);
if (restore) fcb.SetRecord(old_block,old_rec); if (restore) fcb.SetRecord(old_block,old_rec);
/* Update the random record pointer with new position */ /* Update the random record pointer with new position only when restore is false */
fcb.SetRandom(new_block*128+new_rec); if(!restore) fcb.SetRandom(new_block*128+new_rec);
return noerror; return error;
} }
bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset,Bit16u numRec) { bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset,Bit16u numRec) {
@ -787,7 +805,6 @@ void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset) {
fcb.SetRandom(block*128+rec); fcb.SetRandom(block*128+rec);
} }
#endif
bool DOS_FileExists(char * name) { bool DOS_FileExists(char * name) {
char fullname[DOS_PATHLENGTH];Bit8u drive; char fullname[DOS_PATHLENGTH];Bit8u drive;
@ -795,7 +812,7 @@ bool DOS_FileExists(char * name) {
return Drives[drive]->FileExists(fullname); return Drives[drive]->FileExists(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; if (!drive) drive=dos.current_drive;
else drive--; else drive--;
if (!Drives[drive]) return false; if (!Drives[drive]) return false;

View File

@ -86,6 +86,13 @@ bool DOS_IOCTL(void) {
return false; return false;
} }
break; 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: default:
LOG_ERROR("DOS:IOCTL Call %2X unhandled",reg_al); LOG_ERROR("DOS:IOCTL Call %2X unhandled",reg_al);
return false; return false;
@ -96,7 +103,8 @@ bool DOS_IOCTL(void) {
bool DOS_GetSTDINStatus(void) { bool DOS_GetSTDINStatus(void) {
Bit32u handle=RealHandle(STDIN); 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; return true;
}; };

View File

@ -24,6 +24,7 @@
#define MEM_START 0x60 //First Segment that DOS can use #define MEM_START 0x60 //First Segment that DOS can use
//#define MEM_START 4000 //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) { static void DOS_CompressMemory(void) {
MCB * pmcb;MCB * pmcbnext; MCB * pmcb;MCB * pmcbnext;
@ -57,6 +58,15 @@ void DOS_FreeProcessMemory(Bit16u pspseg) {
DOS_CompressMemory(); DOS_CompressMemory();
}; };
Bit16u DOS_GetMemAllocStrategy()
{
return memAllocStrategy;
};
void DOS_SetMemAllocStrategy(Bit16u strat)
{
memAllocStrategy = strat;
};
bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) {
MCB * pmcb;MCB * pmcbnext; MCB * pmcb;MCB * pmcbnext;
@ -77,17 +87,33 @@ bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) {
*segment=mcb_segment+1; *segment=mcb_segment+1;
return true; return true;
} else { } else {
// TODO: Strategy "1": Best matching block
/* If so allocate it */ /* If so allocate it */
pmcbnext=(MCB *)HostMake(mcb_segment+*blocks+1,0); if ((memAllocStrategy & 0x03)==0) {
pmcbnext->psp_segment=MCB_FREE; pmcbnext=(MCB *)HostMake(mcb_segment+*blocks+1,0);
pmcbnext->type=pmcb->type; pmcbnext->psp_segment=MCB_FREE;
pmcbnext->size=pmcb->size-*blocks-1; pmcbnext->type=pmcb->type;
pmcb->size=*blocks; pmcbnext->size=pmcb->size-*blocks-1;
pmcb->type=0x4D; pmcb->size=*blocks;
pmcb->psp_segment=dos.psp; pmcb->type=0x4D;
//TODO Filename pmcb->psp_segment=dos.psp;
*segment=mcb_segment+1; //TODO Filename
return true; *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 */ /* Onward to the next MCB if there is one */

View File

@ -60,11 +60,13 @@ static bool DOS_MultiplexFunctions(void) {
//TODO Maybe do some idling but could screw up other systems :) //TODO Maybe do some idling but could screw up other systems :)
reg_al=0; reg_al=0;
return true; return true;
case 0x168f: /* Close awareness crap */
return true;
} }
return false; return false;
} }
void DOS_SetupMisc(void) { void DOS_SetupMisc(void) {
/* Setup the dos multiplex interrupt */ /* Setup the dos multiplex interrupt */
first_multiplex=0; first_multiplex=0;

View File

@ -25,6 +25,7 @@
#include "cross.h" #include "cross.h"
#include "regs.h" #include "regs.h"
#include "callback.h" #include "callback.h"
#include "../shell/shell_inc.h"
class MOUNT : public Program { class MOUNT : public Program {
public: public:
@ -84,7 +85,8 @@ public:
return; return;
} }
if (temp_line[temp_line.size()-1]!=CROSS_FILESPLIT) temp_line+=CROSS_FILESPLIT; 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); cmd->FindCommand(1,temp_line);
if (temp_line.size()>1) goto showusage; if (temp_line.size()>1) goto showusage;
@ -220,6 +222,69 @@ static void UPCASE_ProgramStart(Program * * make) {
} }
#endif #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) { void DOS_SetupPrograms(void) {
/*Add Messages */ /*Add Messages */
MSG_Add("PROGRAM_MOUNT_STATUS_2","Drive %c is mounted as %s\n"); 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_EXTEND","%10d Kb free extended memory\n");
MSG_Add("PROGRAM_MEM_EXPAND","%10d Kb free expanded 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 */ #if !defined (WIN32) /* Unix */
MSG_Add("PROGRAM_UPCASE_ERROR_DIR","Failed to open directory %s\n"); MSG_Add("PROGRAM_UPCASE_ERROR_DIR","Failed to open directory %s\n");
MSG_Add("PROGRAM_UPCASE_SCANNING_DIR","Scanning directory %s\n"); MSG_Add("PROGRAM_UPCASE_SCANNING_DIR","Scanning directory %s\n");
@ -247,6 +317,7 @@ void DOS_SetupPrograms(void) {
/*regular setup*/ /*regular setup*/
PROGRAMS_MakeFile("MOUNT.COM",MOUNT_ProgramStart); PROGRAMS_MakeFile("MOUNT.COM",MOUNT_ProgramStart);
PROGRAMS_MakeFile("MEM.COM",MEM_ProgramStart); PROGRAMS_MakeFile("MEM.COM",MEM_ProgramStart);
PROGRAMS_MakeFile("LOADFIX.COM",LOADFIX_ProgramStart);
#if !defined (WIN32) /* Unix */ #if !defined (WIN32) /* Unix */
PROGRAMS_MakeFile("UPCASE.COM",UPCASE_ProgramStart); PROGRAMS_MakeFile("UPCASE.COM",UPCASE_ProgramStart);
#endif #endif

View File

@ -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 //TODO Maybe care for attributes but not likely
char newname[CROSS_LEN]; char newname[CROSS_LEN];
strcpy(newname,basedir); strcpy(newname,basedir);
@ -188,6 +188,14 @@ bool localDrive::TestDir(char * dir) {
strcpy(newdir,basedir); strcpy(newdir,basedir);
strcat(newdir,dir); strcat(newdir,dir);
CROSS_FILENAME(newdir); 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); int temp=access(newdir,F_OK);
return (temp==0); 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 */ /* Always report 100 mb free should be enough */
/* Total size is always 1 gb */ /* Total size is always 1 gb */
*_bytes_sector=allocation.bytes_sector; *_bytes_sector=allocation.bytes_sector;
@ -251,7 +259,7 @@ Bit8u localDrive::GetMediaByte(void) {
return allocation.mediaid; 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); strcpy(basedir,startdir);
sprintf(info,"local directory %s",startdir); sprintf(info,"local directory %s",startdir);
srch_opendir=NULL; srch_opendir=NULL;

View File

@ -204,7 +204,7 @@ bool Virtual_Drive::Rename(char * oldname,char * newname) {
return false; 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 */ /* Always report 100 mb free should be enough */
/* Total size is always 1 gb */ /* Total size is always 1 gb */
*_bytes_sector=512; *_bytes_sector=512;

View File

@ -63,6 +63,7 @@ bool WildFileCmp(const char * file, const char * wild)
r++; r++;
} }
checkext: checkext:
r=0;
while (r<3) { while (r<3) {
if (wild_ext[r]=='*') return true; if (wild_ext[r]=='*') return true;
if (wild_ext[r]!='?' && wild_ext[r]!=file_ext[r]) return false; if (wild_ext[r]!='?' && wild_ext[r]!=file_ext[r]) return false;

View File

@ -29,7 +29,7 @@ bool WildFileCmp(const char * file, const char * wild);
class localDrive : public DOS_Drive { class localDrive : public DOS_Drive {
public: 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 FileOpen(DOS_File * * file,char * name,Bit32u flags);
bool FileCreate(DOS_File * * file,char * name,Bit16u attributes); bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
bool FileUnlink(char * name); bool FileUnlink(char * name);
@ -40,7 +40,7 @@ public:
bool FindNext(DOS_DTA & dta); bool FindNext(DOS_DTA & dta);
bool GetFileAttr(char * name,Bit16u * attr); bool GetFileAttr(char * name,Bit16u * attr);
bool Rename(char * oldname,char * newname); 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 FileExists(const char* name);
bool FileStat(const char* name, FileStat_Block * const stat_block); bool FileStat(const char* name, FileStat_Block * const stat_block);
Bit8u GetMediaByte(void); Bit8u GetMediaByte(void);
@ -50,7 +50,7 @@ private:
DIR * srch_opendir; DIR * srch_opendir;
struct { struct {
Bit16u bytes_sector; Bit16u bytes_sector;
Bit16u sectors_cluster; Bit8u sectors_cluster;
Bit16u total_clusters; Bit16u total_clusters;
Bit16u free_clusters; Bit16u free_clusters;
Bit8u mediaid; Bit8u mediaid;
@ -73,7 +73,7 @@ public:
bool FindNext(DOS_DTA & dta); bool FindNext(DOS_DTA & dta);
bool GetFileAttr(char * name,Bit16u * attr); bool GetFileAttr(char * name,Bit16u * attr);
bool Rename(char * oldname,char * newname); 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 FileExists(const char* name);
bool FileStat(const char* name, FileStat_Block* const stat_block); bool FileStat(const char* name, FileStat_Block* const stat_block);
Bit8u GetMediaByte(void); Bit8u GetMediaByte(void);

View File

@ -64,15 +64,20 @@ void KEYBOARD_Init(Section*); //TODO This should setup INT 16 too but ok ;)
void JOYSTICK_Init(Section*); void JOYSTICK_Init(Section*);
void MOUSE_Init(Section*); void MOUSE_Init(Section*);
void SBLASTER_Init(Section*); void SBLASTER_Init(Section*);
void GUS_Init(Section*);
void ADLIB_Init(Section*); void ADLIB_Init(Section*);
void PCSPEAKER_Init(Section*); void PCSPEAKER_Init(Section*);
void TANDYSOUND_Init(Section*); void TANDYSOUND_Init(Section*);
void CMS_Init(Section*); void CMS_Init(Section*);
void DISNEY_Init(Section*);
void PIC_Init(Section*); void PIC_Init(Section*);
void TIMER_Init(Section*); void TIMER_Init(Section*);
void BIOS_Init(Section*); void BIOS_Init(Section*);
void DEBUG_Init(Section*); void DEBUG_Init(Section*);
void CMOS_Init(Section*);
/* Dos Internal mostly */ /* Dos Internal mostly */
void EMS_Init(Section*); void EMS_Init(Section*);
@ -84,27 +89,36 @@ void INT10_Init(Section*);
static LoopHandler * loop; static LoopHandler * loop;
Bitu RemainTicks;;
Bitu LastTicks;
static Bitu Normal_Loop(void) { static Bitu Normal_Loop(void) {
Bit32u new_ticks; Bitu ret,NewTicks;
new_ticks=GetTicks(); while (RemainTicks) {
if (new_ticks>LastTicks) { ret=PIC_RunQueue();
Bit32u ticks=new_ticks-LastTicks; #if C_DEBUG
if (ticks>20) ticks=20; if (DEBUG_ExitLoop()) return 0;
LastTicks=new_ticks; #endif
TIMER_AddTicks(ticks); if (ret) return ret;
RemainTicks--;
TIMER_AddTick();
GFX_Events();
} }
GFX_Events(); NewTicks=GetTicks();
TIMER_CheckPIT(); if (NewTicks>LastTicks) {
PIC_runIRQs(); RemainTicks+=NewTicks-LastTicks;
Bitu ret; if (RemainTicks>20) {
do { // LOG_DEBUG("Ticks to handle overflow %d",RemainTicks);
PIC_IRQAgain=false; RemainTicks=20;
ret=(*cpudecoder)(cpu_cycles); }
} while (!ret && PIC_IRQAgain); LastTicks=NewTicks;
#if C_DEBUG }
if (DEBUG_ExitLoop()) return 0; //TODO Make this selectable in the config file, since it gives some lag */
#endif if (!RemainTicks) {
return ret; SDL_Delay(1);
return 0;
}
return 0;
} }
void DOSBOX_SetLoop(LoopHandler * handler) { void DOSBOX_SetLoop(LoopHandler * handler) {
@ -127,7 +141,7 @@ static void DOSBOX_RealInit(Section * sec) {
/* Initialize some dosbox internals */ /* Initialize some dosbox internals */
errorlevel=section->Get_int("warnings"); errorlevel=section->Get_int("warnings");
MSG_Add("DOSBOX_CONFIGFILE_HELP","General Dosbox settings\n"); MSG_Add("DOSBOX_CONFIGFILE_HELP","General Dosbox settings\n");
LastTicks=GetTicks(); RemainTicks=0;LastTicks=GetTicks();
DOSBOX_SetLoop(&Normal_Loop); DOSBOX_SetLoop(&Normal_Loop);
MSG_Init(section); MSG_Init(section);
} }
@ -154,11 +168,14 @@ void DOSBOX_Init(void) {
secprop->AddInitFunction(&PIC_Init); secprop->AddInitFunction(&PIC_Init);
secprop->AddInitFunction(&PROGRAMS_Init); secprop->AddInitFunction(&PROGRAMS_Init);
secprop->AddInitFunction(&TIMER_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->Add_string("snapshots","snapshots");
secprop=control->AddSection_prop("cpu",&CPU_Init); secprop=control->AddSection_prop("cpu",&CPU_Init);
secprop->Add_int("cycles",4000); secprop->Add_int("cycles",1800);
secprop->AddInitFunction(&DMA_Init); secprop->AddInitFunction(&DMA_Init);
secprop->AddInitFunction(&VGA_Init); secprop->AddInitFunction(&VGA_Init);
@ -181,8 +198,13 @@ void DOSBOX_Init(void) {
secprop->Add_bool("adlib",true); secprop->Add_bool("adlib",true);
secprop->AddInitFunction(&CMS_Init); secprop->AddInitFunction(&CMS_Init);
secprop->Add_bool("cms",false); 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=control->AddSection_prop("speaker",&PCSPEAKER_Init);
secprop->Add_bool("enabled",true);
secprop->Add_bool("sinewave",false); secprop->Add_bool("sinewave",false);
secprop->AddInitFunction(&TANDYSOUND_Init); secprop->AddInitFunction(&TANDYSOUND_Init);
secprop->Add_bool("tandy",false); secprop->Add_bool("tandy",false);

View File

@ -1,5 +1,5 @@
AM_CPPFLAGS = -I$(top_srcdir)/include AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libgui.a noinst_LIBRARIES = libgui.a
libgui_a_SOURCES = sdlmain.cpp render.cpp libgui_a_SOURCES = sdlmain.cpp render.cpp render_support.h

View File

@ -84,7 +84,7 @@ install_sh = @install_sh@
AM_CPPFLAGS = -I$(top_srcdir)/include AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libgui.a noinst_LIBRARIES = libgui.a
libgui_a_SOURCES = sdlmain.cpp render.cpp libgui_a_SOURCES = sdlmain.cpp render.cpp render_support.h
subdir = src/gui subdir = src/gui
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h CONFIG_HEADER = $(top_builddir)/config.h
@ -110,6 +110,11 @@ CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@ -o $@
CXXFLAGS = @CXXFLAGS@ 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_SOURCES = $(libgui_a_SOURCES)
DIST_COMMON = Makefile.am Makefile.in DIST_COMMON = Makefile.am Makefile.in
SOURCES = $(libgui_a_SOURCES) SOURCES = $(libgui_a_SOURCES)

View File

@ -26,9 +26,10 @@
#include "keyboard.h" #include "keyboard.h"
#include "cross.h" #include "cross.h"
#define MAX_RES 2048 #define MAX_RES 2048
typedef void (* RENDER_Part_Handler)(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy);
struct PalData { struct PalData {
struct { struct {
@ -39,6 +40,10 @@ struct PalData {
} rgb[256]; } rgb[256];
Bitu first; Bitu first;
Bitu last; Bitu last;
union {
Bit32u bpp32[256];
Bit16u bpp16[256];
} lookup;
}; };
@ -48,18 +53,40 @@ static struct {
Bitu height; Bitu height;
Bitu bpp; Bitu bpp;
Bitu pitch; Bitu pitch;
Bitu flags;
float ratio; float ratio;
RENDER_Part_Handler part_handler;
} src; } 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; Bitu flags;
RENDER_Handler * handler;
Bitu stretch_x[MAX_RES];
Bitu stretch_y[MAX_RES];
PalData pal; PalData pal;
bool remake; bool keep_small;
bool enlarge;
bool screenshot; bool screenshot;
bool active;
} render; } render;
/* Forward declerations */
static void RENDER_ResetPal(void);
/* Include the different rendering routines */
#include "render_support.h"
static const char * snapshots_dir; static const char * snapshots_dir;
/* Take a screenshot of the data that should be rendered */ /* Take a screenshot of the data that should be rendered */
@ -150,7 +177,6 @@ static void TakeScreenShot(Bit8u * bitmap) {
/*clean up dynamically allocated RAM.*/ /*clean up dynamically allocated RAM.*/
free(row_pointers); free(row_pointers);
} }
@ -158,56 +184,38 @@ static void TakeScreenShot(Bit8u * bitmap) {
/* This could go kinda bad with multiple threads */ /* This could go kinda bad with multiple threads */
static void Check_Palette(void) { static void Check_Palette(void) {
if (render.pal.first>render.pal.last) return; if (render.pal.first>render.pal.last) return;
switch (render.op.bpp) {
GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]); 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.first=256;
render.pal.last=0; render.pal.last=0;
} }
static void MakeTables(void) { static void RENDER_ResetPal(void) {
//The stretching tables render.pal.first=0;
Bitu i;Bit32u c,a; render.pal.last=255;
c=0;a=(render.src.width<<16)/gfx_info.width;
for (i=0;i<gfx_info.width;i++) {
c=(c&0xffff)+a;
render.stretch_x[i]=c>> 16;
}
c=0;a=(render.src.height<<16)/gfx_info.height;
for (i=0;i<gfx_info.height;i++) {
c=(c&0xffff)+a;
render.stretch_y[i]=(c>>16)*render.src.pitch;
}
} }
static void Draw_8_Normal(Bit8u * src_data,Bit8u * dst_data) {
for (Bitu y=0;y<gfx_info.height;y++) {
Bit8u * line_src=src_data;
Bit8u * line_dest=dst_data;
for (Bitu x=0;x<gfx_info.width;x++) {
*line_dest++=*line_src;
line_src+=render.stretch_x[x];
}
src_data+=render.stretch_y[y];
dst_data+=gfx_info.pitch;
}
}
void RENDER_Draw(Bit8u * bitdata) {
Bit8u * src_data;
Check_Palette();
if (render.remake) {
MakeTables();
render.remake=false;
}
render.handler(&src_data);
if (render.screenshot) {
TakeScreenShot(src_data);
render.screenshot=false;
}
Draw_8_Normal(src_data,bitdata);
}
void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) { void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) {
render.pal.rgb[entry].red=red; render.pal.rgb[entry].red=red;
render.pal.rgb[entry].green=green; render.pal.rgb[entry].green=green;
@ -216,6 +224,38 @@ void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) {
if (render.pal.last<entry) render.pal.last=entry; if (render.pal.last<entry) render.pal.last=entry;
} }
bool RENDER_StartUpdate(void) {
if (render.frameskip.count<render.frameskip.max) {
render.frameskip.count++;
return false;
}
render.frameskip.count=0;
if (render.src.bpp==8) Check_Palette();
switch (render.op.type) {
case OP_None:
render.op.dest=render.op.pixels=GFX_StartUpdate();
break;
}
if (render.op.dest) return true;
else return false;
}
void RENDER_EndUpdate(void) {
switch (render.op.type) {
case OP_None:
/* Nothing to be done */
render.op.pixels=0;
break;
}
GFX_EndUpdate();
}
/* Update the data ready to be sent out for blitting onto the screen */
void RENDER_Part(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy) {
(render.src.part_handler)(src,x,y,dx,dy);
return;
}
static void RENDER_Resize(Bitu * width,Bitu * height) { static void RENDER_Resize(Bitu * width,Bitu * height) {
/* Calculate the new size the window should be */ /* Calculate the new size the window should be */
if (!*width && !*height) { if (!*width && !*height) {
@ -226,45 +266,72 @@ static void RENDER_Resize(Bitu * width,Bitu * height) {
if ((*width/render.src.ratio)<*height) *height=(Bitu)(*width/render.src.ratio); if ((*width/render.src.ratio)<*height) *height=(Bitu)(*width/render.src.ratio);
else *width=(Bitu)(*height*render.src.ratio); else *width=(Bitu)(*height*render.src.ratio);
} }
render.remake=true;
} }
void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu flags, RENDER_Handler * handler) { void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu flags) {
if ((!width) || (!height) || (!pitch)) {
if (!width) return; render.active=false;return;
if (!height) return; }
GFX_Stop();
render.src.width=width; render.src.width=width;
render.src.height=height; render.src.height=height;
render.src.bpp=bpp; render.src.bpp=bpp;
render.src.ratio=ratio;
render.src.pitch=pitch; render.src.pitch=pitch;
render.handler=handler; render.src.ratio=ratio;
render.src.flags=flags;
switch (bpp) { GFX_ModeCallBack callback;
case 8: switch (render.op.want_type) {
GFX_Resize(width,height,bpp,&RENDER_Resize);
GFX_SetDrawHandler(RENDER_Draw); case OP_None:
break; normalop:
switch (render.src.flags) {
case DoubleNone:break;
case DoubleWidth:width*=2;break;
case DoubleHeight:height*=2;break;
case DoubleBoth:
if (render.keep_small) {
render.src.flags=0;
} else {
width*=2;height*=2;
}
break;
}
flags=0;
callback=Render_Normal_CallBack;
break;
default: default:
E_Exit("RENDER:Illegal bpp %d",bpp); goto normalop;
};
/* Setup the internal render structures to correctly render this screen */ }
MakeTables(); GFX_SetSize(width,height,bpp,flags,callback);
GFX_Start();
} }
static void EnableScreenShot(void) { static void EnableScreenShot(void) {
render.screenshot=true; render.screenshot=true;
} }
static void IncreaseFrameSkip(void) {
if (render.frameskip.max<10) render.frameskip.max++;
LOG_MSG("Frame Skip at %d",render.frameskip.max);
}
static void DecreaseFrameSkip(void) {
if (render.frameskip.max>0) render.frameskip.max--;
LOG_MSG("Frame Skip at %d",render.frameskip.max);
}
void RENDER_Init(Section * sec) { void RENDER_Init(Section * sec) {
Section_prop * section=static_cast<Section_prop *>(sec); Section_prop * section=static_cast<Section_prop *>(sec);
snapshots_dir=section->Get_string("snapshots"); snapshots_dir=section->Get_string("snapshots");
render.pal.first=256; render.pal.first=256;
render.pal.last=0; 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_f5,CTRL_PRESSED,EnableScreenShot);
KEYBOARD_AddEvent(KBD_f7,CTRL_PRESSED,DecreaseFrameSkip);
KEYBOARD_AddEvent(KBD_f8,CTRL_PRESSED,IncreaseFrameSkip);
} }

228
src/gui/render_support.h Normal file
View File

@ -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();
}

View File

@ -19,7 +19,6 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <SDL.h> #include <SDL.h>
#include <SDL_thread.h>
#include "dosbox.h" #include "dosbox.h"
#include "video.h" #include "video.h"
@ -33,20 +32,16 @@
//#define DISABLE_JOYSTICK //#define DISABLE_JOYSTICK
struct SDL_Block { struct SDL_Block {
bool active; //If this isn't set don't draw bool active; //If this isn't set don't draw
Bitu width; Bitu width;
Bitu height; Bitu height;
Bitu bpp; Bitu bpp;
GFX_DrawHandler * draw; Bitu flags;
GFX_ResizeHandler * resize; GFX_ModeCallBack mode_callback;
bool full_screen; bool full_screen;
SDL_Thread * thread;
SDL_mutex * mutex;
SDL_Surface * surface; SDL_Surface * surface;
SDL_Joystick * joy; SDL_Joystick * joy;
SDL_Color pal[256];
struct { struct {
bool autolock; bool autolock;
bool autoenable; bool autoenable;
@ -54,62 +49,48 @@ struct SDL_Block {
bool locked; bool locked;
Bitu sensitivity; Bitu sensitivity;
} mouse; } mouse;
struct {
Bitu skip;
Bitu count;
} frames ;
}; };
static SDL_Block sdl; 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 */ /* Reset the screen with current values in the sdl structure */
static void ResetScreen(void) { static void ResetScreen(void) {
GFX_Stop();
if (sdl.full_screen) { if (sdl.full_screen) {
/* First get the original resolution */ /* 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 { } 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) { if (sdl.surface==0) {
E_Exit("SDL:Would be nice if I could get a surface."); E_Exit("SDL:Would be nice if I could get a surface.");
} }
SDL_WM_SetCaption(VERSION,VERSION); SDL_WM_SetCaption(VERSION,VERSION);
/* also fill up gfx_info structure */ /* also fill up gfx_info structure */
gfx_info.width=sdl.width; Bitu flags=MODE_SET;
gfx_info.height=sdl.height; if (sdl.full_screen) flags|=MODE_FULLSCREEN;
gfx_info.bpp=sdl.bpp; if (sdl.mode_callback) sdl.mode_callback(sdl.surface->w,sdl.surface->h,sdl.surface->format->BitsPerPixel,sdl.surface->pitch,flags);
gfx_info.pitch=sdl.surface->pitch; GFX_Start();
RestorePalette();
} }
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(); GFX_Stop();
sdl.width=width; sdl.width=width;
sdl.height=height; sdl.height=height;
sdl.bpp=bpp; sdl.bpp=bpp;
sdl.resize=resize; sdl.flags=flags;
sdl.mode_callback=callback;
ResetScreen(); ResetScreen();
GFX_Start(); GFX_Start();
} }
static void CaptureMouse() {
static void CaptureMouse(void) {
sdl.mouse.locked=!sdl.mouse.locked; sdl.mouse.locked=!sdl.mouse.locked;
if (sdl.mouse.locked) { if (sdl.mouse.locked) {
SDL_WM_GrabInput(SDL_GRAB_ON); 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) { static void SwitchFullScreen(void) {
GFX_Stop();
sdl.full_screen=!sdl.full_screen; sdl.full_screen=!sdl.full_screen;
if (sdl.full_screen) { if (sdl.full_screen) {
if (sdl.resize) { //TODO Give an resize event
sdl.width=0;sdl.height=0; if (!sdl.mouse.locked) CaptureMouse();
(*sdl.resize)(&sdl.width,&sdl.height); } else {
} if (sdl.mouse.locked) CaptureMouse();
} }
ResetScreen(); ResetScreen();
GFX_Start();
} }
//only prototype existed //only prototype existed
void GFX_SwitchFullScreen(void) { void GFX_SwitchFullScreen(void) {
SwitchFullScreen(); SwitchFullScreen();
} }
static void GFX_Redraw() { void * GFX_StartUpdate(void) {
#if C_THREADED
if (SDL_mutexP(sdl.mutex)) {
E_Exit("Can't Lock Mutex");
};
#endif
if (++sdl.frames.count<sdl.frames.skip) goto skipframe;
sdl.frames.count=0;
if (sdl.active) { if (sdl.active) {
SDL_LockSurface(sdl.surface ); if (SDL_MUSTLOCK(sdl.surface)) if (SDL_LockSurface(sdl.surface)) return 0;
if (sdl.surface->pixels && sdl.draw) (*sdl.draw)((Bit8u *)sdl.surface->pixels); return sdl.surface->pixels;
SDL_UnlockSurface(sdl.surface ); } else {
if (sdl.full_screen) SDL_Flip(sdl.surface); return 0;
else SDL_UpdateRect(sdl.surface,0,0,0,0);
};
skipframe:
#if C_THREADED
if (SDL_mutexV(sdl.mutex)) {
E_Exit("Can't Release Mutex");
} }
#endif
} }
static int SDLGFX_Thread(void * data) { void GFX_EndUpdate(void) {
do { if (SDL_MUSTLOCK(sdl.surface)) SDL_UnlockSurface(sdl.surface );
GFX_Redraw(); if (sdl.full_screen) SDL_Flip(sdl.surface);
SDL_Delay(1000/70); else SDL_UpdateRect(sdl.surface,0,0,0,0);
} while (true);
return 1;
} }
void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) { void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) {
/* I should probably not change the GFX_PalEntry :) */ /* 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.full_screen) {
if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,(SDL_Color *)entries,start,count)) { if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,(SDL_Color *)entries,start,count)) {
E_Exit("SDL:Can't set palette"); 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"); 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) { Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue) {
sdl.draw=handler; return SDL_MapRGB(sdl.surface->format,red,green,blue);
} }
void GFX_Stop() { void GFX_Stop() {
#if C_THREADED
SDL_mutexP(sdl.mutex);
#endif
sdl.active=false; 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<Section_prop *>(sec); Section_prop * section=static_cast<Section_prop *>(sec);
sdl.active=false; sdl.active=false;
sdl.full_screen=false; sdl.full_screen=false;
sdl.frames.skip=0;
sdl.frames.count=0;
sdl.draw=0;
sdl.mouse.locked=false; sdl.mouse.locked=false;
sdl.mouse.requestlock=false; sdl.mouse.requestlock=false;
sdl.mouse.autoenable=section->Get_bool("autolock"); sdl.mouse.autoenable=section->Get_bool("autolock");
sdl.mouse.autolock=false; sdl.mouse.autolock=false;
sdl.mouse.sensitivity=section->Get_int("sensitivity"); sdl.mouse.sensitivity=section->Get_int("sensitivity");
GFX_Resize(640,400,8,0); GFX_SetSize(640,400,8,0,0);
#if C_THREADED
sdl.mutex=SDL_CreateMutex();
sdl.thread = SDL_CreateThread(&SDLGFX_Thread,0);
#else
TIMER_RegisterMicroHandler(GFX_Redraw,1000000/70);
#endif
SDL_EnableKeyRepeat(250,30); SDL_EnableKeyRepeat(250,30);
/* Get some Keybinds */ /* Get some Keybinds */
KEYBOARD_AddEvent(KBD_f10,CTRL_PRESSED,CaptureMouse); 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); KEYBOARD_AddEvent(KBD_enter,ALT_PRESSED,SwitchFullScreen);
} }
@ -409,7 +334,11 @@ static void HandleMouseMotion(SDL_MouseMotionEvent * motion) {
static void HandleMouseButton(SDL_MouseButtonEvent * button) { static void HandleMouseButton(SDL_MouseButtonEvent * button) {
switch (button->state) { switch (button->state) {
case SDL_PRESSED: 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) { switch (button->button) {
case SDL_BUTTON_LEFT: case SDL_BUTTON_LEFT:
Mouse_ButtonPressed(0); Mouse_ButtonPressed(0);
@ -459,17 +388,11 @@ static void HandleJoystickButton(SDL_JoyButtonEvent * jbutton) {
static void HandleVideoResize(SDL_ResizeEvent * resize) { 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() { void GFX_Events() {
@ -568,8 +491,11 @@ int main(int argc, char* argv[]) {
control->StartUp(); control->StartUp();
/* Shutdown everything */ /* Shutdown everything */
} catch (char * error) { } catch (char * error) {
if (sdl.full_screen) SwitchFullScreen();
if (sdl.mouse.locked) CaptureMouse();
LOG_MSG("Exit to error: %sPress enter to continue.",error); LOG_MSG("Exit to error: %sPress enter to continue.",error);
fgetc(stdin); fgetc(stdin);
} }
GFX_ShutDown();
return 0; return 0;
}; };

View File

@ -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 \ 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 \ 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.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

View File

@ -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 \ 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 \ 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.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 subdir = src/hardware
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs 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.$(OBJEXT) vga_attr.$(OBJEXT) vga_crtc.$(OBJEXT) \
vga_dac.$(OBJEXT) vga_draw.$(OBJEXT) vga_fonts.$(OBJEXT) \ vga_dac.$(OBJEXT) vga_draw.$(OBJEXT) vga_fonts.$(OBJEXT) \
vga_gfx.$(OBJEXT) vga_memory.$(OBJEXT) vga_misc.$(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) libhardware_a_OBJECTS = $(am_libhardware_a_OBJECTS)
DEFS = @DEFS@ DEFS = @DEFS@
@ -118,18 +119,20 @@ LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/adlib.Po ./$(DEPDIR)/dma.Po \ @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/adlib.Po ./$(DEPDIR)/cmos.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/gameblaster.Po ./$(DEPDIR)/hardware.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/disney.Po ./$(DEPDIR)/dma.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/iohandler.Po ./$(DEPDIR)/joystick.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/gameblaster.Po ./$(DEPDIR)/gus.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/keyboard.Po ./$(DEPDIR)/memory.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/hardware.Po ./$(DEPDIR)/iohandler.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mixer.Po ./$(DEPDIR)/pcspeaker.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/joystick.Po ./$(DEPDIR)/keyboard.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/pic.Po ./$(DEPDIR)/sblaster.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/memory.Po ./$(DEPDIR)/mixer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/tandy_sound.Po ./$(DEPDIR)/timer.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/pcspeaker.Po ./$(DEPDIR)/pic.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/vga.Po ./$(DEPDIR)/vga_attr.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/sblaster.Po ./$(DEPDIR)/tandy_sound.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/vga_crtc.Po ./$(DEPDIR)/vga_dac.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/timer.Po ./$(DEPDIR)/vga.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/vga_draw.Po ./$(DEPDIR)/vga_fonts.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/vga_attr.Po ./$(DEPDIR)/vga_crtc.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/vga_gfx.Po ./$(DEPDIR)/vga_memory.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/vga_dac.Po ./$(DEPDIR)/vga_draw.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/vga_misc.Po ./$(DEPDIR)/vga_seq.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) \ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX) CXXLD = $(CXX)
@ -171,8 +174,11 @@ distclean-compile:
-rm -f *.tab.c -rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adlib.Po@am__quote@ @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)/dma.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gameblaster.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)/hardware.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iohandler.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joystick.Po@am__quote@

View File

@ -22,7 +22,7 @@
#include "dosbox.h" #include "dosbox.h"
#include "inout.h" #include "inout.h"
#include "mixer.h" #include "mixer.h"
#include "timer.h" #include "pic.h"
#include "hardware.h" #include "hardware.h"
#include "setup.h" #include "setup.h"
/* /*
@ -32,27 +32,45 @@
namespace MAME { namespace MAME {
/* Defines */ /* Defines */
# define logerror(x) # define logerror(x)
/* Disable recurring warnings */
#pragma warning ( disable : 4018 )
#pragma warning ( disable : 4244 )
/* Bring in Tatsuyuki Satoh's OPL emulation */ /* Disable recurring warnings */
#define HAS_YM3812 1 # pragma warning ( disable : 4018 )
#include "fmopl.c" # 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 { struct OPLTimer_t {
bool isEnabled; bool isEnabled;
bool isMasked; bool isMasked;
bool isOverflowed; bool isOverflowed;
Bit32u count; Bit64u count;
Bit32u base; Bit64u base;
}; };
static OPLTimer_t timer1,timer2; static OPLTimer_t timer1,timer2;
static MAME::FM_OPL * myopl;
static Bit8u regsel; static Bit8u regsel;
#define OPL_INTERNAL_FREQ 3600000 // The OPL operates at 3.6MHz #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 MIXER_Channel * adlib_chan;
static void ADLIB_CallBack(Bit8u *stream, Bit32u len) { 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 */ /* Calculate teh machine ms we are at now */
/* update 1 ms of data */ /* 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) { static Bit8u read_p388(Bit32u port) {
Bit8u ret=0; Bit8u ret=0;
Bit32u new_ticks=GetTicks(); Bit64u micro=PIC_MicroCount();
if (timer1.isEnabled) { if (timer1.isEnabled) {
if ((new_ticks-timer1.base)>timer1.count) { if ((micro-timer1.base)>timer1.count) {
timer1.isOverflowed=true; timer1.isOverflowed=true;
timer1.base=new_ticks; timer1.base=micro;
} }
if (timer1.isOverflowed || !timer1.isMasked) { if (timer1.isOverflowed || !timer1.isMasked) {
ret|=0xc0; ret|=0xc0;
} }
} }
if (timer2.isEnabled) { if (timer2.isEnabled) {
if ((new_ticks-timer2.base)>timer2.count) { if ((micro-timer2.base)>timer2.count) {
timer2.isOverflowed=true; timer2.isOverflowed=true;
timer2.base=new_ticks; timer2.base=micro;
} }
if (timer2.isOverflowed || !timer2.isMasked) { if (timer2.isOverflowed || !timer2.isMasked) {
ret|=0xA0; ret|=0xA0;
@ -94,10 +112,10 @@ static void write_p388(Bit32u port,Bit8u val) {
static void write_p389(Bit32u port,Bit8u val) { static void write_p389(Bit32u port,Bit8u val) {
switch (regsel) { switch (regsel) {
case 0x02: /* Timer 1 */ case 0x02: /* Timer 1 */
timer1.count=(val*80/1000); timer1.count=val*80;
return; return;
case 0x03: /* Timer 2 */ case 0x03: /* Timer 2 */
timer2.count=(val*320/1000); timer2.count=val*320;
return; return;
case 0x04: /* IRQ clear / mask and Timer enable */ case 0x04: /* IRQ clear / mask and Timer enable */
if (val&0x80) { if (val&0x80) {
@ -105,25 +123,24 @@ static void write_p389(Bit32u port,Bit8u val) {
timer2.isOverflowed=false; timer2.isOverflowed=false;
return; return;
} }
if (val&0x40) { if (val&0x40) timer1.isMasked=true;
timer1.isMasked=true; else timer1.isMasked=false;
} else {
timer1.isMasked=false; if (val&1) {
timer1.isEnabled=((val&1)>0); timer1.isEnabled=true;
timer1.base=GetTicks(); timer1.base=PIC_MicroCount();
} } else timer1.isEnabled=false;
if (val&0x20) { if (val&0x20) timer2.isMasked=true;
timer2.isMasked=true; else timer2.isMasked=false;
} else { if (val&2) {
timer2.isMasked=false; timer2.isEnabled=true;
timer2.isEnabled=((val&2)>0); timer2.base=PIC_MicroCount();
timer2.base=GetTicks(); } else timer2.isEnabled=false;
}
return; return;
default: /* Normal OPL call queue it */ 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; static bool adlib_enabled;
@ -169,7 +186,10 @@ void ADLIB_Init(Section* sec) {
timer2.isOverflowed=false; timer2.isOverflowed=false;
#define ADLIB_FREQ 22050 #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"); adlib_chan=MIXER_AddChannel(ADLIB_CallBack,ADLIB_FREQ,"ADLIB");
MIXER_SetMode(adlib_chan,MIXER_16MONO); MIXER_SetMode(adlib_chan,MIXER_16MONO);

118
src/hardware/cmos.cpp Normal file
View File

@ -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;
}

102
src/hardware/disney.cpp Normal file
View File

@ -0,0 +1,102 @@
#include <string.h>
#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<DISNEY_SIZE) {
disney.buffer[disney.used++]=disney.data;
}
}
if (val&0x10) LOG_DEBUG("IRQ Enabled");
disney.control=val;
break;
}
}
static Bit8u disney_read(Bit32u port) {
switch (port-DISNEY_BASE) {
case 0: /* Data Port */
LOG_WARN("DISNEY:Read from data port");
return disney.data;
break;
case 1: /* Status Port */
// LOG_WARN("DISNEY:Read from status port %X",disney.status);
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;
}

View File

@ -83,14 +83,20 @@ static Bit8u read_dma(Bit32u port) {
ret=(chan->current_address>>8)&0xff; ret=(chan->current_address>>8)&0xff;
} }
cont->flipflop=!cont->flipflop; cont->flipflop=!cont->flipflop;
break;
case 0x01:case 0x03:case 0x05:case 0x07: case 0x01:case 0x03:case 0x05:case 0x07:
if (cont->flipflop) { if (cont->flipflop) {
ret=(chan->current_count-1) & 0xff; ret=(Bit8u)((chan->current_count-1) & 0xff);
} else { } else {
ret=((chan->current_count-1)>>8)&0xff; ret=(Bit8u)(((chan->current_count-1)>>8)&0xff);
} }
cont->flipflop=!cont->flipflop; cont->flipflop=!cont->flipflop;
break; break;
case 0x08: /* Read Status */
ret=cont->status_reg;
cont->status_reg&=0xf; /* Clear lower 4 bits on read */
break;
default: default:
LOG_WARN("DMA:Unhandled read from %d",port); LOG_WARN("DMA:Unhandled read from %d",port);
} }
@ -105,18 +111,18 @@ static void write_dma(Bit32u port,Bit8u val) {
switch (port) { switch (port) {
case 0x00:case 0x02:case 0x04:case 0x06: case 0x00:case 0x02:case 0x04:case 0x06:
if (cont->flipflop) { if (cont->flipflop) {
chan->base_address=val; chan->base_address=(chan->base_address & 0xff00) | val;
} else { } else {
chan->base_address|=(val<<8); chan->base_address=(chan->base_address & 0x00ff) | (val<<8);
} }
cont->flipflop=!cont->flipflop; cont->flipflop=!cont->flipflop;
chan->addr_changed=true; chan->addr_changed=true;
break; break;
case 0x01:case 0x03:case 0x05:case 0x07: case 0x01:case 0x03:case 0x05:case 0x07:
if (cont->flipflop) { if (cont->flipflop) {
chan->base_count=val; chan->base_count=(chan->base_count & 0xff00) | val;
} else { } else {
chan->base_count|=(val<<8); chan->base_count=(chan->base_count & 0x00ff) | (val<<8);
} }
cont->flipflop=!cont->flipflop; cont->flipflop=!cont->flipflop;
chan->addr_changed=true; chan->addr_changed=true;
@ -128,6 +134,8 @@ static void write_dma(Bit32u port,Bit8u val) {
case 0x09: /* Request Register */ case 0x09: /* Request Register */
if (val&4) { if (val&4) {
/* Set Request bit */ /* Set Request bit */
Bitu channel = val & 0x03;
cont->status_reg |= (1 << (channel+4));
} else { } else {
Bitu channel = val & 0x03; Bitu channel = val & 0x03;
cont->status_reg &= ~(1 << (channel+4)); 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) { void write_dma_page(Bit32u port,Bit8u val) {
Bitu channel;
switch (port) { switch (port) {
case 0x81: /* dma0 page register, channel 2 */ case 0x81: /* dma0 page register, channel 2 */
channel=2;break;
case 0x82: /* dma0 page register, channel 3 */ case 0x82: /* dma0 page register, channel 3 */
channel=3;break;
case 0x83: /* dma0 page register, channel 1 */ case 0x83: /* dma0 page register, channel 1 */
channel=1;break;
case 0x87: /* dma0 page register, channel 0 */ case 0x87: /* dma0 page register, channel 0 */
Bitu channel = channelindex[port - 0x81]; channel=0;break;
dma[0].chan[channel].page=val;
dma[0].chan[channel].addr_changed=true;
break;
} }
dma[0].chan[channel].page=val;
dma[0].chan[channel].addr_changed=true;
} }
Bit16u DMA_8_Read(Bit32u dmachan,Bit8u * buffer,Bit16u count) { 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; chan->current_address=chan->base_address;
DMA_DEBUG("DMA:Transfer from %d size %d",(chan->page << 16)+chan->base_address,chan->current_count); 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); MEM_BlockRead(chan->address,buffer,count);
chan->address+=count; chan->address+=count;
chan->current_address+=count; chan->current_address+=count;
@ -192,18 +201,27 @@ Bit16u DMA_8_Read(Bit32u dmachan,Bit8u * buffer,Bit16u count) {
} else { } else {
/* Copy remaining piece of first buffer */ /* Copy remaining piece of first buffer */
MEM_BlockRead(chan->address,buffer,chan->current_count); MEM_BlockRead(chan->address,buffer,chan->current_count);
buffer+=chan->current_count; if (!chan->mode.autoinit_enable) {
count-=(Bit16u)chan->current_count; /* Set the end of counter bit */
/* Autoinit reset the dma channel */ dma[0].status_reg|=(1 << dmachan);
chan->address=(chan->page << 16)+chan->base_address; count=(Bit16u)chan->current_count;
chan->current_count=chan->base_count+1; chan->current_address+=count;;
chan->current_address=chan->base_address; chan->current_count=0;
/* Copy the rest of the buffer */ return count;
MEM_BlockRead(chan->address,buffer,count); } else {
chan->address+=count; buffer+=chan->current_count;
chan->current_address+=count; Bit16u left=count-(Bit16u)chan->current_count;
chan->current_count-=count; /* Autoinit reset the dma channel */
return count; 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;
}
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,7 @@
#define BUILD_YM3526 (HAS_YM3526) #define BUILD_YM3526 (HAS_YM3526)
#define BUILD_Y8950 (HAS_Y8950) #define BUILD_Y8950 (HAS_Y8950)
/* --- system optimize --- */ /* select output bits size of output : 8 or 16 */
/* select bit size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16 #define OPL_SAMPLE_BITS 16
/* compiler dependence */ /* compiler dependence */
@ -25,167 +24,88 @@ typedef signed int INT32; /* signed 32bit */
typedef INT16 OPLSAMPLE; typedef INT16 OPLSAMPLE;
#endif #endif
#if (OPL_SAMPLE_BITS==8) #if (OPL_SAMPLE_BITS==8)
typedef unsigned char OPLSAMPLE; typedef INT8 OPLSAMPLE;
#endif #endif
#if BUILD_Y8950
#include "ymdeltat.h"
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq); typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param); 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 */ #if BUILD_YM3812
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
#define OPL_TYPE_IO 0x08 /* I/O port */
/* Saving is necessary for member of the 'R' mark for suspend/resume */ int YM3812Init(int num, int clock, int rate);
/* ---------- OPL slot ---------- */ void YM3812Shutdown(void);
typedef struct fm_opl_slot { void YM3812ResetChip(int which);
const UINT32 *AR; /* attack rate tab :&eg_table[AR<<2]*/ int YM3812Write(int which, int a, int v);
const UINT32 *DR; /* decay rate tab :&eg_table[DR<<2]*/ unsigned char YM3812Read(int which, int a);
const UINT32 *RR; /* release rate tab:&eg_table[RR<<2]*/ int YM3812TimerOver(int which, int c);
UINT8 KSR; /* key scale rate */ void YM3812UpdateOne(int which, INT16 *buffer, int length);
UINT8 ARval; /* current AR */
UINT8 ksl; /* keyscale level */
UINT8 ksr; /* key scale rate :kcode>>KSR */
UINT8 mul; /* multiple :ML_TABLE[ML] */
/* Phase Generator */ void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
UINT32 Cnt; /* frequency count */ void YM3812SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param);
UINT32 Incr; /* frequency step */ void YM3812SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param);
/* Envelope Generator */ #endif
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 */
UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
/* LFO */ #if BUILD_YM3526
UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
/* waveform select */ /*
unsigned int *wavetable; ** Initialize YM3526 emulator(s).
}OPL_SLOT; **
** '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 ---------- */ void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
typedef struct fm_opl_channel { void YM3526SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param);
OPL_SLOT SLOT[2]; void YM3526SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param);
UINT8 FB; /* feedback shift value */
INT32 *connect1; /* slot1 output pointer */
INT32 op1_out[2]; /* slot1 output for feedback */
/* phase generator state */ #endif
UINT32 block_fnum; /* block+fnum */
UINT32 fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 kcode; /* key code (for key scaling) */
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 #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 */ /* Y8950 port handlers */
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);
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);
void Y8950SetDeltaTMemory(int which, void * deltat_rom, int deltat_rom_size );
void OPLResetChip(FM_OPL *OPL); int Y8950Init (int num, int clock, int rate);
int OPLWrite(FM_OPL *OPL,int a,int v); void Y8950Shutdown (void);
unsigned char OPLRead(FM_OPL *OPL,int a); void Y8950ResetChip (int which);
int OPLTimerOver(FM_OPL *OPL,int c); 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 #endif

23
src/hardware/gus.cpp Normal file
View File

@ -0,0 +1,23 @@
#include <string.h>
#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) {
}

View File

@ -46,14 +46,14 @@ static Bit8u read_p201(Bit32u port) {
if (stick[0].enabled) { if (stick[0].enabled) {
if (stick[0].xcount) stick[0].xcount--; else ret&=~1; if (stick[0].xcount) stick[0].xcount--; else ret&=~1;
if (stick[0].ycount) stick[0].ycount--; else ret&=~2; if (stick[0].ycount) stick[0].ycount--; else ret&=~2;
if (stick[0].button[0]) ret&=16; if (stick[0].button[0]) ret&=~16;
if (stick[0].button[1]) ret&=32; if (stick[0].button[1]) ret&=~32;
} }
if (stick[1].enabled) { if (stick[1].enabled) {
if (stick[1].xcount) stick[1].xcount--; else ret&=~4; if (stick[1].xcount) stick[1].xcount--; else ret&=~4;
if (stick[1].ycount) stick[1].ycount--; else ret&=~8; if (stick[1].ycount) stick[1].ycount--; else ret&=~8;
if (stick[1].button[0]) ret&=64; if (stick[1].button[0]) ret&=~64;
if (stick[1].button[1]) ret&=128; if (stick[1].button[1]) ret&=~128;
} }
return ret; return ret;
} }

View File

@ -48,6 +48,7 @@ struct KeyBlock {
KeyCommands command; KeyCommands command;
bool read_active; bool read_active;
bool enabled; bool enabled;
bool active;
}; };
static KeyBlock keyb; static KeyBlock keyb;
@ -87,7 +88,7 @@ void KEYBOARD_AddCode(Bit8u code) {
keyb.buf[start]=code; keyb.buf[start]=code;
keyb.read_active=true; 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) { 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) { static void write_p64(Bit32u port,Bit8u val) {
switch (val) { switch (val) {
case 0: case 0xad: /* Activate keyboard */
keyb.active=true;
break;
case 0xae: /* Deactivate keyboard */
keyb.active=false;
break;
default: default:
LOG_DEBUG("Port 64 write with val %d",val); LOG_DEBUG("Port 64 write with val %d",val);
break; break;

View File

@ -20,6 +20,7 @@
#include "dosbox.h" #include "dosbox.h"
#include "mixer.h" #include "mixer.h"
#include "timer.h" #include "timer.h"
#include "setup.h"
#ifndef PI #ifndef PI
@ -30,20 +31,25 @@
#define SPKR_RATE 22050 #define SPKR_RATE 22050
#define SPKR_VOLUME 5000 #define SPKR_VOLUME 5000
#define FREQ_SHIFT 16 #define SPKR_SHIFT 16
#define FREQ_MAX (2 << FREQ_SHIFT)
#define SIN_ENT 1024
#define SIN_MAX (SIN_ENT << SPKR_SHIFT)
#define FREQ_MAX (2 << SPKR_SHIFT)
#define FREQ_HALF (FREQ_MAX >> 1) #define FREQ_HALF (FREQ_MAX >> 1)
struct Speaker { struct Speaker {
Bit32u freq_add; Bitu freq_add;
Bit32u freq_pos; Bitu freq_pos;
Bit16s volume; Bit16s volume;
MIXER_Channel * chan; MIXER_Channel * chan;
bool enabled; bool enabled;
bool realsound; bool realsound;
bool sinewave;
Bitu mode;
Bit16u buffer[SPKR_BUF]; Bit16u buffer[SPKR_BUF];
Bit16s table[SIN_ENT];
Bitu buf_pos; Bitu buf_pos;
}; };
@ -52,6 +58,7 @@ static Speaker spkr;
void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) { void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) {
spkr.mode=mode;
switch (mode) { switch (mode) {
case 0: case 0:
if (cntr>72) cntr=72; if (cntr>72) cntr=72;
@ -59,8 +66,14 @@ void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) {
if (spkr.buf_pos<SPKR_BUF) spkr.buffer[spkr.buf_pos++]=(cntr-36)*600; if (spkr.buf_pos<SPKR_BUF) spkr.buffer[spkr.buf_pos++]=(cntr-36)*600;
break; break;
case 3: case 3:
spkr.freq_add=(Bit32u)(FREQ_MAX/((float)SPKR_RATE/(PIT_TICK_RATE/(float)cntr))); if (spkr.sinewave) {
spkr.freq_add=(Bitu)(SIN_MAX/((float)SPKR_RATE/(PIT_TICK_RATE/(float)cntr)));
} else {
spkr.freq_add=(Bitu)(FREQ_MAX/((float)SPKR_RATE/(PIT_TICK_RATE/(float)cntr)));
}
break; break;
case 4:
spkr.freq_pos=(Bitu)(SPKR_RATE/(PIT_TICK_RATE/(float)cntr));
} }
} }
@ -70,19 +83,27 @@ void PCSPEAKER_Enable(bool enable) {
} }
static void PCSPEAKER_CallBack(Bit8u * stream,Bit32u len) { static void PCSPEAKER_CallBack(Bit8u * stream,Bit32u len) {
if (spkr.realsound) { switch (spkr.mode) {
/* Generate the "RealSound" */ case 0:
Bitu buf_add=(spkr.buf_pos<<16)/len; /* Generate the "RealSound" */
Bitu buf_pos=0; {
spkr.buf_pos=0;spkr.realsound=0; Bitu buf_add=(spkr.buf_pos<<16)/len;
while (len-->0) { Bitu buf_pos=0;
*(Bit16s*)(stream)=spkr.buffer[buf_pos >> 16]; spkr.buf_pos=0;spkr.realsound=0;
buf_pos+=buf_add; while (len-->0) {
stream+=2; *(Bit16s*)(stream)=spkr.buffer[buf_pos >> 16];
buf_pos+=buf_add;
stream+=2;
}
break;
} }
} else { case 3:
/* Generate a square wave */ if (spkr.sinewave) while (len-->0) {
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; spkr.freq_pos+=spkr.freq_add;
if (spkr.freq_pos>=FREQ_MAX) spkr.freq_pos-=FREQ_MAX; if (spkr.freq_pos>=FREQ_MAX) spkr.freq_pos-=FREQ_MAX;
if (spkr.freq_pos>=FREQ_HALF) { if (spkr.freq_pos>=FREQ_HALF) {
@ -92,11 +113,26 @@ static void PCSPEAKER_CallBack(Bit8u * stream,Bit32u len) {
} }
stream+=2; 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) { void PCSPEAKER_Init(Section* sec) {
MSG_Add("SPEAKER_CONFIGFILE_HELP","pcspeaker related options.\n"); MSG_Add("SPEAKER_CONFIGFILE_HELP","pcspeaker related options.\n");
Section_prop * section=static_cast<Section_prop *>(sec);
if(!section->Get_bool("enabled")) return;
spkr.sinewave=section->Get_bool("sinewave");
spkr.chan=MIXER_AddChannel(&PCSPEAKER_CallBack,SPKR_RATE,"PC-SPEAKER"); spkr.chan=MIXER_AddChannel(&PCSPEAKER_CallBack,SPKR_RATE,"PC-SPEAKER");
MIXER_Enable(spkr.chan,false); MIXER_Enable(spkr.chan,false);
MIXER_SetMode(spkr.chan,MIXER_16MONO); MIXER_SetMode(spkr.chan,MIXER_16MONO);
@ -104,4 +140,8 @@ void PCSPEAKER_Init(Section* sec) {
spkr.enabled=false; spkr.enabled=false;
spkr.realsound=false; spkr.realsound=false;
spkr.buf_pos=0; spkr.buf_pos=0;
/* Generate the sine wave */
for (Bitu i=0;i<SIN_ENT;i++) {
spkr.table[i]=(Bit16s)(sin(2*PI/SIN_ENT*i)*SPKR_VOLUME*1.5);
}
} }

View File

@ -22,6 +22,8 @@
#include "cpu.h" #include "cpu.h"
#include "pic.h" #include "pic.h"
#define PIC_QUEUESIZE 128
struct IRQ_Block { struct IRQ_Block {
bool masked; bool masked;
bool active; bool active;
@ -31,9 +33,10 @@ struct IRQ_Block {
PIC_EOIHandler * handler; PIC_EOIHandler * handler;
}; };
Bitu PIC_Ticks=0;
Bitu PIC_IRQCheck; Bitu PIC_IRQCheck;
Bitu PIC_IRQActive; Bitu PIC_IRQActive;
bool PIC_IRQAgain;
static IRQ_Block irqs[16]; static IRQ_Block irqs[16];
static Bit8u pic0_icws=0; static Bit8u pic0_icws=0;
@ -42,10 +45,29 @@ static Bit8u pic0_icw_state=0;
static Bit8u pic1_icw_state=0; static Bit8u pic1_icw_state=0;
static bool pic0_request_iisr=0; static bool pic0_request_iisr=0;
static bool pic1_request_iisr=0; static bool pic1_request_iisr=0;
//TODO Special mask mode in ocw3
//TODO maybe check for illegal modes that don't work on pc too and exit the emu
//Pic 0 command port enum QUEUE_TYPE {
IRQ,EVENT
};
struct PICEntry {
QUEUE_TYPE type;
Bitu irq;
Bitu index;
PIC_EventHandler event;
PICEntry * next;
};
static struct {
PICEntry entries[PIC_QUEUESIZE];
PICEntry * free_entry;
PICEntry * next_entry;
} pic;
static void write_p20(Bit32u port,Bit8u val) { static void write_p20(Bit32u port,Bit8u val) {
switch (val) { switch (val) {
case 0x0A: /* select read interrupt request register */ case 0x0A: /* select read interrupt request register */
@ -63,7 +85,14 @@ static void write_p20(Bit32u port,Bit8u val) {
pic0_icw_state=1; pic0_icw_state=1;
break; break;
case 0x20: /* end of interrupt command */ case 0x20: /* end of interrupt command */
/* clear highest current in service bit */ 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<8) { if (PIC_IRQActive<8) {
irqs[PIC_IRQActive].inservice=false; irqs[PIC_IRQActive].inservice=false;
if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler(); if (irqs[PIC_IRQActive].handler!=0) irqs[PIC_IRQActive].handler();
@ -111,14 +140,14 @@ static void write_p21(Bit32u port,Bit8u val) {
else PIC_IRQCheck&=~(1 << i); else PIC_IRQCheck&=~(1 << i);
}; };
break; break;
case 1: /* icw2 */ case 1: /* icw2 */
LOG_DEBUG("PIC0:Base vector %X",val);
for (i=0;i<=7;i++) { for (i=0;i<=7;i++) {
irqs[i].vector=(val&0xf8)+i; irqs[i].vector=(val&0xf8)+i;
}; };
default: /* icw2, 3, and 4*/ default: /* icw2, 3, and 4*/
if(pic0_icw_state++ >= pic0_icws) pic0_icw_state=0; if(pic0_icw_state++ >= pic0_icws) pic0_icw_state=0;
} }
} }
static Bit8u read_p20(Bit32u port) { static Bit8u read_p20(Bit32u port) {
@ -174,6 +203,13 @@ static void write_pa0(Bit32u port,Bit8u val) {
pic1_icw_state=1; pic1_icw_state=1;
break; break;
case 0x20: /* end of interrupt command */ 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 */ /* clear highest current in service bit */
if (PIC_IRQActive>7 && PIC_IRQActive <16) { if (PIC_IRQActive>7 && PIC_IRQActive <16) {
irqs[PIC_IRQActive].inservice=false; irqs[PIC_IRQActive].inservice=false;
@ -218,7 +254,6 @@ static void write_pa1(Bit32u port,Bit8u val) {
case 0: /* mask register */ case 0: /* mask register */
for (i=0;i<=7;i++) { for (i=0;i<=7;i++) {
irqs[i+8].masked=(val&1 <<i)>0; irqs[i+8].masked=(val&1 <<i)>0;
if (!irqs[8].masked) LOG_DEBUG("Someone unmasked RTC irq");
}; };
break; break;
case 1: /* icw2 */ case 1: /* icw2 */
@ -292,7 +327,7 @@ void PIC_DeActivateIRQ(Bit32u irq) {
} }
void PIC_runIRQs(void) { void PIC_runIRQs(void) {
Bit32u i; Bitu i;
if (!flags.intf) return; if (!flags.intf) return;
if (PIC_IRQActive!=PIC_NOIRQ) return; if (PIC_IRQActive!=PIC_NOIRQ) return;
if (!PIC_IRQCheck) return; if (!PIC_IRQCheck) return;
@ -304,19 +339,166 @@ void PIC_runIRQs(void) {
PIC_IRQCheck&=~(1 << i); PIC_IRQCheck&=~(1 << i);
Interrupt(irqs[i].vector); Interrupt(irqs[i].vector);
PIC_IRQActive=i; PIC_IRQActive=i;
PIC_IRQAgain=true;
return; 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 (cycles<CPU_CycleLeft) {
CPU_Cycles=cycles;
} else {
CPU_Cycles=CPU_CycleLeft;
}
} else CPU_Cycles=CPU_CycleLeft;
if (PIC_IRQCheck) PIC_runIRQs();
/* Run the actual cpu core */
CPU_CycleLeft-=CPU_Cycles;
ret=(*cpudecoder)();
if (CPU_Cycles>0) {
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) { void PIC_Init(Section* sec) {
/* Setup pic0 and pic1 with initial values like DOS has normally */ /* Setup pic0 and pic1 with initial values like DOS has normally */
PIC_IRQCheck=0; PIC_IRQCheck=0;
PIC_IRQActive=PIC_NOIRQ; PIC_IRQActive=PIC_NOIRQ;
Bit8u i; PIC_Ticks=0;
Bitu i;
for (i=0;i<=7;i++) { for (i=0;i<=7;i++) {
irqs[i].active=false; irqs[i].active=false;
irqs[i].masked=true; irqs[i].masked=true;
@ -338,6 +520,14 @@ void PIC_Init(Section* sec) {
IO_RegisterReadHandler(0xa1,read_pa1,"Slave PIC Data"); IO_RegisterReadHandler(0xa1,read_pa1,"Slave PIC Data");
IO_RegisterWriteHandler(0xa0,write_pa0,"Slave PIC Command"); IO_RegisterWriteHandler(0xa0,write_pa0,"Slave PIC Command");
IO_RegisterWriteHandler(0xa1,write_pa1,"Slave PIC Data"); IO_RegisterWriteHandler(0xa1,write_pa1,"Slave PIC Data");
/* Initialize the pic queue */
for (i=0;i<PIC_QUEUESIZE-1;i++) {
pic.entries[i].next=&pic.entries[i+1];
}
pic.entries[PIC_QUEUESIZE-1].next=0;
pic.free_entry=&pic.entries[0];
pic.next_entry=0;
} }

View File

@ -33,57 +33,56 @@
struct PIT_Block { struct PIT_Block {
Bit8u mode; /* Current Counter Mode */ Bit8u mode; /* Current Counter Mode */
Bit32s cntr;
Bitu cntr;
Bits micro;
Bit64u start;
Bit8u latch_mode; Bit8u latch_mode;
Bit8u read_state; Bit8u read_state;
Bit16s read_latch; Bit16s read_latch;
Bit8u write_state; Bit8u write_state;
Bit16u write_latch; Bit16u write_latch;
Bit32u last_ticks;
}; };
bool TimerAgain;
Bit32u LastTicks;
static PIT_Block pit[3]; static PIT_Block pit[3];
static Bit32u pit_ticks; /* The amount of pit ticks one host tick is bit shifted */
static Bit32u timer_ticks; /* The amount of pit ticks bitshifted one timer cycle needs */
static Bit32u timer_buildup; /* The amount of pit ticks waiting */
#define TIMER_AVERAGE 5
static struct TimerBlock {
float req[TIMER_AVERAGE];
Bitu req_index;
Bitu req_count;
float req_average;
Bitu ticks;
} timer;
#define PIT_SHIFT 9
#define MAX_PASSED ((PIT_TICK_RATE/4) << PIT_SHIFT) /* Alow 1/4 second of timer build up */
static void PIT0_Event(void) {
PIC_ActivateIRQ(0);
PIC_AddEvent(PIT0_Event,pit[0].micro);
}
static void counter_latch(Bitu counter) { static void counter_latch(Bitu counter) {
/* Fill the read_latch of the selected counter with current count */ /* Fill the read_latch of the selected counter with current count */
PIT_Block * p=&pit[counter]; PIT_Block * p=&pit[counter];
timer.req_count++;
float pos=timer.req_average*timer.req_count; Bit64s micro=PIC_MicroCount()-p->start;
Bit16u ticks=pos*p->cntr;
switch (p->mode) { 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: case 2:
micro%=p->micro;
p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr));
break;
case 3: 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; break;
default: default:
LOG_ERROR("PIT:Illegal Mode %d for reading counter %d",p->mode,counter); 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; break;
} }
} }
static void write_latch(Bit32u port,Bit8u val) { static void write_latch(Bit32u port,Bit8u val) {
Bit32u counter=port-0x40; Bitu counter=port-0x40;
PIT_Block * p=&pit[counter]; PIT_Block * p=&pit[counter];
switch (p->write_state) { switch (p->write_state) {
case 0: case 0:
@ -104,21 +103,21 @@ static void write_latch(Bit32u port,Bit8u val) {
if (p->write_state != 0) { if (p->write_state != 0) {
if (p->write_latch == 0) p->cntr = 0x10000; if (p->write_latch == 0) p->cntr = 0x10000;
else p->cntr = p->write_latch; 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) { switch (counter) {
case 0x00: /* Timer hooked to IRQ 0 */ case 0x00: /* Timer hooked to IRQ 0 */
PIC_DeActivateIRQ(0); PIC_RemoveEvents(PIT0_Event);
timer_ticks=p->cntr << PIT_SHIFT; PIC_AddEvent(PIT0_Event,p->micro);
timer_buildup=0;
LOG_DEBUG("PIT 0 Timer at %.3g Hz mode %d",PIT_TICK_RATE/(double)p->cntr,p->mode); LOG_DEBUG("PIT 0 Timer at %.3g Hz mode %d",PIT_TICK_RATE/(double)p->cntr,p->mode);
break; break;
case 0x02: /* Timer hooked to PC-Speaker */ 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); PCSPEAKER_SetCounter(p->cntr,p->mode);
break; break;
default: default:
LOG_ERROR("PIT:Illegal timer selected for writing"); LOG_ERROR("PIT:Illegal timer selected for writing");
} }
} }
} }
@ -194,14 +193,10 @@ struct Timer {
TIMER_TickHandler handler; TIMER_TickHandler handler;
} tick; } tick;
struct{ struct{
Bitu count; Bits left;
Bitu total; Bits total;
TIMER_MicroHandler handler; TIMER_MicroHandler handler;
} micro; } 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); Timer * new_timer=new(Timer);
new_timer->type=T_MICRO; new_timer->type=T_MICRO;
new_timer->micro.handler=handler; new_timer->micro.handler=handler;
new_timer->micro.total=micro;
new_timer->micro.count=0;
Timers.push_front(new_timer); Timers.push_front(new_timer);
TIMER_SetNewMicro(new_timer,micro);
return (TIMER_Block *)new_timer; 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) { void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro) {
Timer * timer=(Timer *)block; Timer * timer=(Timer *)block;
if (timer->type!=T_MICRO) E_Exit("TIMER:Illegal handler type"); if (timer->type!=T_MICRO) E_Exit("TIMER:Illegal handler type");
timer->micro.count=0;
timer->micro.total=micro; 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) { void TIMER_AddTick(void) {
/* Add pit ticks to the counter */ Bits index;
timer_buildup+=ticks*pit_ticks;
if (timer_buildup>MAX_PASSED) timer_buildup=MAX_PASSED;
/* Check if there are timer handlers that need to be called */ /* Check if there are timer handlers that need to be called */
Bitu add_micro=timer.ticks*1000;
std::list<Timer *>::iterator i; std::list<Timer *>::iterator i;
for(i=Timers.begin(); i != Timers.end(); ++i) { for(i=Timers.begin(); i != Timers.end(); ++i) {
Timer * timers=(*i); Timer * timers=(*i);
switch (timers->type) { switch (timers->type) {
case T_TICK: case T_TICK:
if (timer.ticks) timers->tick.handler(timer.ticks); timers->tick.handler(1);
break; break;
case T_MICRO: case T_MICRO:
timers->micro.count+=add_micro; index=1000;
if (timers->micro.count>=timers->micro.total) { while (index>=timers->micro.left) {
timers->micro.count-=timers->micro.total; PIC_AddEvent(timers->micro.handler,timers->micro.left);
timers->micro.handler(); index-=timers->micro.left;
} timers->micro.left=timers->micro.total;
break;
case T_DELAY:
/* Also unregister the timer handler from the list */
if (LastTicks>timers->delay.end) {
std::list<Timer *>::iterator remove;
timers->delay.handler();
remove=i++;
Timers.erase(remove);
} }
timers->micro.left-=index;
break; break;
default: default:
E_Exit("TIMER:Illegal handler type"); 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<TIMER_AVERAGE;l++) total+=timer.req[l];
timer.req_average=1/(total/TIMER_AVERAGE);
PIC_ActivateIRQ(0);
return;
} }
} }
void TIMER_Init(Section* sect) { void TIMER_Init(Section* sect) {
Bitu i;
IO_RegisterWriteHandler(0x40,write_latch,"PIT Timer 0"); IO_RegisterWriteHandler(0x40,write_latch,"PIT Timer 0");
IO_RegisterWriteHandler(0x42,write_latch,"PIT Timer 2"); IO_RegisterWriteHandler(0x42,write_latch,"PIT Timer 2");
IO_RegisterWriteHandler(0x43,write_p43,"PIT Mode Control"); IO_RegisterWriteHandler(0x43,write_p43,"PIT Mode Control");
@ -312,11 +273,9 @@ void TIMER_Init(Section* sect) {
pit[0].read_latch=-1; pit[0].read_latch=-1;
pit[0].write_latch=0; pit[0].write_latch=0;
pit[0].mode=3; pit[0].mode=3;
timer_ticks=pit[0].cntr << PIT_SHIFT;
timer_buildup=0; pit[0].micro=1000000/((float)PIT_TICK_RATE/(float)pit[0].cntr);
timer.req_index=0; pit[2].micro=100;
for (i=0;i<TIMER_AVERAGE;i++) timer.req[i]=0; PIC_AddEvent(PIT0_Event,pit[0].micro);
pit_ticks=(PIT_TICK_RATE << PIT_SHIFT)/1000;
PIC_RegisterIRQ(0,&TIMER_CheckPIT,"PIT 0 Timer");
} }

View File

@ -40,13 +40,72 @@ Bit32u FillTable[16]={
}; };
static void VGA_BlankTimer(void) {
PIC_AddEvent(&VGA_BlankTimer,vga.draw.blank);
Bit8u * buf,* bufsplit;
/* Draw the current frame */
if (!vga.draw.resizing && RENDER_StartUpdate()) {
if (vga.config.line_compare<vga.draw.lines) {
Bitu stop=vga.config.line_compare;
if (vga.draw.double_height) stop/=2;
if (stop>=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); norender:
void VGA_Render_GFX_256C(Bit8u * * data); RENDER_EndUpdate();
void VGA_Render_GFX_256U(Bit8u * * data);
void VGA_Render_TEXT_16(Bit8u * * data); }
VGA_StartRetrace();
}
void VGA_FindSettings(void) { void VGA_FindSettings(void) {
/* Sets up the correct memory handler from the vga.mode setting */ /* 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) { } else if (vga.config.cga_enabled) {
/* 4 color cga */ /* 4 color cga */
//TODO Detect hercules modes, probably set them up in bios too //TODO Detect hercules modes, probably set them up in bios too
if (vga.config.pixel_double) vga.mode=GFX_4; if (vga.seq.clocking_mode & 0x8) {
else vga.mode=GFX_2; 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 //TODO Maybe also use a page handler for cga mode
} else { } else {
/* 16 color ega */ /* 16 color ega */
@ -83,69 +144,96 @@ void VGA_FindSettings(void) {
} }
static void VGA_DoResize(void) { static void VGA_DoResize(void) {
vga.draw.resizing=false; /* Calculate the FPS for this screen */
Bitu width,height,pitch; double fps;
RENDER_Handler * renderer; 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; double clock=(double)vga.config.clock;
if (vga.config.vline_height>0) { /* Check for 8 for 9 character clock mode */
height/=(vga.config.vline_height+1); if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9;
} /* Check for pixel doubling, master clock/2 */
if (vga.config.vline_double) height>>=1; if (vga.seq.clocking_mode & 0x8) clock/=2;
width=vga.config.hdisplayend;
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) { switch (vga.mode) {
case GFX_256C: case GFX_256C:
renderer=&VGA_Render_GFX_256C;
width<<=2;
pitch=vga.config.scan_len*8;
break;
case GFX_256U: 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; width<<=2;
pitch=vga.config.scan_len*8; pitch=vga.config.scan_len*8;
renderer=&VGA_Render_GFX_256U;
break; break;
case GFX_16: case GFX_16:
width<<=3; width<<=3;
pitch=vga.config.scan_len*16; pitch=vga.config.scan_len*16;
renderer=&VGA_Render_GFX_16;
break; break;
case GFX_4: case GFX_4:
width<<=3; width<<=3;
height<<=1;
pitch=width; pitch=width;
renderer=&VGA_Render_GFX_4;
break; break;
case GFX_2: case GFX_2:
width<<=3; width<<=3;
height<<=1;
pitch=width; pitch=width;
renderer=&VGA_Render_GFX_2;
break; break;
case TEXT_16: case TEXT_16:
/* probably a 16-color text mode, got to detect mono mode somehow */ /* probably a 16-color text mode, got to detect mono mode somehow */
width<<=3; /* 8 bit wide text font */ width<<=3; /* 8 bit wide text font */
height<<=4; /* 16 bit font height */
if (width>640) width=640; if (width>640) width=640;
if (height>480) height=480; if (height>480) height=480;
pitch=width; 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; LOG_VGA("Width %d, Height %d",width,height);
vga.draw.height=height; LOG_VGA("Flags %X, fps %f",flags,fps);
RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),0,renderer); 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) { void VGA_StartResize(void) {
if (!vga.draw.resizing) { if (!vga.draw.resizing) {
vga.draw.resizing=true; vga.draw.resizing=true;
/* Start a resize after 50 ms */ /* Start a resize after 50 ms */
TIMER_RegisterDelayHandler(VGA_DoResize,50); PIC_AddEvent(VGA_DoResize,50000);
} }
} }
void VGA_Init(Section* sec) { void VGA_Init(Section* sec) {
vga.draw.resizing=false; vga.draw.resizing=false;
VGA_SetupMemory(); VGA_SetupMemory();

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2002 The DOSBox Team * Copyright (C) 2002 The DOSBox Team
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -20,13 +20,18 @@
#define VGA_H_ #define VGA_H_
#include <mem.h> #include <mem.h>
#include "dosbox.h"
#undef TEXT
#undef GRAPH
/* conflicts with int10.h */
enum { TEXT, GRAPH }; enum { TEXT, GRAPH };
enum { GFX_256C,GFX_256U,GFX_16,GFX_4,GFX_2, TEXT_16 }; enum { GFX_256C,GFX_256U,GFX_16,GFX_4,GFX_2, TEXT_16 };
typedef struct { typedef struct {
bool attrindex; bool attrindex;
Bit16u cursor;
} VGA_Internal; } VGA_Internal;
typedef struct { typedef struct {
@ -37,9 +42,11 @@ typedef struct {
bool retrace; /* A retrace has started */ bool retrace; /* A retrace has started */
Bitu scan_len; Bitu scan_len;
/* Screen resolution and memory mode */ /* Some other screen related variables */
Bitu vdisplayend; Bitu line_compare;
Bitu hdisplayend;
Bitu clock;
bool clock_half;
bool chained; /* Enable or Disabled Chain 4 Mode */ bool chained; /* Enable or Disabled Chain 4 Mode */
bool gfxmode; /* Yes or No Easy no */ bool gfxmode; /* Yes or No Easy no */
@ -51,7 +58,6 @@ typedef struct {
bool vline_double; bool vline_double;
Bit8u vline_height; Bit8u vline_height;
bool pixel_double;
/* Pixel Scrolling */ /* Pixel Scrolling */
Bit8u pel_panning; /* Amount of pixels to skip when starting horizontal line */ Bit8u pel_panning; /* Amount of pixels to skip when starting horizontal line */
Bit8u hlines_skip; Bit8u hlines_skip;
@ -80,11 +86,16 @@ typedef struct {
bool resizing; bool resizing;
Bitu width; Bitu width;
Bitu height; Bitu height;
Bitu pitch;
Bitu blank;
bool double_width;
bool double_height;
Bitu lines;
Bit8u * font;
Bit8u font_height; Bit8u font_height;
Bit8u cursor_enable; struct {
Bit8u cursor_row; Bitu row,col,sline,eline,count;
Bit8u cursor_col; } cursor;
Bit8u cursor_count;
} VGA_Draw; } VGA_Draw;
@ -157,7 +168,6 @@ struct RGBEntry {
Bit8u red; Bit8u red;
Bit8u green; Bit8u green;
Bit8u blue; Bit8u blue;
Bit8u attr_entry;
}; };
typedef struct { typedef struct {
@ -165,9 +175,11 @@ typedef struct {
Bit8u pel_mask; Bit8u pel_mask;
Bit8u pel_index; Bit8u pel_index;
Bit8u state; Bit8u state;
Bit8u index; Bit8u write_index;
Bit8u read_index;
Bitu first_changed; Bitu first_changed;
RGBEntry rgb[0x100]; RGBEntry rgb[0x100];
Bit8u attr[16];
} VGA_Dac; } VGA_Dac;
union VGA_Latch { union VGA_Latch {
@ -196,8 +208,8 @@ typedef struct {
VGA_Dac dac; VGA_Dac dac;
VGA_Latch latch; VGA_Latch latch;
VGA_Memory mem; VGA_Memory mem;
//Special little hack to let the memory run over into the buffer /* Extra buffer following main video ram with double data for overflowing of addresses */
Bit8u buffer[1024*1024]; Bit8u buffer[1024*1024]; /* 256 kb vid ram with 16 colors and double addresses */
} VGA_Type; } VGA_Type;
@ -211,11 +223,10 @@ void VGA_StartResize(void);
/* The Different Drawing functions */ /* The Different Drawing functions */
void VGA_DrawTEXT(Bit8u * bitdata,Bitu next_line); void VGA_DrawTEXT(Bit8u * bitdata,Bitu next_line);
void VGA_DrawGFX256_Fast(Bit8u * bitdata,Bitu next_line); void VGA_DrawGFX256U_Full(Bit8u * bitdata,Bitu next_line);
void VGA_DrawGFX256_Full(Bit8u * bitdata,Bitu next_line); void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line);
void VGA_DrawGFX16_Full(Bit8u * bitdata,Bitu next_line); void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu next_line);
void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu next_line); void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu next_line);
void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu next_line);
/* The Different Memory Read/Write Handlers */ /* The Different Memory Read/Write Handlers */
Bit8u VGA_NormalReadHandler(Bit32u start); Bit8u VGA_NormalReadHandler(Bit32u start);
@ -242,9 +253,10 @@ void VGA_SetupSEQ(void);
/* Some Support Functions */ /* Some Support Functions */
void VGA_DACSetEntirePalette(void); void VGA_DACSetEntirePalette(void);
void VGA_StartRetrace(void);
extern VGA_Type vga; 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_14[256 * 14];
extern Bit8u vga_rom_16[256 * 16]; extern Bit8u vga_rom_16[256 * 16];
@ -260,6 +272,5 @@ extern Bit32u Expand16BigTable[0x10000];
#define LOG_VGA #define LOG_VGA
#endif #endif
#endif #endif

View File

@ -40,6 +40,7 @@ void write_p3c0(Bit32u port,Bit8u val) {
case 0x04: case 0x05: case 0x06: case 0x07: case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
val&=0x3f;
attr(palette[attr(index)])=val; attr(palette[attr(index)])=val;
VGA_DAC_CombineColor(attr(index),val); VGA_DAC_CombineColor(attr(index),val);
/* /*
@ -48,10 +49,12 @@ void write_p3c0(Bit32u port,Bit8u val) {
*/ */
break; break;
case 0x10: /* Mode Control Register */ case 0x10: /* Mode Control Register */
attr(mode_control)=val; if (val != attr(mode_control)) {
vga.config.gfxmode=val&1; attr(mode_control)=val;
vga.config.vga_enabled=(val & 64)>0; vga.config.gfxmode=val&1;
VGA_FindSettings(); vga.config.vga_enabled=(val & 0x40)>0;
VGA_FindSettings();
}
//TODO Monochrome mode //TODO Monochrome mode
//TODO 9 bit characters //TODO 9 bit characters
//TODO line wrapping split screen shit see bit 5 //TODO line wrapping split screen shit see bit 5

View File

@ -40,9 +40,10 @@ void write_p3d5(Bit32u port,Bit8u val) {
/* 0-7 Horizontal Total Character Clocks-5 */ /* 0-7 Horizontal Total Character Clocks-5 */
break; break;
case 0x01: /* Horizontal Display End Register */ case 0x01: /* Horizontal Display End Register */
crtc(horizontal_display_end)=val; if (val != crtc(horizontal_display_end)) {
vga.config.hdisplayend=val+1; crtc(horizontal_display_end)=val;
VGA_StartResize(); VGA_StartResize();
}
/* 0-7 Number of Character Clocks Displayed -1 */ /* 0-7 Number of Character Clocks Displayed -1 */
break; break;
case 0x02: /* Start Horizontal Blanking Register */ case 0x02: /* Start Horizontal Blanking Register */
@ -75,7 +76,10 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/ */
break; break;
case 0x06: /* Vertical Total Register */ 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 /* 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. 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. 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; break;
case 0x07: /* Overflow Register */ case 0x07: /* Overflow Register */
crtc(overflow)=val; crtc(overflow)=val;
vga.config.vdisplayend=(vga.config.vdisplayend&0xFF)|(((val>>1) & 1)<<8)|(((val>>6) & 1)<<9); vga.config.line_compare=(vga.config.line_compare & 0x2ff) | (val & 0x10) << 4;
VGA_StartResize(); if ((vga.crtc.overflow ^ val) & 0xef) {
crtc(overflow)=val;
VGA_StartResize();
} else crtc(overflow)=val;
/* /*
0 Bit 8 of Vertical Total (3d4h index 6) 0 Bit 8 of Vertical Total (3d4h index 6)
1 Bit 8 of Vertical Display End (3d4h index 12h) 1 Bit 8 of Vertical Display End (3d4h index 12h)
@ -110,10 +117,13 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/ */
break; break;
case 0x09: /* Maximum Scan Line Register */ case 0x09: /* Maximum Scan Line Register */
crtc(maximum_scan_line)=val;
vga.config.vline_double=(val & 128)>1; vga.config.vline_double=(val & 128)>1;
vga.config.vline_height=(val & 0xf); 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 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 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 */ case 0x0E: /*Cursor Location High Register */
crtc(cursor_location_high)=val; crtc(cursor_location_high)=val;
if (vga.config.scan_len<2) break; 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.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.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 */ /* 0-7 Upper 8 bits of the address of the cursor */
break; break;
case 0x0F: /* Cursor Location Low Register */ case 0x0F: /* Cursor Location Low Register */
//TODO update cursor on screen //TODO update cursor on screen
crtc(cursor_location_low)=val; crtc(cursor_location_low)=val;
if (vga.config.scan_len<2) break; 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.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.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 */ /* 0-7 Lower 8 bits of the address of the cursor */
break; break;
case 0x10: /* Vertical Retrace Start Register */ case 0x10: /* Vertical Retrace Start Register */
@ -186,9 +196,10 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/ */
break; break;
case 0x12: /* Vertical Display End Register */ case 0x12: /* Vertical Display End Register */
crtc(vertical_display_end)=val; if (val!=crtc(vertical_display_end)) {
vga.config.vdisplayend=(vga.config.vdisplayend & 0x300)|val; crtc(vertical_display_end)=val;
VGA_StartResize(); VGA_StartResize();
}
/* /*
0-7 Lower 8 bits of Vertical Display End. The display ends when the line 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. 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; break;
case 0x13: /* Offset register */ case 0x13: /* Offset register */
crtc(offset)=val; if (val!=crtc(offset)) {
vga.config.scan_len=val; crtc(offset)=val;
VGA_StartResize(); 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 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. word mode and 8 for Double Word mode.
@ -228,9 +241,11 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/ */
break; break;
case 0x17: /* Mode Control Register */ case 0x17: /* Mode Control Register */
crtc(mode_control)=val; if (val!=crtc(mode_control)) {
vga.config.cga_enabled=!((val&1)>0); crtc(mode_control)=val;
VGA_FindSettings(); vga.config.cga_enabled=!((val&1)>0);
VGA_FindSettings();
}
/* /*
0 If clear use CGA compatible memory addressing system 0 If clear use CGA compatible memory addressing system
by substituting character row scan counter bit 0 for address bit 13, by substituting character row scan counter bit 0 for address bit 13,
@ -249,6 +264,7 @@ void write_p3d5(Bit32u port,Bit8u val) {
break; break;
case 0x18: /* Line Compare Register */ case 0x18: /* Line Compare Register */
crtc(line_compare)=val; 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 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 value, the display address wraps to 0. Provides Split Screen

View File

@ -65,13 +65,13 @@ static Bit8u read_p3c6(Bit32u port) {
static void write_p3c7(Bit32u port,Bit8u val) { static void write_p3c7(Bit32u port,Bit8u val) {
vga.dac.index=val; vga.dac.read_index=val;
vga.dac.pel_index=0; vga.dac.pel_index=0;
vga.dac.state=DAC_READ; vga.dac.state=DAC_READ;
} }
static void write_p3c8(Bit32u port,Bit8u val) { static void write_p3c8(Bit32u port,Bit8u val) {
vga.dac.index=val; vga.dac.write_index=val;
vga.dac.pel_index=0; vga.dac.pel_index=0;
vga.dac.state=DAC_WRITE; 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) { static void write_p3c9(Bit32u port,Bit8u val) {
switch (vga.dac.pel_index) { switch (vga.dac.pel_index) {
case 0: case 0:
vga.dac.rgb[vga.dac.index].red=val; vga.dac.rgb[vga.dac.write_index].red=val;
vga.dac.pel_index=1; vga.dac.pel_index=1;
break; break;
case 1: case 1:
vga.dac.rgb[vga.dac.index].green=val; vga.dac.rgb[vga.dac.write_index].green=val;
vga.dac.pel_index=2; vga.dac.pel_index=2;
break; break;
case 2: case 2:
vga.dac.rgb[vga.dac.index].blue=val; vga.dac.rgb[vga.dac.write_index].blue=val;
switch (vga.mode) { switch (vga.mode) {
case GFX_256C: case GFX_256C:
case GFX_256U: case GFX_256U:
RENDER_SetPal(vga.dac.index, RENDER_SetPal(vga.dac.write_index,
vga.dac.rgb[vga.dac.index].red << 2, vga.dac.rgb[vga.dac.write_index].red << 2,
vga.dac.rgb[vga.dac.index].green << 2, vga.dac.rgb[vga.dac.write_index].green << 2,
vga.dac.rgb[vga.dac.index].blue << 2 vga.dac.rgb[vga.dac.write_index].blue << 2
); );
break; break;
default: default:
/* Check for attributes and DAC entry link */ /* Check for attributes and DAC entry link */
if (vga.dac.rgb[vga.dac.index].attr_entry>15) return; for (Bitu i=0;i<16;i++) {
if (vga.attr.palette[vga.dac.rgb[vga.dac.index].attr_entry]==vga.dac.index) { if (vga.dac.attr[i]==vga.dac.write_index) {
RENDER_SetPal(vga.dac.rgb[vga.dac.index].attr_entry, RENDER_SetPal(i,
vga.dac.rgb[vga.dac.index].red << 2, vga.dac.rgb[vga.dac.write_index].red << 2,
vga.dac.rgb[vga.dac.index].green << 2, vga.dac.rgb[vga.dac.write_index].green << 2,
vga.dac.rgb[vga.dac.index].blue << 2 vga.dac.rgb[vga.dac.write_index].blue << 2);
); }
} }
} }
vga.dac.index++; vga.dac.write_index++;
vga.dac.pel_index=0; vga.dac.pel_index=0;
break; break;
default: default:
@ -120,16 +120,16 @@ static Bit8u read_p3c9(Bit32u port) {
Bit8u ret; Bit8u ret;
switch (vga.dac.pel_index) { switch (vga.dac.pel_index) {
case 0: case 0:
ret=vga.dac.rgb[vga.dac.index].red; ret=vga.dac.rgb[vga.dac.read_index].red;
vga.dac.pel_index=1; vga.dac.pel_index=1;
break; break;
case 1: case 1:
ret=vga.dac.rgb[vga.dac.index].green; ret=vga.dac.rgb[vga.dac.read_index].green;
vga.dac.pel_index=2; vga.dac.pel_index=2;
break; break;
case 2: case 2:
ret=vga.dac.rgb[vga.dac.index].blue; ret=vga.dac.rgb[vga.dac.read_index].blue;
vga.dac.index++; vga.dac.read_index++;
vga.dac.pel_index=0; vga.dac.pel_index=0;
break; break;
default: default:
@ -140,7 +140,8 @@ static Bit8u read_p3c9(Bit32u port) {
void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) { void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) {
/* Check if this is a new color */ /* 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, RENDER_SetPal(attr,
vga.dac.rgb[pal].red << 2, vga.dac.rgb[pal].red << 2,
vga.dac.rgb[pal].green << 2, vga.dac.rgb[pal].green << 2,
@ -154,6 +155,8 @@ void VGA_SetupDAC(void) {
vga.dac.pel_mask=0xff; vga.dac.pel_mask=0xff;
vga.dac.pel_index=0; vga.dac.pel_index=0;
vga.dac.state=DAC_READ; vga.dac.state=DAC_READ;
vga.dac.read_index=0;
vga.dac.write_index=0;
/* Setup the DAC IO port Handlers */ /* Setup the DAC IO port Handlers */
IO_RegisterWriteHandler(0x3c6,write_p3c6,"PEL Mask"); IO_RegisterWriteHandler(0x3c6,write_p3c6,"PEL Mask");

View File

@ -21,43 +21,11 @@
#include "video.h" #include "video.h"
#include "vga.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_DrawGFX2_Fast(Bit8u * bitdata,Bitu pitch) {
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) {
Bit8u * reader=HostMake(0xB800,0); Bit8u * reader=HostMake(0xB800,0);
Bit8u * flip=HostMake(0xB800,8*1024);
Bit8u * draw; Bit8u * draw;
for (Bitu y=0;y<vga.draw.height;y++) { for (Bitu y=0;y<vga.draw.height;y++) {
Bit8u * tempread; Bit8u * tempread;
@ -68,7 +36,7 @@ void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu pitch) {
}; };
draw=bitdata; draw=bitdata;
//TODO Look up table like in 4color mode //TODO Look up table like in 4color mode
for (Bit32u x=0;x<vga.draw.width>>3;x++) { for (Bit32u x=vga.draw.width>>3;x>0;x--) {
Bit8u val=*(tempread++); Bit8u val=*(tempread++);
*(draw+0)=(val>>7)&1; *(draw+0)=(val>>7)&1;
*(draw+1)=(val>>6)&1; *(draw+1)=(val>>6)&1;
@ -81,14 +49,12 @@ void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu pitch) {
draw+=8; draw+=8;
} }
bitdata+=pitch; bitdata+=pitch;
}; }
vga.config.retrace=true;
} }
void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu pitch) {
Bit8u * reader=HostMake(0xB800,vga.config.display_start*2);
void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) { Bit8u * flip=HostMake(0xB800,8*1024);
Bit8u * reader=HostMake(0xB800,0);
Bit8u * draw; Bit8u * draw;
for (Bitu y=0;y<vga.draw.height;y++) { for (Bitu y=0;y<vga.draw.height;y++) {
Bit8u * tempread; Bit8u * tempread;
@ -96,7 +62,8 @@ void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) {
if (y&1) { if (y&1) {
tempread+=8*1024; tempread+=8*1024;
reader+=80; reader+=80;
}; if (reader>=flip) reader-=8*1024;
}
draw=bitdata; draw=bitdata;
for (Bit32u x=0;x<vga.draw.width>>2;x++) { for (Bit32u x=0;x<vga.draw.width>>2;x++) {
Bit8u val=*(tempread++); Bit8u val=*(tempread++);
@ -104,12 +71,10 @@ void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) {
draw+=4; draw+=4;
} }
bitdata+=pitch; bitdata+=pitch;
}; }
vga.config.retrace=true;
} }
/* Draw the screen using the lookup buffer */ /* Draw the screen using the lookup buffer */
//TODO include split screen or something
void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line) { void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line) {
Bit8u * reader=&vga.buffer[vga.config.display_start*8+vga.config.pel_panning]; Bit8u * reader=&vga.buffer[vga.config.display_start*8+vga.config.pel_panning];
for (Bitu y=0;y<vga.draw.height;y++) { for (Bitu y=0;y<vga.draw.height;y++) {
@ -117,12 +82,9 @@ void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line) {
bitdata+=vga.draw.width+next_line; bitdata+=vga.draw.width+next_line;
reader+=vga.config.scan_len*16; reader+=vga.config.scan_len*16;
} }
vga.config.retrace=true; }
};
void VGA_DrawGFX256U_Fast(Bit8u * bitdata,Bitu next_line) {
void VGA_DrawGFX256_Full(Bit8u * bitdata,Bitu next_line) {
Bit16u yreader=vga.config.display_start*1; Bit16u yreader=vga.config.display_start*1;
/* TODO add pel panning */ /* TODO add pel panning */
for (Bitu y=0;y<vga.draw.height;y++) { for (Bitu y=0;y<vga.draw.height;y++) {
@ -135,25 +97,12 @@ void VGA_DrawGFX256_Full(Bit8u * bitdata,Bitu next_line) {
} }
yreader+=vga.config.scan_len*2; yreader+=vga.config.scan_len*2;
bitdata+=next_line; bitdata+=next_line;
};
vga.config.retrace=true;
};
void VGA_DrawGFX256_Fast(Bit8u * bitdata,Bitu pitch) {
/* For now just copy 64 kb of memory with pitch support */
Bit8u * reader=memory+0xa0000;
for (Bitu y=0;y<vga.draw.height;y++) {
memcpy((void *)bitdata,(void *)reader,vga.draw.width);
bitdata+=pitch;
reader+=vga.draw.width;
} }
vga.config.retrace=true; }
};
void VGA_DrawTEXT(Bit8u * bitdata,Bitu pitch) { void VGA_DrawTEXT(Bit8u * bitdata,Bitu pitch) {
Bit8u * reader=HostMake(0xB800,0); Bit8u * reader=HostMake(0xB800,0);
Bit8u * draw_start=bitdata;; Bit8u * draw_start=bitdata;
/* Todo Blinking and high intensity colors */ /* Todo Blinking and high intensity colors */
for (Bitu cy=0;cy<(vga.draw.height/16);cy++) { for (Bitu cy=0;cy<(vga.draw.height/16);cy++) {
Bit8u * draw_char=draw_start; Bit8u * draw_char=draw_start;
@ -173,16 +122,16 @@ void VGA_DrawTEXT(Bit8u * bitdata,Bitu pitch) {
}; };
draw_start+=16*pitch; draw_start+=16*pitch;
}; };
vga.config.retrace=true; if(!(vga.internal.cursor & 0x2000)) {
/* Draw a cursor */
/* Draw a cursor */ if (((Bitu)vga.draw.cursor.col*8)>=vga.draw.width) return;
if (((Bitu)vga.draw.cursor_col*8)>=vga.draw.width) return; if (((Bitu)vga.draw.cursor.row*16)>=vga.draw.height) 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;
Bit8u * cursor_draw=bitdata+(vga.draw.cursor_row*16+15)*pitch+vga.draw.cursor_col*8; if (vga.draw.cursor.count>8) {
if (vga.draw.cursor_count>8) { for (Bit8u loop=0;loop<8;loop++) *cursor_draw++=15;
for (Bit8u loop=0;loop<8;loop++) *cursor_draw++=15; }
} vga.draw.cursor.count++;
vga.draw.cursor_count++; if (vga.draw.cursor.count>16) vga.draw.cursor.count=0;
if (vga.draw.cursor_count>16) vga.draw.cursor_count=0; }
}; };

View File

@ -70,6 +70,7 @@ void write_p3cf(Bit32u port,Bit8u val) {
case 3: /* Data Rotate */ case 3: /* Data Rotate */
gfx(data_rotate)=val; gfx(data_rotate)=val;
vga.config.data_rotate=val & 7; 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; vga.config.raster_op=(val>>3) & 3;
/* /*
0-2 Number of positions to rotate data right before it is written to 0-2 Number of positions to rotate data right before it is written to

View File

@ -92,20 +92,21 @@ INLINE static Bit32u ModeOperation(Bit8u val) {
} }
Bit8u VGA_GFX_4_ReadHandler(Bit32u start) { 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) { void VGA_GFX_4_WriteHandler(Bit32u start,Bit8u val) {
start-=0xa0000; start-=0xb8000;
vga.mem.linear[start]=val; vga.mem.linear[start]=val;
Bitu line=start / 320; Bitu off;
Bitu x=start % 320; if (start>0x2000) off=320*(((start-0x2000)/80)*2+1)+((start-0x2000) % 80)*4;
Bit8u * draw=&vga.buffer[start<<2]; 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 */ /* TODO Could also use a Bit32u lookup table for this */
*(draw+0)=(val>>6)&3; *draw=CGAWriteTable[val];
*(draw+1)=(val>>4)&3; draw=(Bit32u *)&vga.buffer[off+0x4000*4];
*(draw+2)=(val>>2)&3; *draw=CGAWriteTable[val];
*(draw+3)=(val)&3;
} }
void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val) { void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val) {

View File

@ -18,9 +18,10 @@
#include "dosbox.h" #include "dosbox.h"
#include "inout.h" #include "inout.h"
#include "timer.h" #include "pic.h"
#include "vga.h" #include "vga.h"
static Bit8u flip=0; static Bit8u flip=0;
static Bit32u keep_vretrace; static Bit32u keep_vretrace;
static bool keeping=false; static bool keeping=false;
@ -34,22 +35,12 @@ Bit8u read_p3d5(Bit32u port);
static Bit8u read_p3da(Bit32u port) { static Bit8u read_p3da(Bit32u port) {
vga.internal.attrindex=false; vga.internal.attrindex=false;
if (vga.config.retrace) { 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; return 9;
} }
if (keeping) { flip++;
if (LastTicks>(keep_vretrace)) keeping=false; if (flip>10) flip=0;
return 9; if (flip>5) return 1;
} else { return 0;
flip++;
if (flip>10) flip=0;
if (flip>5) return 1;
return 0;
}
/* /*
0 Either Vertical or Horizontal Retrace active if set 0 Either Vertical or Horizontal Retrace active if set
3 Vertical Retrace in progress 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) { 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 3 Vertical Sync Select. If set Vertical Sync to the monitor is the
logical OR of the vertical sync and the vertical display enable. 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) { static void write_p3c2(Bit32u port,Bit8u val) {
p3c2data=val; p3c2data=val;
if (val & 1) {
if (val & 0x1) {
IO_RegisterWriteHandler(0x3d4,write_p3d4,"VGA:CRTC Index Select"); IO_RegisterWriteHandler(0x3d4,write_p3d4,"VGA:CRTC Index Select");
IO_RegisterReadHandler(0x3d4,read_p3d4,"VGA:CRTC Index Select"); IO_RegisterReadHandler(0x3d4,read_p3d4,"VGA:CRTC Index Select");
IO_RegisterWriteHandler(0x3d5,write_p3d5,"VGA:CRTC Data Register"); 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_FreeReadHandler(0x3b4);
IO_FreeWriteHandler(0x3b5); IO_FreeWriteHandler(0x3b5);
IO_FreeReadHandler(0x3b5); IO_FreeReadHandler(0x3b5);
} else { } else {
IO_RegisterWriteHandler(0x3b4,write_p3d4,"VGA:CRTC Index Select"); IO_RegisterWriteHandler(0x3b4,write_p3d4,"VGA:CRTC Index Select");
IO_RegisterReadHandler(0x3b4,read_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_FreeWriteHandler(0x3d5);
IO_FreeReadHandler(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. 0 If set Color Emulation. Base Address=3Dxh else Mono Emulation. Base Address=3Bxh.
2-3 Clock Select. 0: 25MHz, 1: 28MHz 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) { void VGA_SetupMisc(void) {
IO_RegisterReadHandler(0x3da,read_p3da,"VGA Input Status 1"); IO_RegisterReadHandler(0x3da,read_p3da,"VGA Input Status 1");
IO_RegisterReadHandler(0x3ba,read_p3da,"VGA Input Status 1"); IO_RegisterReadHandler(0x3ba,read_p3da,"VGA Input Status 1");

View File

@ -36,9 +36,10 @@ void write_p3c5(Bit32u port,Bit8u val) {
seq(reset)=val; seq(reset)=val;
break; break;
case 1: /* Clocking Mode */ case 1: /* Clocking Mode */
seq(clocking_mode)=val; if (val!=seq(clocking_mode)) {
vga.config.pixel_double=(val & 8)>0; seq(clocking_mode)=val;
VGA_FindSettings(); VGA_StartResize();
}
/* TODO Figure this out :) /* TODO Figure this out :)
0 If set character clocks are 8 dots wide, else 9. 0 If set character clocks are 8 dots wide, else 9.
2 If set loads video serializers every other character 2 If set loads video serializers every other character

View File

@ -22,9 +22,10 @@
#include "callback.h" #include "callback.h"
#include "inout.h" #include "inout.h"
#include "mem.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_int1a,call_int11,call_int8,call_int17,call_int12,call_int15,call_int1c;
static Bitu call_int1;
static Bitu INT1A_Handler(void) { static Bitu INT1A_Handler(void) {
switch (reg_ah) { switch (reg_ah) {
@ -104,9 +105,19 @@ static Bitu INT8_Handler(void) {
/* decrease floppy motor timer */ /* decrease floppy motor timer */
Bit8u val = mem_readb(BIOS_DISK_MOTOR_TIMEOUT); Bit8u val = mem_readb(BIOS_DISK_MOTOR_TIMEOUT);
if (val>0) mem_writeb(BIOS_DISK_MOTOR_TIMEOUT,val-1); 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); CALLBACK_RunRealInt(0x1c);
IO_Write(0x20,0x20); IO_Write(0x20,0x20);
// restore old values
SegSet16(ds,oldds);
reg_dx = olddx;
reg_ax = oldax;
return CBRET_NONE; 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_POINTER,RealMake(SegValue(es),reg_bx));
mem_writed(BIOS_WAIT_FLAG_COUNT,reg_cx<<16|reg_dx); mem_writed(BIOS_WAIT_FLAG_COUNT,reg_cx<<16|reg_dx);
mem_writeb(BIOS_WAIT_FLAG_ACTIVE,1); 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; break;
case 0x84: /* BIOS - JOYSTICK SUPPORT (XT after 11/8/82,AT,XT286,PS) */ case 0x84: /* BIOS - JOYSTICK SUPPORT (XT after 11/8/82,AT,XT286,PS) */
//Does anyone even use this? //Does anyone even use this?
@ -177,7 +189,11 @@ static Bitu INT15_Handler(void) {
CALLBACK_SCF(false); CALLBACK_SCF(false);
break; break;
case 0x90: /* OS HOOK - DEVICE BUSY */ 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; reg_ah=0;
break; break;
case 0xc2: /* BIOS PS2 Pointing Device Support */ case 0xc2: /* BIOS PS2 Pointing Device Support */
@ -197,12 +213,16 @@ static Bitu INT15_Handler(void) {
CALLBACK_SCF(false); CALLBACK_SCF(false);
} }
return CBRET_NONE; 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_SetupKeyboard(void);
void BIOS_SetupDisks(void); void BIOS_SetupDisks(void);
@ -244,13 +264,20 @@ void BIOS_Init(Section* sec) {
RealSetVec(0x17,CALLBACK_RealPointer(call_int17)); RealSetVec(0x17,CALLBACK_RealPointer(call_int17));
/* INT 1A TIME and some other functions */ /* INT 1A TIME and some other functions */
call_int1a=CALLBACK_Allocate(); 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)); RealSetVec(0x1A,CALLBACK_RealPointer(call_int1a));
/* INT 1C System Timer tick called from INT 8 */ /* 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); CALLBACK_Setup(call_int1c,&INT1C_Handler,CB_IRET);
RealSetVec(0x1C,CALLBACK_RealPointer(call_int1c)); 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);
} }

View File

@ -21,7 +21,7 @@
#include "bios.h" #include "bios.h"
#include "regs.h" #include "regs.h"
#include "mem.h" #include "mem.h"
#include "dos_inc.h" /* for Drives[] */
static Bitu call_int13; static Bitu call_int13;
static BIOS_Disk * Floppys[2]; static BIOS_Disk * Floppys[2];
@ -31,11 +31,28 @@ static Bit8u last_status;
static Bitu INT13_SmallHandler(void) { static Bitu INT13_SmallHandler(void) {
switch (reg_ah) { switch (reg_ah) {
case 0x0:
reg_ah=0x00;
CALLBACK_SCF(false);
LOG_DEBUG("reset disk return succesfull");
break;
case 0x02: /* Read Disk Sectors */ case 0x02: /* Read Disk Sectors */
LOG_DEBUG("INT13:02:Read Disk Sectors not supported failing"); LOG_DEBUG("INT13:02:Read Disk Sectors not supported failing");
reg_ah=0xff; reg_ah=0x80;
CALLBACK_SCF(true); CALLBACK_SCF(true);
break; 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 */ case 0x08: /* Get Drive Parameters */
LOG_DEBUG("INT13:08:Get Drive parameters not supported failing"); LOG_DEBUG("INT13:08:Get Drive parameters not supported failing");
reg_ah=0xff; reg_ah=0xff;

View File

@ -293,7 +293,7 @@ static Bitu INT16_Handler(void) {
//TODO find a more elegant way to do this //TODO find a more elegant way to do this
do { do {
temp=get_key(); temp=get_key();
if (temp==0) { flags.intf=true;CALLBACK_Idle();}; if (temp==0) { CALLBACK_Idle();};
} while (temp==0); } while (temp==0);
reg_ax=temp; reg_ax=temp;
break; break;
@ -354,7 +354,7 @@ void BIOS_SetupKeyboard(void) {
/* Allocate a callback for int 0x16 and for standard IRQ 1 handler */ /* Allocate a callback for int 0x16 and for standard IRQ 1 handler */
call_int16=CALLBACK_Allocate(); call_int16=CALLBACK_Allocate();
call_irq1=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)); RealSetVec(0x16,CALLBACK_RealPointer(call_int16));
CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRET); CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRET);
RealSetVec(0x9,CALLBACK_RealPointer(call_irq1)); RealSetVec(0x9,CALLBACK_RealPointer(call_irq1));

View File

@ -34,7 +34,7 @@
#define EMM_PAGEFRAME 0xE000 #define EMM_PAGEFRAME 0xE000
#define EMM_MAX_HANDLES 50 /* 255 Max */ #define EMM_MAX_HANDLES 50 /* 255 Max */
#define EMM_PAGE_SIZE (16*1024) #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_MAX_PHYS 4 /* 4 16kb pages in pageframe */
#define EMM_VERSION 0x40 #define EMM_VERSION 0x40
@ -83,7 +83,7 @@ struct EMM_Mapping {
}; };
struct EMM_Page { struct EMM_Page {
void * memory; HostPt * memory;
Bit16u handle; Bit16u handle;
Bit16u next; Bit16u next;
}; };
@ -91,7 +91,7 @@ struct EMM_Page {
struct EMM_Handle { struct EMM_Handle {
Bit16u first_page; Bit16u first_page;
Bit16u pages; Bit16u pages;
char name[9]; char name[8];
bool saved_page_map; bool saved_page_map;
EMM_Mapping page_map[EMM_MAX_PHYS]; 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_Page emm_pages[EMM_MAX_PAGES];
static EMM_Mapping emm_mappings[EMM_MAX_PHYS]; static EMM_Mapping emm_mappings[EMM_MAX_PHYS];
static HostPt emm_pagebase[EMM_MAX_PHYS]; static HostPt emm_pagebase[EMM_MAX_PHYS];
static Bitu emm_page_count;
Bitu call_int67; 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 #if EMM_USEHANDLER
Bit8u EMM_ReadHandler(PhysPt start) { Bit8u EMM_ReadHandler(PhysPt start) {
start-=EMM_PAGEFRAME * 16; start-=EMM_PAGEFRAME * 16;
@ -118,12 +131,18 @@ void EMM_WriteHandler(PhysPt start,Bit8u val) {
static Bit16u EMM_GetFreePages(void) { static Bit16u EMM_GetFreePages(void) {
Bit16u count=0; Bit16u count=0;
for (Bitu index=0;index<EMM_MAX_PAGES;index++) { for (Bitu index=0;index<emm_page_count;index++) {
if (emm_pages[index].handle==NULL_HANDLE) count++; if (emm_pages[index].handle==NULL_HANDLE) count++;
} }
return count; return count;
} }
static bool INLINE ValidHandle(Bit16u handle) {
if (handle>=EMM_MAX_HANDLES) return false;
if (emm_handles[handle].pages==NULL_HANDLE) return false;
return true;
}
static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) { static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) {
/* Check for 0 page allocation */ /* Check for 0 page allocation */
if (!pages) return EMM_ZERO_PAGES; if (!pages) return EMM_ZERO_PAGES;
@ -140,14 +159,14 @@ static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) {
while (pages) { while (pages) {
if (emm_pages[page].handle==NULL_HANDLE) { if (emm_pages[page].handle==NULL_HANDLE) {
emm_pages[page].handle=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 (!emm_pages[page].memory) E_Exit("EMM:Cannont allocate memory");
if (last!=NULL_PAGE) emm_pages[last].next=page; if (last!=NULL_PAGE) emm_pages[last].next=page;
else emm_handles[handle].first_page=page; else emm_handles[handle].first_page=page;
last=page; last=page;
pages--; pages--;
} else { } 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; return EMM_NO_ERROR;
@ -190,14 +209,14 @@ static Bit8u EMM_ReallocatePages(Bit16u handle,Bit16u & pages) {
while (pages) { while (pages) {
if (emm_pages[page].handle==NULL_HANDLE) { if (emm_pages[page].handle==NULL_HANDLE) {
emm_pages[page].handle=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 (!emm_pages[page].memory) E_Exit("EMM:Cannont allocate memory");
if (last!=NULL_PAGE) emm_pages[last].next=page; if (last!=NULL_PAGE) emm_pages[last].next=page;
else emm_handles[handle].first_page=page; else emm_handles[handle].first_page=page;
last=page; last=page;
pages--; pages--;
} else { } 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; 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].first_page=NULL_PAGE;
emm_handles[handle].pages=NULL_HANDLE; emm_handles[handle].pages=NULL_HANDLE;
emm_handles[handle].saved_page_map=false; 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; 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); LOG_ERROR("EMS:Call %2X Subfunction %2X not supported",reg_ah,reg_al);
return EMM_FUNC_NOSUP; 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;handle<EMM_MAX_HANDLES;handle++) {
if (emm_handles[handle].pages!=NULL_HANDLE) {
reg_al++;
mem_writew(data,handle);
MEM_BlockWrite(data+2,emm_handles[handle].name,8);
data+=10;
}
}
break;
default:
LOG_ERROR("EMS:Call %2X Subfunction %2X not supported",reg_ah,reg_al);
return EMM_FUNC_NOSUP;
}
return EMM_NO_ERROR;
}
static void LoadMoveRegion(PhysPt data,MoveRegion & region) {
region.bytes=mem_readd(data+0x0);
region.src_type=mem_readb(data+0x4);
region.src_handle=mem_readw(data+0x5);
region.src_offset=mem_readw(data+0x7);
region.src_page_seg=mem_readw(data+0x9);
region.dest_type=mem_readb(data+0xb);
region.dest_handle=mem_readw(data+0xc);
region.dest_offset=mem_readw(data+0xe);
region.dest_page_seg=mem_readw(data+0x10);
}
static Bit8u MemoryRegion(void) {
MoveRegion region;
Bit8u buf_src[EMM_PAGE_SIZE];
Bit8u buf_dest[EMM_PAGE_SIZE];
if (reg_al>1) {
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<src_remain) {
memcpy(buf_src,emm_pages[src_page].memory+src_off,toread);
} else {
memcpy(buf_src,emm_pages[src_page].memory+src_off,src_remain);
memcpy(buf_src+src_remain,emm_pages[emm_pages[src_page].next].memory,toread-src_remain);
}
}
/* Check for a move */
if (reg_al==1) {
/* Read from the destination */
if (!region.dest_type) {
MEM_BlockRead(dest_mem,buf_dest,toread);
} else {
if (toread<dest_remain) {
memcpy(buf_dest,emm_pages[dest_page].memory+dest_off,toread);
} else {
memcpy(buf_dest,emm_pages[dest_page].memory+dest_off,dest_remain);
memcpy(buf_dest+dest_remain,emm_pages[emm_pages[dest_page].next].memory,toread-dest_remain);
}
}
/* Write to the source */
if (!region.src_type) {
MEM_BlockWrite(src_mem,buf_dest,toread);
} else {
if (toread<(EMM_PAGE_SIZE-src_off)) {
memcpy(emm_pages[src_page].memory+src_off,buf_dest,toread);
} else {
memcpy(emm_pages[src_page].memory+src_off,buf_dest,EMM_PAGE_SIZE-src_off);
memcpy(emm_pages[emm_pages[src_page].next].memory,buf_dest+EMM_PAGE_SIZE-src_off,toread-(EMM_PAGE_SIZE-src_off));
}
}
}
/* Write to the destination */
if (!region.dest_type) {
MEM_BlockWrite(dest_mem,buf_src,toread);
} else {
if (toread<dest_remain) {
memcpy(emm_pages[dest_page].memory+dest_off,buf_src,toread);
} else {
memcpy(emm_pages[dest_page].memory+dest_off,buf_src,dest_remain);
memcpy(emm_pages[emm_pages[dest_page].next].memory,buf_src+dest_remain,toread-dest_remain);
}
}
/* Advance the pointers */
if (!region.src_type) src_mem+=toread;
else src_page=emm_pages[src_page].next;
if (!region.dest_type) dest_mem+=toread;
else dest_page=emm_pages[dest_page].next;
region.bytes-=toread;
}
return EMM_NO_ERROR;
}
static Bitu INT67_Handler(void) { static Bitu INT67_Handler(void) {
Bitu i; Bitu i;
@ -366,7 +519,7 @@ static Bitu INT67_Handler(void) {
reg_ah=EMM_NO_ERROR; reg_ah=EMM_NO_ERROR;
break; break;
case 0x42: /* Get number of pages */ case 0x42: /* Get number of pages */
reg_dx=EMM_MAX_PAGES; reg_dx=emm_page_count;
reg_bx=EMM_GetFreePages(); reg_bx=EMM_GetFreePages();
reg_ah=EMM_NO_ERROR; reg_ah=EMM_NO_ERROR;
break; break;
@ -395,8 +548,7 @@ static Bitu INT67_Handler(void) {
reg_ah=EMM_NO_ERROR; reg_ah=EMM_NO_ERROR;
break; break;
case 0x4c: /* Get Pages for one Handle */ case 0x4c: /* Get Pages for one Handle */
/* Check for valid handle */ if (!ValidHandle(reg_bx)) {reg_ah=EMM_INVALID_HANDLE;break;}
if (reg_bx>=EMM_MAX_HANDLES || emm_handles[reg_bx].pages==NULL_HANDLE) {reg_ah=EMM_INVALID_HANDLE;break;}
reg_bx=emm_handles[reg_dx].pages; reg_bx=emm_handles[reg_dx].pages;
reg_ah=EMM_NO_ERROR; reg_ah=EMM_NO_ERROR;
break; break;
@ -431,7 +583,6 @@ static Bitu INT67_Handler(void) {
case 0x4f: /* Save/Restore Partial Page Map */ case 0x4f: /* Save/Restore Partial Page Map */
reg_ah=EMM_PartialPageMapping(); reg_ah=EMM_PartialPageMapping();
break; break;
case 0x50: /* Map/Unmap multiple handle pages */ case 0x50: /* Map/Unmap multiple handle pages */
reg_ah = EMM_NO_ERROR; reg_ah = EMM_NO_ERROR;
switch (reg_al) { switch (reg_al) {
@ -467,6 +618,13 @@ static Bitu INT67_Handler(void) {
reg_ah=EMM_NO_ERROR; reg_ah=EMM_NO_ERROR;
} }
break; 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 case 0x58: // Get mappable physical array address array
if (reg_al==0x00) { if (reg_al==0x00) {
PhysPt data = SegPhys(es)+reg_di; PhysPt data = SegPhys(es)+reg_di;
@ -498,6 +656,12 @@ void EMS_Init(Section* sec) {
Section_prop * section=static_cast<Section_prop *>(sec); Section_prop * section=static_cast<Section_prop *>(sec);
Bitu size=section->Get_int("emssize"); Bitu size=section->Get_int("emssize");
if (!size) return; 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(); call_int67=CALLBACK_Allocate();
CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET); CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET);
/* Register the ems device */ /* Register the ems device */
@ -515,7 +679,7 @@ void EMS_Init(Section* sec) {
RealSetVec(0x67,RealMake(seg,0)); RealSetVec(0x67,RealMake(seg,0));
/* Clear handle and page tables */ /* Clear handle and page tables */
Bitu i; Bitu i;
for (i=0;i<EMM_MAX_PAGES;i++) { for (i=0;i<emm_page_count;i++) {
emm_pages[i].memory=0; emm_pages[i].memory=0;
emm_pages[i].handle=NULL_HANDLE; emm_pages[i].handle=NULL_HANDLE;
emm_pages[i].next=NULL_PAGE; emm_pages[i].next=NULL_PAGE;
@ -523,7 +687,7 @@ void EMS_Init(Section* sec) {
for (i=0;i<EMM_MAX_HANDLES;i++) { for (i=0;i<EMM_MAX_HANDLES;i++) {
emm_handles[i].first_page=NULL_PAGE; emm_handles[i].first_page=NULL_PAGE;
emm_handles[i].pages=NULL_HANDLE; emm_handles[i].pages=NULL_HANDLE;
memset(&emm_handles[i].name,0,9); memset(&emm_handles[i].name,0,8);
} }
for (i=0;i<EMM_MAX_PHYS;i++) { for (i=0;i<EMM_MAX_PHYS;i++) {
emm_mappings[i].page=NULL_PAGE; emm_mappings[i].page=NULL_PAGE;

View File

@ -25,12 +25,13 @@
#include "video.h" #include "video.h"
#include "inout.h" #include "inout.h"
#include "int10.h" #include "int10.h"
#include "../hardware/vga.h" /* Maybe move this thing */
#define TEXT_SEG 0xb800 #define TEXT_SEG 0xb800
static Bitu call_10; static Bitu call_10;
static bool warned_ff=false; static bool warned_ff=false;
static bool warned_int10_0b=false;
static Bitu INT10_Handler(void) { static Bitu INT10_Handler(void) {
switch (reg_ah) { switch (reg_ah) {
@ -38,7 +39,8 @@ static Bitu INT10_Handler(void) {
INT10_SetVideoMode(reg_al); INT10_SetVideoMode(reg_al);
break; break;
case 0x01: /* Set TextMode Cursor Shape */ case 0x01: /* Set TextMode Cursor Shape */
LOG_WARN("INT10:01:Set textmode cursor shape not supported"); vga.internal.cursor=reg_cx; // maybe write some memory somewhere
LOG_DEBUG("INT10:01:Set textmode cursor shape partially supported: %X",reg_cx);
break; break;
case 0x02: /* Set Cursor Pos */ case 0x02: /* Set Cursor Pos */
//TODO Check some shit but not really usefull //TODO Check some shit but not really usefull
@ -74,6 +76,10 @@ static Bitu INT10_Handler(void) {
INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,false); INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,false);
break; break;
case 0x0B: /* Set Background/Border Colour & Set Palette*/ case 0x0B: /* Set Background/Border Colour & Set Palette*/
if(!warned_int10_0b) {
LOG_WARN("INT 10:0B Unsupported: Set Background/border colour & Set Pallete");
warned_int10_0b=true;
}
break; break;
E_Exit("Unsupported int 10 call %02X" ,reg_ah); E_Exit("Unsupported int 10 call %02X" ,reg_ah);
break; break;

View File

@ -200,6 +200,8 @@ void INT10_GetSingleDacRegister(Bit8u index,Bit8u * red,Bit8u * green,Bit8u * bl
void INT10_SetDACBlock(Bit16u index,Bit16u count,PhysPt data); void INT10_SetDACBlock(Bit16u index,Bit16u count,PhysPt data);
void INT10_GetDACBlock(Bit16u index,Bit16u count,PhysPt data); void INT10_GetDACBlock(Bit16u index,Bit16u count,PhysPt data);
/* Mouse pointer */
void INT10_SetGfxControllerToDefault(void);
/* Sup Groups */ /* Sup Groups */
void INT10_SetupRomMemory(void); void INT10_SetupRomMemory(void);

View File

@ -24,6 +24,17 @@
#include "inout.h" #include "inout.h"
#include "int10.h" #include "int10.h"
static INLINE void CGA_CopyRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) {
PhysPt dest=base+((curmode->twidth*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;i<curmode->cheight/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) { static INLINE void PLANAR4_CopyRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8u rold,Bit8u rnew,PhysPt base) {
PhysPt src,dest;Bitu copy; PhysPt src,dest;Bitu copy;
dest=base+(curmode->twidth*rnew)*curmode->cheight+cleft; 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 (;copy>0;copy--) {
for (Bitu x=0;x<rowsize;x++) mem_writeb(dest+x,mem_readb(src+x)); for (Bitu x=0;x<rowsize;x++) mem_writeb(dest+x,mem_readb(src+x));
dest+=nextline;src+=nextline; dest+=nextline;src+=nextline;
} }
/* Restore registers */ /* Restore registers */
IO_Write(0x3ce,5);IO_Write(0x3cf,0); /* Normal transfer mode */ IO_Write(0x3ce,5);IO_Write(0x3cf,0); /* Normal transfer mode */
@ -52,6 +62,19 @@ static INLINE void TEXT_CopyRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8
MEM_BlockCopy(dest,src,(cright-cleft)*2); MEM_BlockCopy(dest,src,(cright-cleft)*2);
} }
static INLINE void CGA_FillRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) {
PhysPt dest=base+((curmode->twidth*row)*(curmode->cheight/2)+cleft)*2;
Bitu copy=(cright-cleft)*2;Bitu nextline=curmode->twidth*2;
for (Bits i=0;i<curmode->cheight/2;i++) {
for (Bitu x=0;x<copy;x++) {
mem_writeb(dest+x,attr);
mem_writeb(dest+8*1024+x,attr);
}
dest+=nextline;
}
}
static INLINE void PLANAR4_FillRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) { static INLINE void PLANAR4_FillRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8u row,PhysPt base,Bit8u attr) {
/* Set Bitmask / Color / Full Set Reset */ /* Set Bitmask / Color / Full Set Reset */
IO_Write(0x3ce,0x8);IO_Write(0x3cf,0xff); IO_Write(0x3ce,0x8);IO_Write(0x3cf,0xff);
@ -77,12 +100,10 @@ static INLINE void TEXT_FillRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,Bit8
mem_writew(dest,fill); mem_writew(dest,fill);
dest+=2; dest+=2;
} }
} }
void INT10_ScrollWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8s nlines,Bit8u attr,Bit8u page) { void INT10_ScrollWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8s nlines,Bit8u attr,Bit8u page) {
/* Do some range checking */ /* Do some range checking */
BIOS_NCOLS;BIOS_NROWS; BIOS_NCOLS;BIOS_NROWS;
if(rul>rlr) return; if(rul>rlr) return;
@ -116,9 +137,10 @@ void INT10_ScrollWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8s nlines,Bit
case MTEXT: case MTEXT:
case CTEXT: case CTEXT:
TEXT_CopyRow(curmode,cul,clr,start,start+nlines,base);break; TEXT_CopyRow(curmode,cul,clr,start,start+nlines,base);break;
case CGA:
CGA_CopyRow(curmode,cul,clr,start,start+nlines,base);break;
case PLANAR4: case PLANAR4:
PLANAR4_CopyRow(curmode,cul,clr,start,start+nlines,base);break; PLANAR4_CopyRow(curmode,cul,clr,start,start+nlines,base);break;
} }
} while (start!=end); } while (start!=end);
/* Fill some lines */ /* Fill some lines */
@ -134,6 +156,8 @@ filling:
case MTEXT: case MTEXT:
case CTEXT: case CTEXT:
TEXT_FillRow(curmode,cul,clr,start,base,attr);break; TEXT_FillRow(curmode,cul,clr,start,base,attr);break;
case CGA:
CGA_FillRow(curmode,cul,clr,start,base,attr);break;
case PLANAR4: case PLANAR4:
PLANAR4_FillRow(curmode,cul,clr,start,base,attr);break; 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) { void INT10_WriteChar(Bit8u chr,Bit8u attr,Bit8u page,Bit16u count,bool showattr) {
if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
Bit8u cur_row=CURSOR_POS_ROW(page); Bit8u cur_row=CURSOR_POS_ROW(page);

View File

@ -20,6 +20,7 @@
#include "mem.h" #include "mem.h"
#include "inout.h" #include "inout.h"
#include "int10.h" #include "int10.h"
#include "mouse.h"
//TODO Maybe also add PCJR Video Modes could be nice :) //TODO Maybe also add PCJR Video Modes could be nice :)
//TODO include some credits to bochs/plex86 bios i used for info/tables //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_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1);
real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight); real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem << 7))); real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem << 7)));
real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9); real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0x09);
real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0);
real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f); 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 // FIXME We nearly have the good tables. to be reworked
@ -410,4 +410,18 @@ void INT10_SetVideoMode(Bit8u mode) {
INT10_SetActivePage(0); INT10_SetActivePage(0);
/* Set some interrupt vectors */ /* Set some interrupt vectors */
RealSetVec(0x43,int10_romarea.font_8_first); 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]);
}
};

View File

@ -29,6 +29,9 @@
static Bitu call_int33,call_int74; static Bitu call_int33,call_int74;
// forward
void WriteMouseIntVector(void);
struct button_event { struct button_event {
Bit16u type; Bit16u type;
Bit16u buttons; Bit16u buttons;
@ -40,6 +43,30 @@ struct button_event {
#define POS_X (Bit16s)(mouse.x) #define POS_X (Bit16s)(mouse.x)
#define POS_Y (Bit16s)(mouse.y) #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 { static struct {
Bit16u buttons; Bit16u buttons;
Bit16u times_pressed[MOUSE_BUTTONS]; Bit16u times_pressed[MOUSE_BUTTONS];
@ -57,6 +84,22 @@ static struct {
Bit32u events; Bit32u events;
Bit16u sub_seg,sub_ofs; Bit16u sub_seg,sub_ofs;
Bit16u sub_mask; 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; } mouse;
#define X_MICKEY 8 #define X_MICKEY 8
@ -79,17 +122,211 @@ INLINE void Mouse_AddEvent(Bit16u type) {
PIC_ActivateIRQ(12); PIC_ActivateIRQ(12);
} }
static void DrawCursor() { // ***************************************************************************
// Mouse cursor - text mode
// ***************************************************************************
void RestoreCursorBackgroundText()
{
if (mouse.shown<0) return; 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) { void Mouse_CursorMoved(float x,float y) {
mouse.mickey_x+=x;
mouse.mickey_y+=y; float dx = x * mouse.pixelPerMickey_x;
mouse.x+=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.x>mouse.max_x) mouse.x=mouse.max_x;;
if (mouse.x<mouse.min_x) mouse.x=mouse.min_x; if (mouse.x<mouse.min_x) mouse.x=mouse.min_x;
mouse.y+=y; mouse.y += dy;
if (mouse.y>mouse.max_y) mouse.y=mouse.max_y;; if (mouse.y>mouse.max_y) mouse.y=mouse.max_y;;
if (mouse.y<mouse.min_y) mouse.y=mouse.min_y; if (mouse.y<mouse.min_y) mouse.y=mouse.min_y;
Mouse_AddEvent(MOUSE_MOVED); Mouse_AddEvent(MOUSE_MOVED);
@ -142,14 +379,32 @@ void Mouse_ButtonReleased(Bit8u button) {
mouse.last_released_y[button]=POS_Y; mouse.last_released_y[button]=POS_Y;
} }
static void mouse_reset(void) { static void SetMickeyPixelRate(Bit16s px, Bit16s py)
real_writed(0,(0x33<<2),CALLBACK_RealPointer(call_int33)); {
if ((px!=0) && (py!=0)) {
mouse.mickeysPerPixel_x = (float)px/X_MICKEY;
mouse.mickeysPerPixel_y = (float)py/Y_MICKEY;
mouse.pixelPerMickey_x = X_MICKEY/(float)px;
mouse.pixelPerMickey_y = Y_MICKEY/(float)py;
}
};
void Mouse_SetResolution(Bit16u width, Bit16u height)
{
mouse.resy = height-1;
mouse.shown = -1; // hide cursor
};
static void mouse_reset(void)
{
WriteMouseIntVector();
real_writed(0,(0x74<<2),CALLBACK_RealPointer(call_int74)); real_writed(0,(0x74<<2),CALLBACK_RealPointer(call_int74));
mouse.shown=-1; mouse.shown=-1;
mouse.min_x=0; mouse.min_x=0;
mouse.max_x=639;
mouse.min_y=0; mouse.min_y=0;
mouse.max_y=199; mouse.max_x=639;
mouse.max_y=mouse.resy;
// Dont set max coordinates here. it is done by SetResolution!
mouse.x=0; // civ wont work otherwise mouse.x=0; // civ wont work otherwise
mouse.y=100; mouse.y=100;
mouse.events=0; mouse.events=0;
@ -158,10 +413,21 @@ static void mouse_reset(void) {
mouse.sub_mask=0; mouse.sub_mask=0;
mouse.sub_seg=0; mouse.sub_seg=0;
mouse.sub_ofs=0; mouse.sub_ofs=0;
mouse.hotx = 0;
mouse.hoty = 0;
mouse.background = false;
mouse.screenMask = defaultScreenMask;
mouse.cursorMask = defaultCursorMask;
mouse.textAndMask= defaultTextAndMask;
mouse.textXorMask= defaultTextXorMask;
SetMickeyPixelRate(8,16);
} }
static Bitu INT33_Handler(void) { static Bitu INT33_Handler(void) {
// LOG_DEBUG("MOUSE: %04X",reg_ax);
switch (reg_ax) { switch (reg_ax) {
case 0x00: /* Reset Driver and Read Status */ case 0x00: /* Reset Driver and Read Status */
reg_ax=0xffff; reg_ax=0xffff;
@ -172,9 +438,15 @@ static Bitu INT33_Handler(void) {
case 0x01: /* Show Mouse */ case 0x01: /* Show Mouse */
mouse.shown++; mouse.shown++;
if (mouse.shown>0) mouse.shown=0; if (mouse.shown>0) mouse.shown=0;
DrawCursor();
break; break;
case 0x02: /* Hide Mouse */ case 0x02: /* Hide Mouse */
mouse.shown--; {
VGAMODES * curmode=GetCurrentMode();
if (curmode && curmode->type==GRAPH) RestoreCursorBackground();
else RestoreCursorBackgroundText();
mouse.shown--;
}
break; break;
case 0x03: /* Return position and Button Status */ case 0x03: /* Return position and Button Status */
reg_bx=mouse.buttons; reg_bx=mouse.buttons;
@ -184,6 +456,7 @@ static Bitu INT33_Handler(void) {
case 0x04: /* Position Mouse */ case 0x04: /* Position Mouse */
mouse.x=(float)reg_cx; mouse.x=(float)reg_cx;
mouse.y=(float)reg_dx; mouse.y=(float)reg_dx;
DrawCursor();
break; break;
case 0x05: /* Return Button Press Data */ case 0x05: /* Return Button Press Data */
{ {
@ -212,18 +485,38 @@ static Bitu INT33_Handler(void) {
break; break;
} }
case 0x07: /* Define horizontal cursor range */ case 0x07: /* Define horizontal cursor range */
mouse.min_x=reg_cx; if (reg_cx<reg_dx) {
mouse.max_x=reg_dx; mouse.min_x=reg_cx;
mouse.max_x=reg_dx;
} else {
mouse.min_x=reg_dx;
mouse.max_x=reg_cx;
};
break; break;
case 0x08: /* Define vertical cursor range */ case 0x08: /* Define vertical cursor range */
mouse.min_y=reg_cx; if (reg_cx<reg_dx) {
mouse.max_y=reg_dx; mouse.min_y=reg_cx;
mouse.max_y=reg_dx;
} else {
mouse.min_y=reg_dx;
mouse.max_y=reg_cx;
};
break; break;
case 0x09: /* Define GFX Cursor */ case 0x09: /* Define GFX Cursor */
LOG_WARN("MOUSE:Define gfx cursor not supported"); {
PhysPt src = SegPhys(es)+reg_dx;
MEM_BlockRead(src ,userdefScreenMask,CURSORY*2);
MEM_BlockRead(src+CURSORY*2,userdefCursorMask,CURSORY*2);
mouse.screenMask = userdefScreenMask;
mouse.cursorMask = userdefCursorMask;
mouse.hotx = reg_bx;
mouse.hoty = reg_cx;
DrawCursor();
}
break; break;
case 0x0a: /* Define Text Cursor */ case 0x0a: /* Define Text Cursor */
/* Don't see much need for supporting this */ mouse.textAndMask = reg_cx;
mouse.textXorMask = reg_dx;
break; break;
case 0x0c: /* Define interrupt subroutine parameters */ case 0x0c: /* Define interrupt subroutine parameters */
mouse.sub_mask=reg_cx; mouse.sub_mask=reg_cx;
@ -231,11 +524,11 @@ static Bitu INT33_Handler(void) {
mouse.sub_ofs=reg_dx; mouse.sub_ofs=reg_dx;
break; break;
case 0x0f: /* Define mickey/pixel rate */ case 0x0f: /* Define mickey/pixel rate */
//TODO Maybe dunno for sure might be possible */ SetMickeyPixelRate(reg_cx,reg_dx);
break; break;
case 0x0B: /* Read Motion Data */ case 0x0B: /* Read Motion Data */
reg_cx=(Bit16s)(mouse.mickey_x*X_MICKEY); reg_cx=(Bit16s)(mouse.mickey_x*mouse.mickeysPerPixel_x);
reg_dx=(Bit16s)(mouse.mickey_y*Y_MICKEY); reg_dx=(Bit16s)(mouse.mickey_y*mouse.mickeysPerPixel_y);
mouse.mickey_x=0; mouse.mickey_x=0;
mouse.mickey_y=0; mouse.mickey_y=0;
break; break;
@ -254,6 +547,16 @@ static Bitu INT33_Handler(void) {
SegSet16(es,oldSeg); SegSet16(es,oldSeg);
} }
break; break;
case 0x1a: /* Set mouse sensitivity */
SetMickeyPixelRate(reg_bx,reg_cx);
// ToDo : double mouse speed value
break;
case 0x1b: /* Get mouse sensitivity */
reg_bx = Bit16s(X_MICKEY * mouse.mickeysPerPixel_x);
reg_cx = Bit16s(Y_MICKEY * mouse.mickeysPerPixel_y);
// ToDo : double mouse speed value
reg_dx = 64;
break;
case 0x1c: /* Set interrupt rate */ case 0x1c: /* Set interrupt rate */
/* Can't really set a rate this is host determined */ /* Can't really set a rate this is host determined */
break; break;
@ -288,12 +591,13 @@ static Bitu INT74_Handler(void) {
reg_bx=mouse.event_queue[mouse.events].buttons; reg_bx=mouse.event_queue[mouse.events].buttons;
reg_cx=POS_X; reg_cx=POS_X;
reg_dx=POS_Y; reg_dx=POS_Y;
reg_si=(Bit16s)(mouse.mickey_x*X_MICKEY); reg_si=(Bit16s)(mouse.mickey_x*mouse.mickeysPerPixel_x);
reg_di=(Bit16s)(mouse.mickey_y*Y_MICKEY); reg_di=(Bit16s)(mouse.mickey_y*mouse.mickeysPerPixel_y);
if (mouse.event_queue[mouse.events].type==MOUSE_MOVED) { // Hmm... this look ok, but moonbase wont work with it
/*if (mouse.event_queue[mouse.events].type==MOUSE_MOVED) {
mouse.mickey_x=0; mouse.mickey_x=0;
mouse.mickey_y=0; mouse.mickey_y=0;
} }*/
CALLBACK_RunRealFar(mouse.sub_seg,mouse.sub_ofs); CALLBACK_RunRealFar(mouse.sub_seg,mouse.sub_ofs);
reg_eax=oldeax;reg_ebx=oldebx;reg_ecx=oldecx;reg_edx=oldedx; reg_eax=oldeax;reg_ebx=oldebx;reg_ecx=oldecx;reg_edx=oldedx;
reg_esi=oldesi;reg_edi=oldedi;reg_ebp=oldebp;reg_esp=oldesp; reg_esi=oldesi;reg_edi=oldedi;reg_ebp=oldebp;reg_esp=oldesp;
@ -309,16 +613,41 @@ static Bitu INT74_Handler(void) {
return CBRET_NONE; return CBRET_NONE;
} }
void MOUSE_Init(Section* sec) { void WriteMouseIntVector(void)
{
// Create a mouse vector with weird address
// for strange mouse detection routines in Sim City & Wasteland
real_writed(0,0x33<<2,RealMake(CB_SEG+1,(call_int33<<4)-0x10+1)); // +1 = Skip NOP
};
void CreateMouseCallback(void)
{
// Create callback
call_int33=CALLBACK_Allocate(); call_int33=CALLBACK_Allocate();
CALLBACK_Setup(call_int33,&INT33_Handler,CB_IRET); CALLBACK_Setup(call_int33,&INT33_Handler,CB_IRET);
real_writed(0,(0x33<<2),CALLBACK_RealPointer(call_int33)); // Create a mouse vector with weird address
// for strange mouse detection routines in Sim City & Wasteland
Bit16u ofs = call_int33<<4;
real_writeb((Bit16u)CB_SEG,ofs+0,(Bit8u)0x90); //NOP
real_writeb((Bit16u)CB_SEG,ofs+1,(Bit8u)0xFE); //GRP 4
real_writeb((Bit16u)CB_SEG,ofs+2,(Bit8u)0x38); //Extra Callback instruction
real_writew((Bit16u)CB_SEG,ofs+3,call_int33); //The immediate word
real_writeb((Bit16u)CB_SEG,ofs+5,(Bit8u)0xCF); //An IRET Instruction
// Write weird vector
WriteMouseIntVector();
};
void MOUSE_Init(Section* sec) {
// Callback 0x33
CreateMouseCallback();
call_int74=CALLBACK_Allocate(); call_int74=CALLBACK_Allocate();
CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRET); CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRET);
real_writed(0,(0x74<<2),CALLBACK_RealPointer(call_int74)); real_writed(0,(0x74<<2),CALLBACK_RealPointer(call_int74));
memset(&mouse,0,sizeof(mouse)); memset(&mouse,0,sizeof(mouse));
mouse.resy = 199; // Init with startup value
mouse_reset(); mouse_reset();
} }

View File

@ -118,7 +118,8 @@ Bitu XMS_Handler(void) {
case XMS_LOCAL_ENABLE_A20: /* 05 */ case XMS_LOCAL_ENABLE_A20: /* 05 */
case XMS_LOCAL_DISABLE_A20: /* 06 */ case XMS_LOCAL_DISABLE_A20: /* 06 */
case XMS_QUERY_A20: /* 07 */ case XMS_QUERY_A20: /* 07 */
LOG_WARN("XMS:Unhandled call %2X",reg_ah);break; LOG_WARN("XMS:Unhandled call %2X",reg_ah);
break;
case XMS_QUERY_FREE_EXTENDED_MEMORY: /* 08 */ case XMS_QUERY_FREE_EXTENDED_MEMORY: /* 08 */
/* Scan the tree for free memory and find largest free block */ /* Scan the tree for free memory and find largest free block */
{ {
@ -177,7 +178,7 @@ foundnew:
return CBRET_NONE; return CBRET_NONE;
} }
/* Not a free block or too small advance to next one if possible */ /* Not a free block or too small advance to next one if possible */
if (xms_handles[index].next) index=xms_handles[index].next; if (xms_handles[index].next < XMS_HANDLES ) index=xms_handles[index].next;
else break; else break;
} }
/* Found no good blocks give some errors */ /* Found no good blocks give some errors */
@ -311,7 +312,7 @@ foundnew:
} }
reg_bh=xms_handles[reg_dx].locked; reg_bh=xms_handles[reg_dx].locked;
/* Find available blocks */ /* Find available blocks */
reg_bx=0;{ for (Bitu i=0;i<XMS_HANDLES;i++) if (!xms_handles[i].data) reg_bx++;} reg_bx=0;{ for (Bitu i=1;i<XMS_HANDLES;i++) if (!xms_handles[i].data) reg_bx++;}
reg_dx=xms_handles[reg_dx].size; reg_dx=xms_handles[reg_dx].size;
break; break;
case XMS_RESIZE_EXTENDED_MEMORY_BLOCK: /* 0f */ case XMS_RESIZE_EXTENDED_MEMORY_BLOCK: /* 0f */

View File

@ -69,7 +69,7 @@ void MSG_Replace(const char * _name, const char* _val) {
static void LoadMessageFile(const char * fname) { static void LoadMessageFile(const char * fname) {
if (!fname) return; if (!fname) return;
if(*fname=='\0') return;//empty string=no languagefile if(*fname=='\0') return;//empty string=no languagefile
FILE * mfile=fopen(fname,"rb"); FILE * mfile=fopen(fname,"rt");
/* This should never happen and since other modules depend on this use a normal printf */ /* This should never happen and since other modules depend on this use a normal printf */
if (!mfile) { if (!mfile) {
E_Exit("MSG:Can't load messages: %s",fname); E_Exit("MSG:Can't load messages: %s",fname);
@ -120,7 +120,7 @@ const char * MSG_Get(char const * msg) {
void MSG_Write(const char * location) { void MSG_Write(const char * location) {
FILE* out=fopen(location,"w+b"); FILE* out=fopen(location,"w+t");
if(out==NULL) return;//maybe an error? if(out==NULL) return;//maybe an error?
for(itmb tel=Lang.begin();tel!=Lang.end();tel++){ for(itmb tel=Lang.begin();tel!=Lang.end();tel++){
fprintf(out,":%s\n%s.\n",(*tel).name.c_str(),(*tel).val.c_str()); fprintf(out,":%s\n%s.\n",(*tel).name.c_str(),(*tel).val.c_str());

View File

@ -32,8 +32,8 @@ Bitu call_program;
/* This registers a file on the virtual drive and creates the correct structure for it*/ /* This registers a file on the virtual drive and creates the correct structure for it*/
static Bit8u exe_block[]={ static Bit8u exe_block[]={
0xbc,0x00,0x03, //MOV SP,0x300 decrease stack size 0xbc,0x00,0x04, //MOV SP,0x400 decrease stack size
0xbb,0x30,0x00, //MOV BX,0x030 for memory resize 0xbb,0x40,0x00, //MOV BX,0x040 for memory resize
0xb4,0x4a, //MOV AH,0x4A Resize memory block 0xb4,0x4a, //MOV AH,0x4A Resize memory block
0xcd,0x21, //INT 0x21 0xcd,0x21, //INT 0x21
//pos 12 is callback number //pos 12 is callback number
@ -70,7 +70,7 @@ static Bitu PROGRAMS_Handler(void) {
new_program->Run(); new_program->Run();
delete new_program; delete new_program;
return CBRET_NONE; return CBRET_NONE;
}; }
/* Main functions used in all program */ /* Main functions used in all program */

View File

@ -156,7 +156,7 @@ void Section_line::PrintData(FILE* outfile) {
void Config::PrintConfig(const char* configfilename){ void Config::PrintConfig(const char* configfilename){
char temp[50]; char temp[50];
FILE* outfile=fopen(configfilename,"w+b"); FILE* outfile=fopen(configfilename,"w+t");
if(outfile==NULL) return; if(outfile==NULL) return;
for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){
/* Print out the Section header */ /* Print out the Section header */
@ -325,6 +325,18 @@ bool CommandLine::FindStringBegin(char * begin,std::string & value, bool remove)
return false; 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) { int CommandLine::GetCount(void) {
return cmds.size(); return cmds.size();
} }
@ -369,3 +381,4 @@ CommandLine::CommandLine(char * name,char * cmdline) {
} }
if (inword || inquote) cmds.push_back(str); if (inword || inquote) cmds.push_back(str);
} }

View File

@ -1,6 +1,6 @@
#define INLINE __forceinline #define INLINE __forceinline
#define VERSION "0.56" #define VERSION "0.57"
#define GCC_ATTRIBUTE(x) /* attribute not supported */ #define GCC_ATTRIBUTE(x) /* attribute not supported */

View File

@ -7,6 +7,7 @@
*/ */
#include "dirent.h" #include "dirent.h"
#include "io.h"
#ifdef WIN32 #ifdef WIN32
@ -22,17 +23,14 @@ DIR * opendir(const char *dirname) {
/* Stash the directory name */ /* Stash the directory name */
strcpy(dir.pathName,dirname); strcpy(dir.pathName,dirname);
strcat(dir.pathName,"*.*");
/* set the handle to invalid and set the firstTime flag */ /* set the handle to invalid and set the firstTime flag */
dir.handle = INVALID_HANDLE_VALUE; dir.handle = INVALID_HANDLE_VALUE;
dir.firstTime = TRUE; dir.firstTime = TRUE;
if (strcmp(dirname, ".") == 0) {
return &dir;
}
/* Change the current directory to the one requested */ /* 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 */ /** Close the current directory - return 0 if success */
@ -60,7 +58,7 @@ struct dirent * readdir(DIR *dirp) {
if (TRUE == dirp->firstTime) if (TRUE == dirp->firstTime)
{ {
/** Get the first entry in the directory */ /** Get the first entry in the directory */
dirp->handle = FindFirstFile("*.*", &dirp->findFileData); dirp->handle = FindFirstFile(dirp->pathName, &dirp->findFileData);
dirp->firstTime = FALSE; dirp->firstTime = FALSE;
if (INVALID_HANDLE_VALUE == dirp->handle) if (INVALID_HANDLE_VALUE == dirp->handle)
{ {

View File

@ -79,7 +79,7 @@ void DOS_Shell::ParseLine(char * line) {
char * fname1=0; char * fname1=0;
/* Check for a leading @ */ /* Check for a leading @ */
if (line[0]=='@') line[0]=' '; if (line[0]=='@') line[0]=' ';
line=trim(line); line=trim(line);
Bit32u num=0; /* Number of commands in this 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) { void DOS_Shell::Run(void) {
char input_line[CMD_MAXLINE]; char input_line[CMD_MAXLINE];
std::string line; std::string line;
if (cmd->FindString("/C",line,true)) {
if (cmd->FindStringRemain("/C",line)) {
strcpy(input_line,line.c_str()); strcpy(input_line,line.c_str());
line.erase(); ParseLine(input_line);
return; return;
} }
/* Start a normal shell and check for a first command init */ /* 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() { void SHELL_Init() {
/* Add messages */ /* Add messages */
MSG_Add("SHELL_ILLEGAL_PATH","Illegal Path\n");
MSG_Add("SHELL_CMD_HELP","supported commands are:\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_ON","ECHO is on\n");
MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off\n"); MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off\n");
MSG_Add("SHELL_ILLEGAL_SWITCH","Illegal switch: %s\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_CHDIR_ERROR","Unable to change to: %s\n");
MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %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_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_NOT_SET","Environment variable %s not defined\n");
MSG_Add("SHELL_CMD_SET_OUT_OF_SPACE","Not enough environment space left.\n"); MSG_Add("SHELL_CMD_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_NOT_FOUND","File %s not found.\n");
MSG_Add("SHELL_CMD_FILE_EXISTS","File %s already exists.\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_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_USED","%5d File(s) %17s Bytes\n");
MSG_Add("SHELL_CMD_DIR_BYTES_FREE","%5d Dir(s) %17s Bytes free\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_DRIVE_NOT_FOUND","Drive %c does not exist!\n");
MSG_Add("SHELL_EXECUTE_ILLEGAL_COMMAND","Illegal command: %s.\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_CHDIR_HELP","Change Directory.\n");
MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n"); MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n");
MSG_Add("SHELL_CMD_DIR_HELP","Directory View.\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_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_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_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 */ /* Regular startup */
call_shellstop=CALLBACK_Allocate(); 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); CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET);
PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart); PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart);

View File

@ -20,7 +20,6 @@
#include <string.h> #include <string.h>
#include "shell_inc.h" #include "shell_inc.h"
#include "cpu.h"
BatchFile::BatchFile(DOS_Shell * host,char * name, char * cmd_line) { BatchFile::BatchFile(DOS_Shell * host,char * name, char * cmd_line) {
@ -50,7 +49,7 @@ emptyline:
n=1; n=1;
DOS_ReadFile(file_handle,&c,&n); DOS_ReadFile(file_handle,&c,&n);
if (n>0) { if (n>0) {
if (c>31) if (c>31 || c==0x1b)
*cmd_write++=c; *cmd_write++=c;
} }
} while (c!='\n' && n); } while (c!='\n' && n);

View File

@ -28,6 +28,8 @@ static SHELL_Cmd cmd_list[]={
"CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP", "CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP",
// "COPY", 0, &DOS_Shell::CMD_COPY, "Copy Files.", // "COPY", 0, &DOS_Shell::CMD_COPY, "Copy Files.",
"DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP", "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", "ECHO", 0, &DOS_Shell::CMD_ECHO, "SHELL_CMD_ECHO_HELP",
"EXIT", 0, &DOS_Shell::CMD_EXIT, "SHELL_CMD_EXIT_HELP", "EXIT", 0, &DOS_Shell::CMD_EXIT, "SHELL_CMD_EXIT_HELP",
"HELP", 0, &DOS_Shell::CMD_HELP, "SHELL_CMD_HELP_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", "GOTO", 0, &DOS_Shell::CMD_GOTO, "SHELL_CMD_GOTO_HELP",
"TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP", "TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP",
"REM", 0, &DOS_Shell::CMD_REM, "SHELL_CMD_REM_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", "CHDIR", 0, &DOS_Shell::CMD_CHDIR, "Change Directory",
"MKDIR", 0, &DOS_Shell::CMD_MKDIR, "Make 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==32) break;
if (*line=='/') break; if (*line=='/') break;
if ((*line=='.') && (*(line+1)=='.')) break; if ((*line=='.') && (*(line+1)=='.')) break;
// if ((*line=='.') && (*(line+1)==0)) break;
*cmd_write++=*line++; *cmd_write++=*line++;
} }
*cmd_write=0; *cmd_write=0;
@ -80,6 +84,33 @@ void DOS_Shell::CMD_CLS(char * args) {
CALLBACK_RunRealInt(0x10); 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){ void DOS_Shell::CMD_HELP(char * args){
/* Print the help */ /* Print the help */
WriteOut(MSG_Get("SHELL_CMD_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) { void DOS_Shell::CMD_ECHO(char * args) {
if (!*args) { if (!*args) {
if (echo) { WriteOut(MSG_Get("SHELL_CMD_ECHO_ON"));} 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 */ /* Make a full path in the args */
if (!DOS_Canonicalize(args,path)) { if (!DOS_Canonicalize(args,path)) {
WriteOut(MSG_Get("SHELL_CMD_DIR_PATH_ERROR")); WriteOut(MSG_Get("SHELL_CMD_ILLEGAL_PATH"));
return; return;
} }
*(strrchr(path,'\\')+1)=0; *(strrchr(path,'\\')+1)=0;
@ -250,7 +292,7 @@ void DOS_Shell::CMD_DIR(char * args) {
//TODO Free Space //TODO Free Space
Bitu free_space=1024*1024*100; Bitu free_space=1024*1024*100;
if (Drives[drive]) { 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,&sectors_cluster,&total_clusters,&free_clusters); Drives[drive]->AllocationInfo(&bytes_sector,&sectors_cluster,&total_clusters,&free_clusters);
free_space=bytes_sector*sectors_cluster*free_clusters; free_space=bytes_sector*sectors_cluster*free_clusters;
} }
@ -385,3 +427,4 @@ nextfile:
void DOS_Shell::CMD_REM(char * args) { void DOS_Shell::CMD_REM(char * args) {
} }

View File

@ -66,6 +66,7 @@ public:
void CMD_CLS(char * args); void CMD_CLS(char * args);
void CMD_COPY(char * args); void CMD_COPY(char * args);
void CMD_DIR(char * args); void CMD_DIR(char * args);
void CMD_DELETE(char * args);
void CMD_ECHO(char * args); void CMD_ECHO(char * args);
void CMD_EXIT(char * args); void CMD_EXIT(char * args);
void CMD_MKDIR(char * args); void CMD_MKDIR(char * args);
@ -76,6 +77,7 @@ public:
void CMD_GOTO(char * args); void CMD_GOTO(char * args);
void CMD_TYPE(char * args); void CMD_TYPE(char * args);
void CMD_REM(char * args); void CMD_REM(char * args);
void CMD_RENAME(char * args);
void SyntaxError(void); void SyntaxError(void);
/* The shell's variables */ /* The shell's variables */

View File

@ -47,6 +47,7 @@ void DOS_Shell::InputCommand(char * line) {
Bitu str_len=0;Bitu str_index=0; Bitu str_len=0;Bitu str_index=0;
while (size) { while (size) {
dos.echo=false;
DOS_ReadFile(input_handle,&c,&n); DOS_ReadFile(input_handle,&c,&n);
if (!n) { if (!n) {
size=0; //Kill the while loop size=0; //Kill the while loop
@ -164,10 +165,18 @@ void DOS_Shell::Execute(char * name,char * args) {
cmd.buffer[strlen(line)]=0xd; cmd.buffer[strlen(line)]=0xd;
/* Copy command line in stack block too */ /* Copy command line in stack block too */
MEM_BlockWrite(SegPhys(ss)+reg_sp+0x100,&cmd,128); 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 */ /* Set the command line in the block and save it */
block.exec.cmdtail=RealMakeSeg(ss,reg_sp+0x100); block.exec.cmdtail=RealMakeSeg(ss,reg_sp+0x100);
block.SaveData(); block.SaveData();
/* Save CS:IP to some point where i can return them from */ /* 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); RealPt newcsip=CALLBACK_RealPointer(call_shellstop);
SegSet16(cs,RealSeg(newcsip)); SegSet16(cs,RealSeg(newcsip));
reg_ip=RealOff(newcsip); reg_ip=RealOff(newcsip);
@ -181,7 +190,10 @@ void DOS_Shell::Execute(char * name,char * args) {
reg_bx=reg_sp; reg_bx=reg_sp;
flags.intf=false; flags.intf=false;
CALLBACK_RunRealInt(0x21); CALLBACK_RunRealInt(0x21);
/* Restore CS:IP and the stack */
reg_sp+=0x200; reg_sp+=0x200;
reg_eip=oldeip;
SegSet16(cs,oldcs);
} }
} }

View File

@ -271,6 +271,10 @@ SOURCE=..\include\render.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\src\gui\render_support.h
# End Source File
# Begin Source File
SOURCE=..\src\gui\sdlmain.cpp SOURCE=..\src\gui\sdlmain.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -335,6 +339,14 @@ SOURCE=..\src\hardware\adlib.cpp
# End Source File # End Source File
# Begin 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 SOURCE=..\src\hardware\dma.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -343,6 +355,10 @@ SOURCE=..\src\hardware\gameblaster.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\src\hardware\gus.cpp
# End Source File
# Begin Source File
SOURCE=..\src\hardware\hardware.cpp SOURCE=..\src\hardware\hardware.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File