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

3
README
View File

@ -1,4 +1,4 @@
DOSBox v0.56
DOSBox v0.57
Usage:
======
@ -122,6 +122,7 @@ Vlad R. of the vdmsound project for excellent sound blaster info.
Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator.
The Bochs and DOSemu projects which I used for information.
Freedos for ideas in making my shell.
The Beta Testers.
Contact:
========

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.
Freedos for ideas in making my shell.
All the people who submitted a bug.
The Beta Testers.

20
configure vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -63,6 +63,7 @@ struct DOS_Block {
Bit8u current_drive;
bool verify;
bool breakcheck;
bool echo; // if set to true dev_con::read will echo input
struct {
RealPt indosflag;
RealPt mediaid;
@ -119,7 +120,7 @@ bool DOS_ChangeDir(char * dir);
bool DOS_MakeDir(char * dir);
bool DOS_RemoveDir(char * dir);
bool DOS_Rename(char * oldname,char * newname);
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free);
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free);
bool DOS_GetFileAttr(char * name,Bit16u * attr);
/* IOCTL Stuff */
@ -140,22 +141,25 @@ bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks);
bool DOS_FreeMemory(Bit16u segment);
void DOS_FreeProcessMemory(Bit16u pspseg);
Bit16u DOS_GetMemory(Bit16u pages);
void DOS_SetMemAllocStrategy(Bit16u strat);
Bit16u DOS_GetMemAllocStrategy(void);
/* FCB stuff */
bool DOS_FCBOpenCreate(Bit16u seg,Bit16u offset);
bool DOS_FCBOpen(Bit16u seg,Bit16u offset);
bool DOS_FCBCreate(Bit16u seg,Bit16u offset);
bool DOS_FCBClose(Bit16u seg,Bit16u offset);
bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset);
bool DOS_FCBFindNext(Bit16u seg,Bit16u offset);
Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset, Bit16u numBlocks);
bool DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u numBlocks);
Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u numBlocks);
Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore);
bool DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore);
Bit8u DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore);
bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset,Bit16u numRec);
bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset);
bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset);
void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset);
Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change);
bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters);
bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters);
/* Extra DOS Interrupts */
void DOS_SetupMisc(void);
@ -418,8 +422,9 @@ private:
extern DOS_InfoBlock dos_infoblock;;
INLINE Bit8u RealHandle(Bit16u handle) {
DOS_PSP psp(dos.psp);
return psp.GetFileHandle((Bit8u)handle);
return psp.GetFileHandle(handle);
}
#endif

View File

@ -84,7 +84,7 @@ public:
virtual bool FindNext(DOS_DTA & dta)=0;
virtual bool GetFileAttr(char * name,Bit16u * attr)=0;
virtual bool Rename(char * oldname,char * newname)=0;
virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters)=0;
virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters)=0;
virtual bool FileExists(const char* name)=0;
virtual bool FileStat(const char* name, FileStat_Block * const stat_block)=0;
virtual Bit8u GetMediaByte(void)=0;

View File

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

View File

@ -19,7 +19,12 @@
#ifndef __PIC_H
#define __PIC_H
#include "cpu.h"
typedef void (PIC_EOIHandler) (void);
typedef void (* PIC_EventHandler)(void);
#define PIC_MAXIRQ 15
#define PIC_NOIRQ 0xFF
@ -27,7 +32,20 @@ typedef void (PIC_EOIHandler) (void);
extern Bitu PIC_IRQCheck;
extern Bitu PIC_IRQActive;
extern bool PIC_IRQAgain;
extern Bitu PIC_Ticks;
INLINE Bitu PIC_Index(void) {
return ((CPU_CycleMax-CPU_CycleLeft-CPU_Cycles)*1000)/CPU_CycleMax;
}
INLINE Bits PIC_MakeCycles(Bitu amount) {
return (CPU_CycleMax*amount)/1000;
}
INLINE Bit64u PIC_MicroCount(void) {
return PIC_Ticks*1000+PIC_Index();
}
void PIC_ActivateIRQ(Bit32u irq);
@ -37,8 +55,12 @@ void PIC_runIRQs(void);
void PIC_RegisterIRQ(Bit32u irq,PIC_EOIHandler handler,char * name);
void PIC_FreeIRQ(Bit32u irq);
Bitu PIC_RunQueue(void);
void PIC_AddIRQ(Bitu irq,Bitu delay);
void PIC_AddEvent(PIC_EventHandler handler,Bitu delay);
void PIC_RemoveEvents(PIC_EventHandler handler);
#endif

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);

View File

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

View File

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

View File

@ -21,15 +21,12 @@
/* underlying clock rate in HZ */
#include <SDL.h>
extern Bit32u LastTicks;
#define PIT_TICK_RATE 1193182
#define GetTicks() SDL_GetTicks()
typedef void (*TIMER_TickHandler)(Bitu ticks);
typedef void (*TIMER_MicroHandler)(void);
typedef void (*TIMER_DelayHandler)(void);
typedef void TIMER_Block;
@ -38,18 +35,12 @@ typedef void TIMER_Block;
TIMER_Block * TIMER_RegisterTickHandler(TIMER_TickHandler handler);
/* Register a function to be called every x microseconds */
TIMER_Block * TIMER_RegisterMicroHandler(TIMER_MicroHandler handler,Bitu micro);
/* Register a function to be called once after x microseconds */
TIMER_Block * TIMER_RegisterDelayHandler(TIMER_DelayHandler handler,Bitu delay);
/* Set the microseconds value to a new value */
void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro);
/* This function should be called very often to support very high res timers
Although with the new timer code it doesn't matter that much */
void TIMER_CheckPIT(void);
/* This will add ms ticks to support the timer handlers */
void TIMER_AddTicks(Bit32u ticks);
/* This will add 1 milliscond to all timers */
void TIMER_AddTick(void);
#endif

View File

@ -20,9 +20,7 @@
#define __VIDEO_H
typedef void (GFX_DrawHandler)(Bit8u * vidstart);
/* Used to reply to the renderer what size to set */
typedef void (GFX_ResizeHandler)(Bitu * width,Bitu * height);
typedef void (* GFX_ModeCallBack)(Bitu width,Bitu height,Bitu bpp,Bitu pitch,Bitu flags);
struct GFX_PalEntry {
Bit8u r;
@ -31,20 +29,25 @@ struct GFX_PalEntry {
Bit8u unused;
};
struct GFX_Info {
Bitu width,height,bpp,pitch;
};
#define GFX_FIXED_BPP 0x01
#define GFX_RESIZEABLE 0x02
extern GFX_Info gfx_info;
#define MODE_SET 0x01
#define MODE_FULLSCREEN 0x02
#define MODE_RESIZE 0x04
void GFX_Events(void);
void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries);
void GFX_SetDrawHandler(GFX_DrawHandler * handler);
void GFX_Resize(Bitu width,Bitu height,Bitu bpp,GFX_ResizeHandler * resize);
Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue);
void GFX_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu flags,GFX_ModeCallBack callback);
void GFX_Start(void);
void GFX_Stop(void);
void GFX_SwitchFullScreen(void);
void * GFX_StartUpdate(void);
void GFX_EndUpdate(void);
#endif

View File

@ -17,18 +17,15 @@
*/
#ifndef _SETTINGS_H_
#define _SETTINSG_H_
#define _SETTINGS_H_
/* Enable the debugger, this only seems to work in win32 for now. */
/* Enable the debugger, under linux/freebsd dosbox must be started in an xterm under X */
#define C_DEBUG 0
#define C_HEAVY_DEBUG 0
/* Enable the logging of extra information for debugging to the console */
#define C_LOGGING 0
/* Use multi threading to speed up things on multi cpu's, also gives a nice frame-skipping effect :) */
#define C_THREADED 1
/* Enable some big compile-time increasing inlines, great for speed though */
#define C_EXTRAINLINE 0
@ -38,12 +35,6 @@
/* Maximum memory range in megabytes */
#define C_MEM_MAX_SIZE 12
/* Maximum memory available for xms, should be lower than maxsize-1 */
#define C_MEM_XMS_SIZE 8
/* Maximum memory available for ems, should be lower than 32 */
#define C_MEM_EMS_SIZE 4
/* Enable debug messages for several modules, requires C_LOGGING */
#define DEBUG_SBLASTER 0 /* SoundBlaster Debugging*/
#define DEBUG_DMA 0 /* DMA Debugging */

View File

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

View File

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

View File

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

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

View File

@ -33,6 +33,14 @@ switch (Fetchb()) {
else {GetEAa;DSHRD(eaa,*rmrd,Fetchb(),LoadMd,SaveMd);}
break;
}
case 0xad: /* SHRD Ed,Gd,Cl */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArd;DSHRD(*eard,*rmrd,reg_cl,LoadRd,SaveRd);}
else {GetEAa;DSHRD(eaa,*rmrd,reg_cl,LoadMd,SaveMd);}
break;
}
case 0xb6: /* MOVZX Gd,Eb */
{
GetRMrd;
@ -44,8 +52,8 @@ switch (Fetchb()) {
{
GetRMrd;
Bit64s res;
if (rm >= 0xc0 ) {GetEArd;res=(Bit64s)(*rmrd) * (Bit64s)(*eards);}
else {GetEAa;res=(Bit64s)(*rmrd) * (Bit64s)LoadMds(eaa);}
if (rm >= 0xc0 ) {GetEArd;res=((Bit64s)((Bit32s)*rmrd) * (Bit64s)((Bit32s)*eards));}
else {GetEAa;res=((Bit64s)((Bit32s)*rmrd) * (Bit64s)LoadMds(eaa));}
*rmrd=(Bit32s)(res);
flags.type=t_MUL;
if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {flags.cf=false;flags.of=false;}
@ -108,6 +116,56 @@ switch (Fetchb()) {
flags.type=t_CF;
break;
}
case 0xbb: /* BTC Ed,Gd */
{
GetRMrd;
Bit32u mask=1 << (*rmrd & 31);
if (rm >= 0xc0 ) {
GetEArd;
flags.cf=(*eard & mask)>0;
*eard^=mask;
} else {
GetEAa;Bit32u old=LoadMd(eaa);
flags.cf=(old & mask)>0;
SaveMd(eaa,old ^ mask);
}
if (flags.type!=t_CF) { flags.prev_type=flags.type;flags.type=t_CF; }
break;
}
case 0xbc: /* BSF Gd,Ed */
{
GetRMrd;
Bit32u result,value;
if (rm >= 0xc0) { GetEArd; value=*eard; }
else { GetEAa; value=LoadMd(eaa); }
if (value==0) {
flags.zf = true;
} else {
result = 0;
while ((value & 0x01)==0) { result++; value>>=1; }
flags.zf = false;
*rmrd = result;
}
flags.type=t_UNKNOWN;
break;
}
case 0xbd: /* BSR Gd,Ed */
{
GetRMrd;
Bit32u result,value;
if (rm >= 0xc0) { GetEArd; value=*eard; }
else { GetEAa; value=LoadMd(eaa); }
if (value==0) {
flags.zf = true;
} else {
result = 35; // Operandsize-1
while ((value & 0x80000000)==0) { result--; value<<=1; }
flags.zf = false;
*rmrd = result;
}
flags.type=t_UNKNOWN;
break;
}
case 0xbe: /* MOVSX Gd,Eb */
{
GetRMrd;

View File

@ -59,6 +59,12 @@ switch(Fetchb()) {
/* 0x21 MOV Rd,DRx (386) */
/* 0x22 MOV CRx,Rd (386) */
/* 0x23 MOV DRx,Rd (386) */
case 0x23: /* MOV DRx,Rd */
{
GetRM;
LOG_DEBUG("CPU:0F:23 does nothing");
}
break;
/* 0x24 MOV Rd,TRx (386) */
/* 0x26 MOV TRx,Rd (386) */
/* 0x30 WRMSR (P5) */
@ -251,7 +257,12 @@ switch(Fetchb()) {
}
/* 0xb0 CMPXCHG Eb,Gb */
/* 0xb1 CMPXCHG Ew,Gw */
/* 0xb2 LSS */
case 0xb2: /* LSS */
{
GetRMrw;GetEAa;
*rmrw=LoadMw(eaa);SegSet16(ss,LoadMw(eaa+2));
break;
}
case 0xb3: /* BTR Ew,Gw */
{
GetRMrw;
@ -389,7 +400,6 @@ switch(Fetchb()) {
flags.type=t_UNKNOWN;
break;
}
/* 0xbd BSR Gw,Ew */
case 0xbe: /* MOVSX Gw,Eb */
{
GetRMrw;

View File

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

View File

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

View File

@ -19,6 +19,8 @@
/* Some variables for EA Loolkup */
typedef EAPoint (*GetEATable[256])(void);
typedef EAPoint (*EA_LookupHandler)(void);
static GetEATable * lookupEATable;
#define PREFIX_NONE 0x0
@ -35,6 +37,7 @@ static struct {
/* Gets initialized at the bottem, can't seem to declare forward references */
static GetEATable * EAPrefixTable[4];
#define SegPrefix(blah) \
prefix.segbase=SegBase(blah); \
prefix.mark|=PREFIX_SEG; \
@ -55,29 +58,6 @@ static GetEATable * EAPrefixTable[4];
prefix.count=0; \
lookupEATable=EAPrefixTable[PREFIX_NONE];
#if 1
#define GetEADirect \
EAPoint eaa;switch (prefix.mark) { \
case PREFIX_NONE:eaa=SegBase(ds)+Fetchw();break; \
case PREFIX_SEG:eaa=prefix.segbase+Fetchw();PrefixReset;break; \
case PREFIX_ADDR:eaa=SegBase(ds)+Fetchd();PrefixReset;break; \
case PREFIX_SEG_ADDR:eaa=prefix.segbase+Fetchd();PrefixReset;break; \
}
#else
#define GetEADirect \
EAPoint eaa; \
if (!prefix.mark) { eaa=SegBase(ds)+Fetchw();} \
else if (prefix.mark == PREFIX_SEG) { eaa=prefix.segbase+Fetchw();PrefixReset;} \
else if (prefix.mark == PREFIX_ADDR) { eaa=SegBase(ds)+Fetchd();PrefixReset;} \
else if (prefix.mark == PREFIX_SEG_ADDR) { eaa=prefix.segbase+Fetchd();PrefixReset;}
#endif
/* The MOD/RM Decoder for EA for this decoder's addressing modes */
static EAPoint EA_16_00_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_si); }
@ -240,32 +220,32 @@ INLINE EAPoint Sib(Bitu mode) {
};
static EAPoint EA_32_00_n(void) { return SegBase(ds)+reg_eax; }
static EAPoint EA_32_01_n(void) { return SegBase(ds)+reg_ecx; }
static EAPoint EA_32_02_n(void) { return SegBase(ds)+reg_edx; }
static EAPoint EA_32_03_n(void) { return SegBase(ds)+reg_ebx; }
static EAPoint EA_32_04_n(void) { return Sib(0);}
static EAPoint EA_32_05_n(void) { return SegBase(ds)+Fetchd(); }
static EAPoint EA_32_06_n(void) { return SegBase(ss)+reg_esi; }
static EAPoint EA_32_07_n(void) { return SegBase(ds)+reg_edi; }
static EAPoint EA_32_00_n(void) { PrefixReset;return SegBase(ds)+reg_eax; }
static EAPoint EA_32_01_n(void) { PrefixReset;return SegBase(ds)+reg_ecx; }
static EAPoint EA_32_02_n(void) { PrefixReset;return SegBase(ds)+reg_edx; }
static EAPoint EA_32_03_n(void) { PrefixReset;return SegBase(ds)+reg_ebx; }
static EAPoint EA_32_04_n(void) { PrefixReset;return Sib(0);}
static EAPoint EA_32_05_n(void) { PrefixReset;return SegBase(ds)+Fetchd(); }
static EAPoint EA_32_06_n(void) { PrefixReset;return SegBase(ds)+reg_esi; }
static EAPoint EA_32_07_n(void) { PrefixReset;return SegBase(ds)+reg_edi; }
static EAPoint EA_32_40_n(void) { return SegBase(ds)+reg_eax+Fetchbs(); }
static EAPoint EA_32_41_n(void) { return SegBase(ds)+reg_ecx+Fetchbs(); }
static EAPoint EA_32_42_n(void) { return SegBase(ds)+reg_edx+Fetchbs(); }
static EAPoint EA_32_43_n(void) { return SegBase(ds)+reg_ebx+Fetchbs(); }
static EAPoint EA_32_44_n(void) { return Sib(1)+Fetchbs();}
static EAPoint EA_32_45_n(void) { return SegBase(ss)+reg_ebp+Fetchbs(); }
static EAPoint EA_32_46_n(void) { return SegBase(ds)+reg_esi+Fetchbs(); }
static EAPoint EA_32_47_n(void) { return SegBase(ds)+reg_edi+Fetchbs(); }
static EAPoint EA_32_40_n(void) { PrefixReset;return SegBase(ds)+reg_eax+Fetchbs(); }
static EAPoint EA_32_41_n(void) { PrefixReset;return SegBase(ds)+reg_ecx+Fetchbs(); }
static EAPoint EA_32_42_n(void) { PrefixReset;return SegBase(ds)+reg_edx+Fetchbs(); }
static EAPoint EA_32_43_n(void) { PrefixReset;return SegBase(ds)+reg_ebx+Fetchbs(); }
static EAPoint EA_32_44_n(void) { PrefixReset;return Sib(1)+Fetchbs();}
static EAPoint EA_32_45_n(void) { PrefixReset;return SegBase(ss)+reg_ebp+Fetchbs(); }
static EAPoint EA_32_46_n(void) { PrefixReset;return SegBase(ds)+reg_esi+Fetchbs(); }
static EAPoint EA_32_47_n(void) { PrefixReset;return SegBase(ds)+reg_edi+Fetchbs(); }
static EAPoint EA_32_80_n(void) { return SegBase(ds)+reg_eax+Fetchds(); }
static EAPoint EA_32_81_n(void) { return SegBase(ds)+reg_ecx+Fetchds(); }
static EAPoint EA_32_82_n(void) { return SegBase(ds)+reg_edx+Fetchds(); }
static EAPoint EA_32_83_n(void) { return SegBase(ds)+reg_ebx+Fetchds(); }
static EAPoint EA_32_84_n(void) { return Sib(2)+Fetchds();}
static EAPoint EA_32_85_n(void) { return SegBase(ss)+reg_ebp+Fetchds(); }
static EAPoint EA_32_86_n(void) { return SegBase(ds)+reg_esi+Fetchds(); }
static EAPoint EA_32_87_n(void) { return SegBase(ds)+reg_edi+Fetchds(); }
static EAPoint EA_32_80_n(void) { PrefixReset;return SegBase(ds)+reg_eax+Fetchds(); }
static EAPoint EA_32_81_n(void) { PrefixReset;return SegBase(ds)+reg_ecx+Fetchds(); }
static EAPoint EA_32_82_n(void) { PrefixReset;return SegBase(ds)+reg_edx+Fetchds(); }
static EAPoint EA_32_83_n(void) { PrefixReset;return SegBase(ds)+reg_ebx+Fetchds(); }
static EAPoint EA_32_84_n(void) { PrefixReset;return Sib(2)+Fetchds();}
static EAPoint EA_32_85_n(void) { PrefixReset;return SegBase(ss)+reg_ebp+Fetchds(); }
static EAPoint EA_32_86_n(void) { PrefixReset;return SegBase(ds)+reg_esi+Fetchds(); }
static EAPoint EA_32_87_n(void) { PrefixReset;return SegBase(ds)+reg_edi+Fetchds(); }
static GetEATable GetEA_32_n={
/* 00 */
@ -327,7 +307,8 @@ INLINE EAPoint Sib_s(Bitu mode) {
case 7: /* EDI Base */
base=prefix.segbase+reg_edi;break;
}
base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); PrefixReset;
base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6);
PrefixReset;
return base;
};
@ -346,7 +327,7 @@ static EAPoint EA_32_40_s(void) { segprefixed_32(reg_eax+Fetchbs()); }
static EAPoint EA_32_41_s(void) { segprefixed_32(reg_ecx+Fetchbs()); }
static EAPoint EA_32_42_s(void) { segprefixed_32(reg_edx+Fetchbs()); }
static EAPoint EA_32_43_s(void) { segprefixed_32(reg_ebx+Fetchbs()); }
static EAPoint EA_32_44_s(void) { return Sib(1)+Fetchbs();}
static EAPoint EA_32_44_s(void) { return Sib_s(1)+Fetchbs();}
static EAPoint EA_32_45_s(void) { segprefixed_32(reg_ebp+Fetchbs()); }
static EAPoint EA_32_46_s(void) { segprefixed_32(reg_esi+Fetchbs()); }
static EAPoint EA_32_47_s(void) { segprefixed_32(reg_edi+Fetchbs()); }
@ -355,7 +336,7 @@ static EAPoint EA_32_80_s(void) { segprefixed_32(reg_eax+Fetchds()); }
static EAPoint EA_32_81_s(void) { segprefixed_32(reg_ecx+Fetchds()); }
static EAPoint EA_32_82_s(void) { segprefixed_32(reg_edx+Fetchds()); }
static EAPoint EA_32_83_s(void) { segprefixed_32(reg_ebx+Fetchds()); }
static EAPoint EA_32_84_s(void) { return Sib(2)+Fetchds();}
static EAPoint EA_32_84_s(void) { return Sib_s(2)+Fetchds();}
static EAPoint EA_32_85_s(void) { segprefixed_32(reg_ebp+Fetchds()); }
static EAPoint EA_32_86_s(void) { segprefixed_32(reg_esi+Fetchds()); }
static EAPoint EA_32_87_s(void) { segprefixed_32(reg_edi+Fetchds()); }
@ -396,4 +377,21 @@ static GetEATable GetEA_32_s={
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static EAPoint GetEADirect_NONE(void) {
EAPoint result=SegBase(ds)+Fetchw();
return result;
}
static EAPoint GetEADirect_SEG(void) {
EAPoint result=prefix.segbase+Fetchw();PrefixReset;
return result;
}
static EAPoint GetEADirect_ADDR(void) {
EAPoint result=SegBase(ds)+Fetchd();PrefixReset;
return result;
}
static EAPoint GetEADirect_SEG_ADDR(void) {
EAPoint result=prefix.segbase+Fetchd();PrefixReset;
return result;
}
static EA_LookupHandler GetEADirect[4]={GetEADirect_NONE,GetEADirect_SEG,GetEADirect_ADDR,GetEADirect_SEG_ADDR};

View File

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

View File

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

View File

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

View File

@ -34,7 +34,7 @@
#include "mixer.h"
#include "debug_inc.h"
#include "timer.h"
#include "..\shell\shell_inc.h"
#include "../shell/shell_inc.h"
#ifdef WIN32
void WIN32_Console();
@ -48,6 +48,7 @@ class DEBUG;
DEBUG* pDebugcom = 0;
bool exitLoop = false;
bool logHeavy = false;
static struct {
Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip;
@ -91,7 +92,7 @@ static Bit16u dataSeg,dataOfs;
bool skipFirstInstruction = false;
enum EBreakpoint { BKPNT_UNKNOWN, BKPNT_PHYSICAL, BKPNT_INTERRUPT };
enum EBreakpoint { BKPNT_UNKNOWN, BKPNT_PHYSICAL, BKPNT_INTERRUPT, BKPNT_MEMORY };
#define BPINT_ALL 0x100
@ -104,21 +105,24 @@ public:
void SetAddress (PhysPt adr) { location = adr; type = BKPNT_PHYSICAL; };
void SetInt (Bit8u _intNr, Bit16u ah) { intNr = _intNr, ahValue = ah; type = BKPNT_INTERRUPT; };
void SetOnce (bool _once) { once = _once; };
void SetType (EBreakpoint _type) { type = _type; };
void SetValue (Bit8u value) { ahValue = value; };
bool IsActive (void) { return active; };
void Activate (bool _active);
EBreakpoint GetType (void) { return type; };
bool GetOnce (void) { return once; };
PhysPt GetLocation (void) { if (GetType()==BKPNT_PHYSICAL) return location; else return 0; };
PhysPt GetLocation (void) { if (GetType()!=BKPNT_INTERRUPT) return location; else return 0; };
Bit16u GetSegment (void) { return segment; };
Bit32u GetOffset (void) { return offset; };
Bit8u GetIntNr (void) { if (GetType()==BKPNT_INTERRUPT) return intNr; else return 0; };
Bit16u GetValue (void) { if (GetType()==BKPNT_INTERRUPT) return ahValue; else return 0; };
Bit8u GetIntNr (void) { if (GetType()==BKPNT_INTERRUPT) return intNr; else return 0; };
Bit16u GetValue (void) { if (GetType()!=BKPNT_PHYSICAL) return ahValue; else return 0; };
// statics
static CBreakpoint* AddBreakpoint (Bit16u seg, Bit32u off, bool once);
static CBreakpoint* AddIntBreakpoint (Bit8u intNum, Bit16u ah, bool once);
static CBreakpoint* AddMemBreakpoint (Bit16u seg, Bit32u off);
static void ActivateBreakpoints (PhysPt adr, bool activate);
static bool CheckBreakpoint (PhysPt adr);
static bool CheckIntBreakpoint (PhysPt adr, Bit8u intNr, Bit16u ahValue);
@ -145,6 +149,7 @@ private:
bool once;
static std::list<CBreakpoint*> BPoints;
public:
static CBreakpoint* ignoreOnce;
};
@ -192,9 +197,18 @@ CBreakpoint* CBreakpoint::AddIntBreakpoint(Bit8u intNum, Bit16u ah, bool once)
return bp;
};
CBreakpoint* CBreakpoint::AddMemBreakpoint(Bit16u seg, Bit32u off)
{
CBreakpoint* bp = new CBreakpoint();
bp->SetAddress (seg,off);
bp->SetOnce (false);
bp->SetType (BKPNT_MEMORY);
BPoints.push_front (bp);
return bp;
};
void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
{
ignoreOnce = 0;
// activate all breakpoints
std::list<CBreakpoint*>::iterator i;
CBreakpoint* bp;
@ -202,7 +216,7 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
bp = static_cast<CBreakpoint*>(*i);
// Do not activate, when bp is an actual adress
if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) {
ignoreOnce = bp;
// Do not activate :)
continue;
}
bp->Activate(activate);
@ -212,26 +226,45 @@ void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate)
bool CBreakpoint::CheckBreakpoint(PhysPt adr)
// Checks if breakpoint is valid an should stop execution
{
// if breakpoint is same address as started, it's not valid...
if (ignoreOnce) {
ignoreOnce->Activate(true);
ignoreOnce = 0;
}
// Search matching breakpoint
std::list<CBreakpoint*>::iterator i;
CBreakpoint* bp;
for(i=BPoints.begin(); i != BPoints.end(); i++) {
bp = static_cast<CBreakpoint*>(*i);
if ((bp->GetType()==BKPNT_PHYSICAL) && bp->IsActive() && (bp->GetLocation()==adr)) {
// Ignore Once ?
if (ignoreOnce==bp) {
ignoreOnce=0;
bp->Activate(true);
return false;
};
// Found,
if (bp->GetOnce()) {
// delete it, if it should only be used once
(BPoints.erase)(i);
bp->Activate(false);
delete bp;
}
} else {
ignoreOnce = bp;
};
return true;
}
#if C_HEAVY_DEBUG
// Memory breakpoint support
else if ((bp->GetType()==BKPNT_MEMORY) && bp->IsActive()) {
Bit8u value = mem_readb(bp->GetLocation());
if (bp->GetValue() != value) {
// Yup, memory value changed
char buffer[200];
sprintf(buffer,"DEBUG: Memory breakpoint: %04X:%04X - %02X -> %02X",bp->GetSegment(),bp->GetOffset(),bp->GetValue(),value);
LOG_DEBUG(buffer);
bp->SetValue(value);
return true;
};
};
#endif
};
return false;
};
@ -239,11 +272,6 @@ bool CBreakpoint::CheckBreakpoint(PhysPt adr)
bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue)
// Checks if interrupt breakpoint is valid an should stop execution
{
// if breakpoint is same address as started, it's not valid...
if (ignoreOnce) {
ignoreOnce->Activate(true);
ignoreOnce = 0;
}
// Search matching breakpoint
std::list<CBreakpoint*>::iterator i;
CBreakpoint* bp;
@ -251,13 +279,21 @@ bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue)
bp = static_cast<CBreakpoint*>(*i);
if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) {
if ((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) {
// Ignoie it once ?
if (ignoreOnce==bp) {
ignoreOnce=0;
bp->Activate(true);
return false;
};
// Found
if (bp->GetOnce()) {
// delete it, if it should only be used once
(BPoints.erase)(i);
bp->Activate(false);
delete bp;
}
} else {
ignoreOnce = bp;
}
return true;
}
};
@ -292,6 +328,7 @@ bool CBreakpoint::DeleteByIndex(Bit16u index)
delete bp;
return true;
}
nr++;
};
return false;
};
@ -353,14 +390,15 @@ void CBreakpoint::ShowList(void)
for(i=BPoints.begin(); i != BPoints.end(); i++) {
CBreakpoint* bp = static_cast<CBreakpoint*>(*i);
if (bp->GetType()==BKPNT_PHYSICAL) {
PhysPt adr = bp->GetLocation();
wprintw(dbg.win_out,"%02X. BP %04X:%04X\n",nr,bp->GetSegment(),bp->GetOffset);
wprintw(dbg.win_out,"%02X. BP %04X:%04X\n",nr,bp->GetSegment(),bp->GetOffset());
nr++;
} else if (bp->GetType()==BKPNT_INTERRUPT) {
if (bp->GetValue()==BPINT_ALL) wprintw(dbg.win_out,"%02X. BPINT %02X\n",nr,bp->GetIntNr());
else wprintw(dbg.win_out,"%02X. BPINT %02X AH=%02X\n",nr,bp->GetIntNr(),bp->GetValue());
nr++;
} else if (bp->GetType()==BKPNT_MEMORY) {
wprintw(dbg.win_out,"%02X. BPMEM %04X:%04X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue());
nr++;
};
}
wrefresh(dbg.win_out);
@ -591,6 +629,47 @@ Bit32u GetHexValue(char* str, char*& hex)
return value;
};
bool ChangeRegister(char* str)
{
Bit32u value = 0;
char* hex = str;
while (*hex==' ') hex++;
if (strstr(hex,"AX")==hex) { hex+=2; reg_ax = GetHexValue(hex,hex); } else
if (strstr(hex,"BX")==hex) { hex+=2; reg_bx = GetHexValue(hex,hex); } else
if (strstr(hex,"CX")==hex) { hex+=2; reg_cx = GetHexValue(hex,hex); } else
if (strstr(hex,"DX")==hex) { hex+=2; reg_dx = GetHexValue(hex,hex); } else
if (strstr(hex,"SI")==hex) { hex+=2; reg_si = GetHexValue(hex,hex); } else
if (strstr(hex,"DI")==hex) { hex+=2; reg_di = GetHexValue(hex,hex); } else
if (strstr(hex,"BP")==hex) { hex+=2; reg_bp = GetHexValue(hex,hex); } else
if (strstr(hex,"SP")==hex) { hex+=2; reg_sp = GetHexValue(hex,hex); } else
if (strstr(hex,"IP")==hex) { hex+=2; reg_ip = GetHexValue(hex,hex); } else
if (strstr(hex,"CS")==hex) { hex+=2; SegSet16(cs,GetHexValue(hex,hex)); } else
if (strstr(hex,"DS")==hex) { hex+=2; SegSet16(ds,GetHexValue(hex,hex)); } else
if (strstr(hex,"ES")==hex) { hex+=2; SegSet16(es,GetHexValue(hex,hex)); } else
if (strstr(hex,"FS")==hex) { hex+=2; SegSet16(fs,GetHexValue(hex,hex)); } else
if (strstr(hex,"GS")==hex) { hex+=2; SegSet16(gs,GetHexValue(hex,hex)); } else
if (strstr(hex,"SS")==hex) { hex+=2; SegSet16(ss,GetHexValue(hex,hex)); } else
if (strstr(hex,"EAX")==hex) { hex+=3; reg_eax = GetHexValue(hex,hex); } else
if (strstr(hex,"EBX")==hex) { hex+=3; reg_ebx = GetHexValue(hex,hex); } else
if (strstr(hex,"ECX")==hex) { hex+=3; reg_ecx = GetHexValue(hex,hex); } else
if (strstr(hex,"EDX")==hex) { hex+=3; reg_edx = GetHexValue(hex,hex); } else
if (strstr(hex,"ESI")==hex) { hex+=3; reg_esi = GetHexValue(hex,hex); } else
if (strstr(hex,"EDI")==hex) { hex+=3; reg_edi = GetHexValue(hex,hex); } else
if (strstr(hex,"EBP")==hex) { hex+=3; reg_ebp = GetHexValue(hex,hex); } else
if (strstr(hex,"ESP")==hex) { hex+=3; reg_esp = GetHexValue(hex,hex); } else
if (strstr(hex,"EIP")==hex) { hex+=3; reg_eip = GetHexValue(hex,hex); } else
if (strstr(hex,"AF")==hex) { hex+=2; flags.af = (GetHexValue(hex,hex)!=0); } else
if (strstr(hex,"CF")==hex) { hex+=2; flags.cf = (GetHexValue(hex,hex)!=0); } else
if (strstr(hex,"DF")==hex) { hex+=2; flags.df = (GetHexValue(hex,hex)!=0); } else
if (strstr(hex,"IF")==hex) { hex+=2; flags.intf = (GetHexValue(hex,hex)!=0); } else
if (strstr(hex,"OF")==hex) { hex+=3; flags.of = (GetHexValue(hex,hex)!=0); } else
if (strstr(hex,"ZF")==hex) { hex+=3; flags.zf = (GetHexValue(hex,hex)!=0); } else
if (strstr(hex,"PF")==hex) { hex+=3; flags.pf = (GetHexValue(hex,hex)!=0); } else
{ return false; };
return true;
};
bool ParseCommand(char* str)
{
char* found = str;
@ -604,6 +683,17 @@ bool ParseCommand(char* str)
LOG_DEBUG("DEBUG: Set breakpoint at %04X:%04X",seg,ofs);
return true;
}
#if C_HEAVY_DEBUG
found = strstr(str,"BPM ");
if (found) { // Add new breakpoint
found+=3;
Bit16u seg = GetHexValue(found,found);found++; // skip ":"
Bit32u ofs = GetHexValue(found,found);
CBreakpoint::AddMemBreakpoint(seg,ofs);
LOG_DEBUG("DEBUG: Set memory breakpoint at %04X:%04X",seg,ofs);
return true;
}
#endif
found = strstr(str,"BPINT");
if (found) { // Add Interrupt Breakpoint
found+=5;
@ -666,6 +756,30 @@ bool ParseCommand(char* str)
LOG_DEBUG("DEBUG: Logfile LOGCPU.TXT created.");
return true;
}
found = strstr(str,"SR ");
if (found) { // Set register value
found+=2;
if (ChangeRegister(found)) LOG_DEBUG("DEBUG: Set Register success.");
else LOG_DEBUG("DEBUG: Set Register failure.");
return true;
}
found = strstr(str,"SM ");
if (found) { // Set memory with following values
found+=3;
Bit16u seg = GetHexValue(found,found); found++;
Bit32u ofs = GetHexValue(found,found); found++;
Bit16u count = 0;
while (*found) {
while (*found==' ') found++;
if (*found) {
Bit8u value = GetHexValue(found,found); found++;
mem_writeb(PhysMake(seg,ofs+count),value);
count++;
}
};
LOG_DEBUG("DEBUG: Memory changed.");
return true;
}
found = strstr(str,"INTT ");
if (found) { // Create Cpu log file
found+=4;
@ -688,6 +802,15 @@ bool ParseCommand(char* str)
Interrupt(intNr);
return true;
}
#if C_HEAVY_DEBUG
found = strstr(str,"HEAVYLOG");
if (found) { // Create Cpu log file
logHeavy = !logHeavy;
if (logHeavy) LOG_DEBUG("DEBUG: Heavy cpu logging on.");
else LOG_DEBUG("DEBUG: Heavy cpu logging off.");
return true;
}
#endif
if ((*str=='H') || (*str=='?')) {
wprintw(dbg.win_out,"Debugger keys:\n");
wprintw(dbg.win_out,"--------------------------------------------------------------------------\n");
@ -703,11 +826,19 @@ bool ParseCommand(char* str)
wprintw(dbg.win_out,"BP [segment]:[offset] - Set breakpoint\n");
wprintw(dbg.win_out,"BPINT [intNr] * - Set interrupt breakpoint\n");
wprintw(dbg.win_out,"BPINT [intNr] [ah] - Set interrupt breakpoint with ah\n");
#if C_HEAVY_DEBUG
wprintw(dbg.win_out,"BPM [segment]:[offset] - Set memory breakpoint (memory change)\n");
#endif
wprintw(dbg.win_out,"BPLIST - List breakpoints\n");
wprintw(dbg.win_out,"BPDEL [bpNr] / * - Delete breakpoint nr / all\n");
wprintw(dbg.win_out,"C / D [segment]:[offset] - Set code / data view address\n");
wprintw(dbg.win_out,"INT [nr] / INTT [nr] - Execute / Trace into Iinterrupt\n");
wprintw(dbg.win_out,"LOG [num] - Write cpu log file\n");
#if C_HEAVY_DEBUG
wprintw(dbg.win_out,"HEAVYLOG - Enable/Disable automatic cpu log for INT CD\n");
#endif
wprintw(dbg.win_out,"SR [reg] [value] - Set register value\n");
wprintw(dbg.win_out,"SM [seg]:[off] [val] [.]..- Set memory with following values\n");
wprintw(dbg.win_out,"H - Help\n");
wrefresh(dbg.win_out);
return TRUE;
@ -744,22 +875,28 @@ Bit32u DEBUG_CheckKeys(void) {
if (key>0) {
switch (toupper(key)) {
case '1':
ret=(*cpudecoder)(100);
CPU_Cycles = 100;
ret=(*cpudecoder)();
break;
case '2':
ret=(*cpudecoder)(500);
CPU_Cycles = 500;
ret=(*cpudecoder)();
break;
case '3':
ret=(*cpudecoder)(1000);
CPU_Cycles = 1000;
ret=(*cpudecoder)();
break;
case '4':
ret=(*cpudecoder)(5000);
CPU_Cycles = 5000;
ret=(*cpudecoder)();
break;
case '5':
ret=(*cpudecoder)(10000);
CPU_Cycles = 10000;
ret=(*cpudecoder)();
break;
case 'q':
ret=(*cpudecoder)(5);
CPU_Cycles = 5;
ret=(*cpudecoder)();
break;
case 'D': dataSeg = SegValue(ds);
dataOfs = reg_si;
@ -813,14 +950,18 @@ Bit32u DEBUG_CheckKeys(void) {
if (StepOver()) return 0;
else {
skipFirstInstruction = true; // for heavy debugger
Bitu ret=(*cpudecoder)(1);
CPU_Cycles = 1;
Bitu ret=(*cpudecoder)();
SetCodeWinStart();
CBreakpoint::ignoreOnce = 0;
}
break;
case KEY_F(11): // trace into
skipFirstInstruction = true; // for heavy debugger
ret = (*cpudecoder)(1);
CPU_Cycles = 1;
ret = (*cpudecoder)();
SetCodeWinStart();
CBreakpoint::ignoreOnce = 0;
break;
// default:
@ -868,10 +1009,20 @@ static void DEBUG_RaiseTimerIrq(void) {
PIC_ActivateIRQ(0);
}
static void LogInstruction(Bit16u segValue, Bit32u eipValue, char* buffer)
{
PhysPt start = PhysMake(segValue,eipValue);
char dline[200];Bitu size;
size = DasmI386(dline, start, reg_eip, false);
Bitu len = strlen(dline);
if (len<30) for (Bitu i=0; i<30-len; i++) strcat(dline," ");
// Get register values
sprintf(buffer,"%04X:%08X %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X\n",segValue,eipValue,dline,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(es),SegValue(fs),SegValue(gs),SegValue(ss),get_CF(),get_ZF(),get_SF(),get_OF(),get_AF(),get_PF());
};
static bool DEBUG_Log_Loop(int count) {
char buffer[512];
getcwd(buffer,512);
FILE* f = fopen("LOGCPU.TXT","wt");
if (!f) return false;
@ -884,23 +1035,17 @@ static bool DEBUG_Log_Loop(int count) {
// Get disasm
Bit16u csValue = SegValue(cs);
Bit32u eipValue = reg_eip;
PhysPt start=Segs[cs].phys+reg_eip;
char dline[200];Bitu size;
size = DasmI386(dline, start, reg_eip, false);
Bitu len = strlen(dline);
if (len<30) for (Bitu i=0; i<30-len; i++) strcat(dline," ");
PIC_IRQAgain=false;
ret=(*cpudecoder)(1);
// Get register values
char buffer[512];
sprintf(buffer,"%04X:%08X %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X\n",csValue,eipValue,dline,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(ds),SegValue(es),SegValue(fs),SegValue(gs),SegValue(ss),get_CF(),get_ZF(),get_SF(),get_OF(),get_AF(),get_PF());
LogInstruction(csValue,eipValue,buffer);
fprintf(f,"%s",buffer);
CPU_Cycles = 1;
ret=(*cpudecoder)();
count--;
if (count==0) break;
} while (!ret && PIC_IRQAgain);
} while (!ret);
if (ret) break;
} while (count>0);
@ -920,15 +1065,42 @@ public:
void Run(void)
{
char filename[128];
char args[128];
char args[256];
cmd->FindCommand(1,temp_line);
strncpy(filename,temp_line.c_str(),128);
cmd->FindCommand(2,temp_line);
strncpy(args,temp_line.c_str(),128);
// Read commandline
Bit16u i =2;
bool ok = false;
args[0] = 0;
do {
ok = cmd->FindCommand(i++,temp_line);
strncat(args,temp_line.c_str(),256);
strncat(args," ",256);
} while (ok);
// Start new shell and execute prog
active = true;
DOS_Shell shell;
shell.Execute(filename,args);
// Save cpu state....
Bit16u oldcs = SegValue(cs);
Bit32u oldeip = reg_eip;
Bit16u oldss = SegValue(ss);
Bit32u oldesp = reg_esp;
// Workaround : Allocate Stack Space
Bit16u segment;
Bit16u size = 0x200 / 0x10;
if (DOS_AllocateMemory(&segment,&size)) {
SegSet16(ss,segment);
reg_sp = 0x200;
// Start shell
DOS_Shell shell;
shell.Execute(filename,args);
DOS_FreeMemory(segment);
}
// set old reg values
SegSet16(ss,oldss);
reg_esp = oldesp;
SegSet16(cs,oldcs);
reg_eip = oldeip;
};
private:
@ -954,6 +1126,9 @@ void DEBUG_SetupConsole(void)
{
#ifdef WIN32
WIN32_Console();
#else
printf("\e[8;50;80t"); //resize terminal
fflush(NULL);
#endif
memset((void *)&dbg,0,sizeof(dbg));
debugging=false;
@ -987,8 +1162,53 @@ void DEBUG_Init(Section* sec) {
#if C_HEAVY_DEBUG
const Bit16u LOGCPUMAX = 200;
static Bit16u logCpuCS [LOGCPUMAX];
static Bit32u logCpuEIP[LOGCPUMAX];
static Bit32u logCount = 0;
typedef struct SLogInst {
char buffer[256];
} TLogInst;
TLogInst logInst[LOGCPUMAX];
void DEBUG_HeavyLogInstruction(void)
{
LogInstruction(SegValue(cs),reg_eip,logInst[logCount++].buffer);
if (logCount>=LOGCPUMAX) logCount = 0;
};
void DEBUG_HeavyWriteLogInstruction(void)
{
if (!logHeavy) return;
LOG_DEBUG("DEBUG: Creating cpu log LOGCPU_INT_CD.TXT");
FILE* f = fopen("LOGCPU_INT_CD.TXT","wt");
if (!f) {
LOG_DEBUG("DEBUG: Failed.");
return;
}
Bit16u startLog = logCount;
do {
// Write Intructions
fprintf(f,"%s",logInst[startLog++].buffer);
if (startLog>=LOGCPUMAX) startLog = 0;
} while (startLog!=logCount);
fclose(f);
LOG_DEBUG("DEBUG: Done.");
};
bool DEBUG_HeavyIsBreakpoint(void)
{
// LogInstruction
if (logHeavy) DEBUG_HeavyLogInstruction();
if (skipFirstInstruction) {
skipFirstInstruction = false;
return false;

View File

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

View File

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

View File

@ -16,6 +16,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "dos_inc.h"
#include "../ints/int10.h"
#define NUMBER_ANSI_DATA 10
class device_CON : public DOS_Device {
public:
device_CON();
@ -23,17 +28,36 @@ public:
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
void ClearAnsi(void);
Bit16u GetInformation(void);
private:
Bit8u cache;
struct ansi { /* should create a constructor which fills them with the appriorate values */
bool esc;
bool sci;
Bit8u attr;
Bit8u data[NUMBER_ANSI_DATA];
Bit8u numberofarg;
Bit16u nrows;
Bit16u ncols;
Bit8s savecol;
Bit8s saverow;
} ansi;
};
void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page);
void INT10_SetCursorPos(Bit8u row,Bit8u col,Bit8u page);
bool device_CON::Read(Bit8u * data,Bit16u * size) {
Bit16u oldax=reg_ax;
Bit16u count=0;
if ((cache) && (*size)) {
data[count++]=cache;
cache=0;
if(dos.echo) {
INT10_TeletypeOutput(cache,7,false,0);
}
cache=0;
}
while (*size>count) {
reg_ah=0;
@ -41,11 +65,26 @@ bool device_CON::Read(Bit8u * data,Bit16u * size) {
switch(reg_al) {
case 13:
data[count++]=0x0D;
// if (*size>count) data[count++]=0x0A;
// else cache=0x0A;
*size=count;
if (*size>count) data[count++]=0x0A; // it's only expanded if there is room for it. (NO cache)
*size=count;
reg_ax=oldax;
if(dos.echo) {
INT10_TeletypeOutput(13,7,false,0); //maybe don't do this ( no need for it actually ) (but it's compatible)
INT10_TeletypeOutput(10,7,false,0);
}
return true;
break;
case 8:
if(*size==1) data[count++]=reg_al; //one char at the time so give back that BS
else if(count) { //Remove data if it exists (extended keys don't go right)
data[count--]=0;
INT10_TeletypeOutput(8,7,false,0);
INT10_TeletypeOutput(' ',7,false,0);
} else {
continue; //no data read yet so restart whileloop.
}
break;
default:
data[count++]=reg_al;
break;
@ -54,27 +93,247 @@ bool device_CON::Read(Bit8u * data,Bit16u * size) {
if (*size>count) data[count++]=reg_ah;
else cache=reg_ah;
break;
}
}
if(dos.echo) { //what to do if *size==1 and character is BS ?????
INT10_TeletypeOutput(reg_al,7,false,0);
}
}
*size=count;
reg_ax=oldax;
return true;
}
extern void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page);
bool device_CON::Write(Bit8u * data,Bit16u * size) {
Bit16u count=0;
while (*size>count) {
Bitu i;
Bit8s col,row;
static bool ansiwarned=false;
INT10_TeletypeOutput(data[count],7,false,0);
count++;
while (*size>count) {
if (!ansi.esc){
if(data[count]=='\033') {
/*clear the datastructure */
ClearAnsi();
/* start the sequence */
ansi.esc=true;
count++;
if(!ansiwarned) {
LOG_WARN("ANSI sequences detected. enabling ansi support"); /* maybe LOG_MSG */
ansiwarned=true;
}
continue;
} else {
INT10_TeletypeOutput(data[count],ansi.attr,true,0);
count++;
continue;
};
};
/* ansi.esc=true */
if(!ansi.sci){
switch(data[count]){
case '[':
ansi.sci=true;
break;
case '7': /* save cursor pos +attr */
case '8': /* restore this (Wonder if this is actually used) */
case 'D':/* scrolling DOWN*/
case 'M':/* scrolling UP*/
default:
LOG_DEBUG("ANSI: unknown char %c after a esc",data[count]); /*prob () */
ClearAnsi();
break;
}
count++;
continue;
}
/*ansi.esc and ansi.sci are true */
switch(data[count]){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
ansi.data[ansi.numberofarg]=10*ansi.data[ansi.numberofarg]+(data[count]-'0');
break;
case ';': /* till a max of NUMBER_ANSI_DATA */
ansi.numberofarg++;
break;
case 'm': /* SGR */
for(i=0;i<=ansi.numberofarg;i++){
switch(ansi.data[i]){
case 0: /* normal */
ansi.attr=0x7;
break;
case 1: /* bold mode on*/
ansi.attr|=0x8;
break;
case 4: /* underline */
LOG_DEBUG("ANSI:no support for underline yet");
break;
case 5: /* blinking */
LOG_DEBUG("ANSI:no support for blinking yet");
break;
case 7: /* reverse */
LOG_DEBUG("ANSI:no support for reverse yet");
break;
case 30: /* fg color black */
ansi.attr&=0xf8;
ansi.attr|=0x0;
break;
case 31: /* fg color red */
ansi.attr&=0xf8;
ansi.attr|=0x4;
break;
case 32: /* fg color green */
ansi.attr&=0xf8;
ansi.attr|=0x2;
break;
case 33: /* fg color yellow */
ansi.attr&=0xf8;
ansi.attr|=0x6;
break;
case 34: /* fg color blue */
ansi.attr&=0xf8;
ansi.attr|=0x1;
break;
case 35: /* fg color magenta */
ansi.attr&=0xf8;
ansi.attr|=0x5;
break;
case 36: /* fg color cyan */
ansi.attr&=0xf8;
ansi.attr|=0x3;
break;
case 37: /* fg color white */
ansi.attr&=0xf8;
ansi.attr|=0x7;
break;
case 40:
ansi.attr&=0x8f;
ansi.attr|=0x0;
break;
case 41:
ansi.attr&=0x8f;
ansi.attr|=0x40;
break;
case 42:
ansi.attr&=0x8f;
ansi.attr|=0x20;
break;
case 43:
ansi.attr&=0x8f;
ansi.attr|=0x60;
break;
case 44:
ansi.attr&=0x8f;
ansi.attr|=0x10;
break;
case 45:
ansi.attr&=0x8f;
ansi.attr|=0x50;
break;
case 46:
ansi.attr&=0x8f;
ansi.attr|=0x30;
break;
case 47:
ansi.attr&=0x8f;
ansi.attr|=0x70;
break;
default:
break;
}
}
ClearAnsi();
break;
case 'f':
case 'H':/* Cursor Pos*/
if(ansi.data[0]==0) ansi.data[0]=1;
if(ansi.data[1]==0) ansi.data[1]=1;
INT10_SetCursorPos(--(ansi.data[0]),--(ansi.data[1]),0); /*ansi=1 based, int10 is 0 based */
ClearAnsi();
break;
case 'A': /* cursor up*/
col=CURSOR_POS_COL(0) ;
row=CURSOR_POS_ROW(0) - (ansi.data[0]? ansi.data[0] : 1);
INT10_SetCursorPos(row,col,0);
ClearAnsi();
break;
case 'C': /*cursor forward */
col=CURSOR_POS_COL(0) + (ansi.data[0]? ansi.data[0] : 1);
row=CURSOR_POS_ROW(0);
while(col>=ansi.ncols) {
row++;
col = col - ansi.ncols; // should depend on linebrake mode
}
INT10_SetCursorPos(row,col,0);
ClearAnsi();
break;
case 'J': /*erase screen and move cursor home*/
if(ansi.data[0]==0) ansi.data[0]=2;
if(ansi.data[0]!=2) {/* only number 2 (the standard one supported) */
LOG_DEBUG("ANSI: esc[%dJ called : not supported",ansi.data[0]);
break;
}
for(i=0;i<(Bitu)ansi.ncols*ansi.nrows;i++) INT10_TeletypeOutput(' ',ansi.attr,true,0);
ClearAnsi();
INT10_SetCursorPos(0,0,0);
break;
case 'h': /* set MODE (if code =7 enable linewrap) */
case 'I': /*RESET MODE */
LOG_DEBUG("ANSI: set/reset mode called(not supported)");
ClearAnsi();
break;
case 'D': /*Cursor Backward */
col=CURSOR_POS_COL(0) - (ansi.data[0]? ansi.data[0] : 1);
row=CURSOR_POS_ROW(0);
while(col<0) {
row--;
col = col + ansi.ncols ; // should depend on linebrake mode
}
INT10_SetCursorPos(row,col,0);
ClearAnsi();
break;
case 'u': /* Restore Cursor Pos */
INT10_SetCursorPos(ansi.saverow,ansi.savecol,0);
ClearAnsi();
break;
case 's': /* SAVE CURSOR POS */
ansi.savecol=CURSOR_POS_COL(0);
ansi.saverow=CURSOR_POS_ROW(0);
ClearAnsi();
break;
case 'K':/* erase till end of line */
case 'l':/* (if code =7) disable linewrap */
case 'p':/* reassign keys (needs strings) */
case 'i':/* printer stuff */
default:
LOG_DEBUG("ANSI: unhandled char %c in esc[",data[count]);
ClearAnsi();
break;
}
count++;
}
*size=count;
return true;
}
bool device_CON::Seek(Bit32u * pos,Bit32u type) {
return false;
// seek is valid
*pos = 0;
return true;
}
bool device_CON::Close() {
@ -89,9 +348,23 @@ Bit16u device_CON::GetInformation(void) {
return 0x8093; /* Key Available */
};
device_CON::device_CON() {
name="CON";
cache=0;
ansi.esc=false;
ansi.sci=false;
ansi.attr=0x7;
ansi.numberofarg=0;
for(Bit8u i=0; 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;
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) {
dos.errorcode=code;
@ -43,15 +43,14 @@ static Bitu DOS_21Handler(void) {
char name1[DOSNAMEBUF+1];
char name2[DOSNAMEBUF+1];
switch (reg_ah) {
case 0x00: /* Terminate Program */
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
case 0x01: /* Read character from STDIN, with echo */
{
Bit8u c;Bit16u n=1;
dos.echo=true;
DOS_ReadFile(STDIN,&c,&n);
reg_al=c;
DOS_WriteFile(STDOUT,&c,&n);
dos.echo=false;
}
break;
case 0x02: /* Write character to STDOUT */
@ -71,6 +70,7 @@ static Bitu DOS_21Handler(void) {
{
//TODO Make this better according to standards
if (!DOS_GetSTDINStatus()) {
reg_al=0;
CALLBACK_SZF(true);
break;
}
@ -95,7 +95,7 @@ static Bitu DOS_21Handler(void) {
reg_al=c;
break;
};
case 0x08: /* Direct Character Input, without echo */
case 0x08: /* Direct Character Input, without echo (checks for breaks officially :)*/
{
Bit8u c;Bit16u n=1;
DOS_ReadFile (STDIN,&c,&n);
@ -161,10 +161,10 @@ static Bitu DOS_21Handler(void) {
break;
case 0x0e: /* Select Default Drive */
DOS_SetDefaultDrive(reg_dl);
reg_al=26;
reg_al=DOS_DRIVES;
break;
case 0x0f: /* Open File using FCB */
if(DOS_FCBOpenCreate(SegValue(ds),reg_dx)){
if(DOS_FCBOpen(SegValue(ds),reg_dx)){
reg_al=0;
}else{
reg_al=0xff;
@ -204,13 +204,12 @@ static Bitu DOS_21Handler(void) {
LOG_DEBUG("DOS:0x14 FCB-Read used, result:al=%d",reg_al);
break;
case 0x15: /* Sequential write to FCB */
if (DOS_FCBWrite(SegValue(ds),reg_dx,0)) reg_al = 0x00;
else reg_al = 0x01;
reg_al=DOS_FCBWrite(SegValue(ds),reg_dx,0);
LOG_DEBUG("DOS:0x15 FCB-Write used, result:al=%d",reg_al);
break;
case 0x16: /* Create or truncate file using FCB */
if (DOS_FCBOpenCreate(SegValue(ds),reg_dx)) reg_al = 0x00;
else reg_al = 0x01;
if (DOS_FCBCreate(SegValue(ds),reg_dx)) reg_al = 0x00;
else reg_al = 0xFF;
LOG_DEBUG("DOS:0x16 FCB-Create used, result:al=%d",reg_al);
break;
case 0x17: /* Rename file using FCB */
@ -218,18 +217,17 @@ static Bitu DOS_21Handler(void) {
else reg_al = 0xFF;
break;
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;
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;
case 0x21: /* Read random record from FCB */
reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,1,true);
LOG_DEBUG("DOS:0x21 FCB-Random read used, result:al=%d",reg_al);
break;
case 0x22: /* Write random record to FCB */
if (DOS_FCBRandomWrite(SegValue(ds),reg_dx,1,true)) reg_al = 0x00;
else reg_al = 0x01;
reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,1,true);
LOG_DEBUG("DOS:0x28 FCB-Random write used, result:al=%d",reg_al);
break;
case 0x23: /* Get file size for FCB */
@ -241,30 +239,21 @@ static Bitu DOS_21Handler(void) {
break;
case 0x27: /* Random block read from FCB */
reg_al = DOS_FCBRandomRead(SegValue(ds),reg_dx,reg_cx,false);
LOG_DEBUG("DOS:0x27 FCB-Random read used, result:al=%d",reg_al);
LOG_DEBUG("DOS:0x27 FCB-Random(block) read used, result:al=%d",reg_al);
break;
case 0x28: /* Random Block write to FCB */
if (DOS_FCBRandomWrite(SegValue(ds),reg_dx,reg_cx,false)) reg_al = 0x00;
else reg_al = 0x01;
LOG_DEBUG("DOS:0x28 FCB-Random write used, result:al=%d",reg_al);
reg_al=DOS_FCBRandomWrite(SegValue(ds),reg_dx,reg_cx,false);
LOG_DEBUG("DOS:0x28 FCB-Random(block) write used, result:al=%d",reg_al);
break;
case 0x29: /* Parse filename into FCB */
{ Bit8u difference;
char string[1024];
MEM_StrCopy(SegPhys(ds)+reg_si,string,1024);
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);
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 */
reg_al=DOS_GetDefaultDrive();
break;
@ -276,6 +265,7 @@ static Bitu DOS_21Handler(void) {
}
break;
case 0x1f: /* Get drive parameter block for default drive */
case 0x32: /* Get drive parameter block for specific drive */
E_Exit("DOS:Unhandled call %02X",reg_ah);
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());
break;
case 0x2a: /* Get System Date */
reg_al=0; /* It's always sunday TODO find that correct formula */
reg_cx=dos.date.year;
reg_dh=dos.date.month;
reg_dl=dos.date.day;
{
int a = (14 - dos.date.month)/12;
int y = dos.date.year - a;
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;
case 0x2b: /* Set System Date */
//TODO Check for months with less then 31 days
if (reg_cx<1980) { 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;}
@ -307,9 +301,9 @@ static Bitu DOS_21Handler(void) {
Bit32u ticks=mem_readd(BIOS_TIMER);
Bit32u seconds=(ticks*10)/182;
reg_ch=(Bit8u)(seconds/3600);
reg_cl=(Bit8u)(seconds % 3600)/60;
reg_cl=(Bit8u)((seconds % 3600)/60);
reg_dh=(Bit8u)(seconds % 60);
reg_dl=(Bit8u)(ticks % 19)*5;
reg_dl=(Bit8u)((ticks % 20)*5); /* 0-19 ->0-95 */
}
break;
case 0x2d: /* Set System Time */
@ -367,7 +361,8 @@ static Bitu DOS_21Handler(void) {
break;
case 0x36: /* Get Free Disk Space */
{
Bit16u bytes,sectors,clusters,free;
Bit16u bytes,clusters,free;
Bit8u sectors;
if (DOS_GetFreeDiskSpace(reg_dl,&bytes,&sectors,&clusters,&free)) {
reg_ax=sectors;
reg_bx=free;
@ -459,7 +454,7 @@ static Bitu DOS_21Handler(void) {
case 0x3f: /* READ Read from file or device */
{
Bit16u toread=reg_cx;
if (reg_cx+reg_dx>0xffff) LOG_DEBUG("DOS:READ:Buffer overflow %d",reg_cx+reg_dx);
dos.echo=true;
if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread);
reg_ax=toread;
@ -468,12 +463,12 @@ static Bitu DOS_21Handler(void) {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
dos.echo=false;
break;
}
case 0x40: /* WRITE Write to file or device */
{
Bit16u towrite=reg_cx;
if (reg_cx+reg_dx>0xffff) LOG_DEBUG("DOS:WRITE:Buffer overflow %d",reg_cx+reg_dx);
MEM_BlockRead(SegPhys(ds)+reg_dx,dos_copybuf,towrite);
if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) {
reg_ax=towrite;
@ -604,8 +599,11 @@ static Bitu DOS_21Handler(void) {
}
break;
//TODO Check for use of execution state AL=5
case 0x00:
reg_ax=0x4c00; /* Terminate Program */
case 0x4c: /* EXIT Terminate with return code */
{
{
if (DOS_Terminate(false)) {
/* This can't ever return false normally */
} else {
@ -652,9 +650,10 @@ static Bitu DOS_21Handler(void) {
//TODO Think hard how shit this is gonna be
//And will any game ever use this :)
case 0x53: /* Translate BIOS parameter block to drive parameter block */
//YEAH RIGHT
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x54: /* Get verify flag */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
reg_al=dos.verify?1:0;
break;
case 0x55: /* Create Child PSP*/
DOS_NewPSP(reg_dx,reg_si);
@ -686,9 +685,10 @@ static Bitu DOS_21Handler(void) {
case 0x58: /* Get/Set Memory allocation strategy */
switch (reg_al) {
case 0: /* Get Strategy */
reg_ax=0; //Low memory first fit
reg_ax=DOS_GetMemAllocStrategy();
break;
case 1: /* Set Strategy */
DOS_SetMemAllocStrategy(reg_bx);
break;
default:
LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al);
@ -733,8 +733,8 @@ static Bitu DOS_21Handler(void) {
}
break;
}
case 0x5c: /* FLOCK File region locking */
case 0x5d: /* Network Functions */
case 0x5e: /* More Network Functions */
case 0x5f: /* And Even More Network Functions */
E_Exit("DOS:Unhandled call %02X",reg_ah);
@ -752,10 +752,6 @@ static Bitu DOS_21Handler(void) {
case 0x62: /* Get Current PSP Address */
reg_bx=dos.psp;
break;
case 0x63: /* Weirdo double byte stuff */
reg_al=0xff;
LOG_WARN("DOS:0x63:Doubly byte characters not supported");
break;
case 0x64: /* Set device driver lookahead flag */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
@ -792,9 +788,6 @@ static Bitu DOS_21Handler(void) {
LOG_DEBUG("DOS:67:Set Handle Count not working");
CALLBACK_SCF(false);
break;
case 0x68: /* FFLUSH Commit file */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x69: /* Get/Set disk serial number */
{
switch(reg_al) {
@ -817,11 +810,21 @@ static Bitu DOS_21Handler(void) {
CALLBACK_SCF(true);
LOG_WARN("DOS:Windows long file name support call %2X",reg_al);
break;
case 0xE0:
LOG_DEBUG("DOS:E0:Unhandled, what should this call do?");
break;
case 0x68: /* FFLUSH Commit file */
case 0x63: /* Weirdo double byte stuff (fails but say it succeeded) available only in MSDOS 2.25 */
CALLBACK_SCF(false); //mirek
case 0xE0:
case 0x18: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x1d: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x1e: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x20: /* NULL Function for CP/M compatibility or Extended rename FCB */
case 0x6b: /* NULL Function */
case 0x61: /* UNUSED */
case 0xEF: /* Used in Ancient Art Of War CGA */
case 0x5d: /* Network Functions */
default:
E_Exit("DOS:Unhandled call %02X",reg_ah);
LOG_DEBUG("DOS:Unhandled call %02X al=%02X. Set al to default of 0",reg_ah,reg_al);
reg_al=0x00; /* default value */
break;
};
return CBRET_NONE;
@ -837,6 +840,22 @@ static Bitu DOS_20Handler(void) {
return CBRET_NONE;
}
static Bitu DOS_27Handler(void)
{
// Terminate & stay resident
Bit16u para = (reg_dx/16)+((reg_dx % 16)>0);
if (DOS_ResizeMemory(dos.psp,&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) {
MSG_Add("DOS_CONFIGFILE_HELP","Setting a memory size to 0 will disable it.\n");
@ -845,9 +864,21 @@ void DOS_Init(Section* sec) {
RealSetVec(0x20,CALLBACK_RealPointer(call_20));
call_21=CALLBACK_Allocate();
CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET);
CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET_STI);
RealSetVec(0x21,CALLBACK_RealPointer(call_21));
call_27=CALLBACK_Allocate();
CALLBACK_Setup(call_27,DOS_27Handler,CB_IRET);
RealSetVec(0x27,CALLBACK_RealPointer(call_27));
call_28=CALLBACK_Allocate();
CALLBACK_Setup(call_28,DOS_28Handler,CB_IRET);
RealSetVec(0x28,CALLBACK_RealPointer(call_28));
call_29=CALLBACK_Allocate();
CALLBACK_Setup(call_29,DOS_29Handler,CB_IRET);
RealSetVec(0x29,CALLBACK_RealPointer(call_29));
DOS_SetupFiles(); /* Setup system File tables */
DOS_SetupDevices(); /* Setup dos devices */
DOS_SetupTables();
@ -855,8 +886,16 @@ void DOS_Init(Section* sec) {
DOS_SetupPrograms();
DOS_SetupMisc(); /* Some additional dos interrupts */
DOS_SetDefaultDrive(25);
/* Execute the file that should be */
dos.version.major=5;
dos.version.minor=0;
// DOS_RunProgram(startname);
};
/* Setup time and date */
time_t curtime;struct tm *loctime;
curtime = time (NULL);loctime = localtime (&curtime);
dos.date.day=(Bit8u)loctime->tm_mday;
dos.date.month=(Bit8u)loctime->tm_mon+1;
dos.date.year=(Bit16u)loctime->tm_year+1900;
Bit32u ticks=(Bit32u)((loctime->tm_hour*3600+loctime->tm_min*60+loctime->tm_sec)*18.2);
mem_writed(BIOS_TIMER,ticks);
}

View File

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

View File

@ -208,7 +208,7 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
Bitu headersize,imagesize;
DOS_ParamBlock block(block_pt);
block.LoadData();
if (flags!=LOADNGO && flags!=OVERLAY) {
if (flags!=LOADNGO && flags!=OVERLAY && flags!=LOAD) {
E_Exit("DOS:Not supported execute mode %d for file %s",flags,name);
}
/* Check for EXE or COM File */
@ -271,12 +271,12 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
pos=headersize;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET);
while (imagesize>0x7FFF) {
readsize=0x8000;DOS_ReadFile(fhandle,loadaddress,&readsize);
if (readsize!=0x8000) E_Exit("Illegal header");
if (readsize!=0x8000) LOG_WARN("Illegal header");
loadaddress+=0x8000;imagesize-=0x8000;
}
if (imagesize>0) {
readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadaddress,&readsize);
if (readsize!=imagesize) E_Exit("Illegal header");
if (readsize!=imagesize) LOG_WARN("Illegal header");
}
/* Relocate the exe image */
Bit16u relocate;
@ -302,6 +302,20 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) {
csip=RealMake(loadseg+head.initCS,head.initIP);
sssp=RealMake(loadseg+head.initSS,head.initSP);
}
if (flags==LOAD) {
DOS_PSP callpsp(dos.psp);
/* Save the SS:SP on the PSP of calling program */
callpsp.SetStack(RealMakeSeg(ss,reg_sp));
/* Switch the psp's */
dos.psp=pspseg;
block.exec.initsssp = sssp;
block.exec.initcsip = csip;
block.SaveData();
return true;
}
if (flags==LOADNGO) {
/* Get Caller's program CS:IP of the stack and set termination address to that */
RealSetVec(0x22,RealMake(mem_readw(SegPhys(ss)+reg_sp+2),mem_readw(SegPhys(ss)+reg_sp)));

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 '\'':
upname[w++]=c;
break;
default:
@ -150,8 +151,10 @@ bool DOS_GetCurrentDir(Bit8u drive,char * buffer) {
}
bool DOS_ChangeDir(char * dir) {
Bit8u drive;char fulldir[DOS_PATHLENGTH];
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
if (Drives[drive]->TestDir(fulldir)) {
strcpy(Drives[drive]->curdir,fulldir);
return true;
@ -202,14 +205,14 @@ bool DOS_FindFirst(char * search,Bit16u attr) {
}
dta.SetupSearch(drive,(Bit8u)attr,pattern);
if (Drives[drive]->FindFirst(dir,dta)) return true;
DOS_SetError(DOSERR_FILE_NOT_FOUND);
DOS_SetError(DOSERR_NO_MORE_FILES);
return false;
}
bool DOS_FindNext(void) {
DOS_DTA dta(dos.dta);
if (Drives[dta.GetSearchDrive()]->FindNext(dta)) return true;
DOS_SetError(DOSERR_FILE_NOT_FOUND);
DOS_SetError(DOSERR_NO_MORE_FILES);
return false;
}
@ -397,7 +400,7 @@ bool DOS_Canonicalize(char * name,char * big) {
return true;
}
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) {
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free) {
if (drive==0) drive=DOS_GetDefaultDrive();
else drive--;
if ((drive>DOS_DRIVES) || (!Drives[drive])) {
@ -473,7 +476,6 @@ bool DOS_CreateTempFile(char * name,Bit16u * entry) {
}
#if 1
static bool FCB_MakeName2 (DOS_FCB & fcb, char* outname, Bit8u* outdrive){
char short_name[DOS_FCBNAME];
@ -626,7 +628,16 @@ static void SaveFindResult(DOS_FCB & find_fcb) {
fcb.SetSizeDateTime(size,date,time);
}
bool DOS_FCBOpenCreate(Bit16u seg,Bit16u offset) {
bool DOS_FCBCreate(Bit16u seg,Bit16u offset) {
DOS_FCB fcb(seg,offset);
char shortname[DOS_FCBNAME];Bit16u handle;
fcb.GetName(shortname);
if (!DOS_CreateFile(shortname,2,&handle)) return false;
fcb.FileOpen((Bit8u)handle);
return true;
}
bool DOS_FCBOpen(Bit16u seg,Bit16u offset) {
DOS_FCB fcb(seg,offset);
char shortname[DOS_FCBNAME];Bit16u handle;
fcb.GetName(shortname);
@ -687,7 +698,7 @@ Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset,Bit16u recno) {
return FCB_READ_PARTIAL;
}
bool DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno)
Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno)
{
DOS_FCB fcb(seg,offset);
Bit8u fhandle,cur_rec;Bit16u cur_block,rec_size;
@ -709,13 +720,19 @@ bool DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno)
}
Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) {
/* if restore is true :random read else random blok read.
* random read updates old block and old record to reflect the random data
* before the read!!!!!!!!! and the random data is not updated! (user must do this)
* Random block read updates these fields to reflect the state after the read!
*/
DOS_FCB fcb(seg,offset);
Bit32u random;Bit16u old_block;Bit8u old_rec;Bit8u error;
/* Set the correct record from the random data */
fcb.GetRandom(random);
if (restore) fcb.GetRecord(old_block,old_rec);
fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127));
if (restore) fcb.GetRecord(old_block,old_rec);//store this for after the read.
// Read records
for (int i=0; i<numRec; 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;
fcb.GetRecord(new_block,new_rec);
if (restore) fcb.SetRecord(old_block,old_rec);
/* Update the random record pointer with new position */
fcb.SetRandom(new_block*128+new_rec);
return error;
/* Update the random record pointer with new position only when restore is false*/
if(!restore) fcb.SetRandom(new_block*128+new_rec);
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);
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 */
fcb.GetRandom(random);
if (restore) fcb.GetRecord(old_block,old_rec);
fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127));
if (restore) fcb.GetRecord(old_block,old_rec);
/* Write records */
for (int i=0; i<numRec; i++) {
noerror = DOS_FCBWrite(seg,offset,i);
if (!noerror) break;
error = DOS_FCBWrite(seg,offset,i);// dos_fcbwrite return 0 false when true...
if (error!=0x00) break;
}
Bit16u new_block;Bit8u new_rec;
fcb.GetRecord(new_block,new_rec);
if (restore) fcb.SetRecord(old_block,old_rec);
/* Update the random record pointer with new position */
fcb.SetRandom(new_block*128+new_rec);
return noerror;
/* Update the random record pointer with new position only when restore is false */
if(!restore) fcb.SetRandom(new_block*128+new_rec);
return error;
}
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);
}
#endif
bool DOS_FileExists(char * name) {
char fullname[DOS_PATHLENGTH];Bit8u drive;
@ -795,7 +812,7 @@ bool DOS_FileExists(char * name) {
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;
else drive--;
if (!Drives[drive]) return false;

View File

@ -86,6 +86,13 @@ bool DOS_IOCTL(void) {
return false;
}
break;
case 0x06: /* Get Input Status */
if(reg_bx==0x00) { /* might work for other handles, but tested it only for STDIN */
if(Files[handle]->GetInformation() & 0x40) reg_al=0x00; else
reg_al=0xFF;
return true;
break;
}
default:
LOG_ERROR("DOS:IOCTL Call %2X unhandled",reg_al);
return false;
@ -96,7 +103,8 @@ bool DOS_IOCTL(void) {
bool DOS_GetSTDINStatus(void) {
Bit32u handle=RealHandle(STDIN);
if (Files[handle]->GetInformation() & 64) return false;
if (handle==0xFF) return false;
if (Files[handle] && (Files[handle]->GetInformation() & 64)) return false;
return true;
};

View File

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

View File

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

View File

@ -25,6 +25,7 @@
#include "cross.h"
#include "regs.h"
#include "callback.h"
#include "../shell/shell_inc.h"
class MOUNT : public Program {
public:
@ -84,7 +85,8 @@ public:
return;
}
if (temp_line[temp_line.size()-1]!=CROSS_FILESPLIT) temp_line+=CROSS_FILESPLIT;
newdrive=new localDrive(temp_line.c_str(),sizes[0],sizes[1],sizes[2],sizes[3],mediaid);
Bit8u bit8size=(Bit8u) sizes[1];
newdrive=new localDrive(temp_line.c_str(),sizes[0],bit8size,sizes[2],sizes[3],mediaid);
}
cmd->FindCommand(1,temp_line);
if (temp_line.size()>1) goto showusage;
@ -220,6 +222,69 @@ static void UPCASE_ProgramStart(Program * * make) {
}
#endif
// LOADFIX
class LOADFIX : public Program {
public:
void Run(void);
};
void LOADFIX::Run(void)
{
Bit16u commandNr = 1;
Bit16u kb = 64;
if (cmd->FindCommand(commandNr,temp_line)) {
if (temp_line[0]=='-') {
char ch = temp_line[1];
if ((*upcase(&ch)=='D') || (*upcase(&ch)=='F')) {
// Deallocate all
DOS_FreeProcessMemory(0x40);
WriteOut(MSG_Get("PROGRAM_LOADFIX_DEALLOCALL"),kb);
return;
} else {
// Set mem amount to allocate
kb = atoi(temp_line.c_str()+1);
if (kb==0) kb=64;
commandNr++;
}
}
}
// Allocate Memory
Bit16u segment;
Bit16u blocks = kb*1024/16;
if (DOS_AllocateMemory(&segment,&blocks)) {
MCB* pmcb = (MCB*)HostMake(segment-1,0);
pmcb->psp_segment = 0x40; // use fake segment
WriteOut(MSG_Get("PROGRAM_LOADFIX_ALLOC"),kb);
// Prepare commandline...
if (cmd->FindCommand(commandNr++,temp_line)) {
// get Filename
char filename[128];
strncpy(filename,temp_line.c_str(),128);
// Setup commandline
bool ok;
char args[256];
args[0] = 0;
do {
ok = cmd->FindCommand(commandNr++,temp_line);
strncat(args,temp_line.c_str(),256);
strncat(args," ",256);
} while (ok);
// Use shell to start program
DOS_Shell shell;
shell.Execute(filename,args);
DOS_FreeMemory(segment);
WriteOut(MSG_Get("PROGRAM_LOADFIX_DEALLOC"),kb);
}
} else {
WriteOut(MSG_Get("PROGRAM_LOADFIX_ERROR"),kb);
}
};
static void LOADFIX_ProgramStart(Program * * make) {
*make=new LOADFIX;
}
void DOS_SetupPrograms(void) {
/*Add Messages */
MSG_Add("PROGRAM_MOUNT_STATUS_2","Drive %c is mounted as %s\n");
@ -233,6 +298,11 @@ void DOS_SetupPrograms(void) {
MSG_Add("PROGRAM_MEM_EXTEND","%10d Kb free extended memory\n");
MSG_Add("PROGRAM_MEM_EXPAND","%10d Kb free expanded memory\n");
MSG_Add("PROGRAM_LOADFIX_ALLOC","%d kb allocated.\n");
MSG_Add("PROGRAM_LOADFIX_DEALLOC","%d kb freed.\n");
MSG_Add("PROGRAM_LOADFIX_DEALLOCALL","Used memory freed.\n");
MSG_Add("PROGRAM_LOADFIX_ERROR","Memory allocation error.\n");
#if !defined (WIN32) /* Unix */
MSG_Add("PROGRAM_UPCASE_ERROR_DIR","Failed to open directory %s\n");
MSG_Add("PROGRAM_UPCASE_SCANNING_DIR","Scanning directory %s\n");
@ -247,6 +317,7 @@ void DOS_SetupPrograms(void) {
/*regular setup*/
PROGRAMS_MakeFile("MOUNT.COM",MOUNT_ProgramStart);
PROGRAMS_MakeFile("MEM.COM",MEM_ProgramStart);
PROGRAMS_MakeFile("LOADFIX.COM",LOADFIX_ProgramStart);
#if !defined (WIN32) /* Unix */
PROGRAMS_MakeFile("UPCASE.COM",UPCASE_ProgramStart);
#endif

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
char newname[CROSS_LEN];
strcpy(newname,basedir);
@ -188,6 +188,14 @@ bool localDrive::TestDir(char * dir) {
strcpy(newdir,basedir);
strcat(newdir,dir);
CROSS_FILENAME(newdir);
// Skip directory test, if "\"
Bit16u len = strlen(newdir);
if ((len>0) && (newdir[len-1]!='\\')) {
// It has to be a directory !
struct stat test;
if (stat(newdir,&test)==-1) return false;
if ((test.st_mode & S_IFDIR)==0) return false;
};
int temp=access(newdir,F_OK);
return (temp==0);
}
@ -206,7 +214,7 @@ bool localDrive::Rename(char * oldname,char * newname) {
};
bool localDrive::AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) {
bool localDrive::AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) {
/* Always report 100 mb free should be enough */
/* Total size is always 1 gb */
*_bytes_sector=allocation.bytes_sector;
@ -251,7 +259,7 @@ Bit8u localDrive::GetMediaByte(void) {
return allocation.mediaid;
}
localDrive::localDrive(const char * startdir,Bit16u _bytes_sector,Bit16u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid) {
localDrive::localDrive(const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid) {
strcpy(basedir,startdir);
sprintf(info,"local directory %s",startdir);
srch_opendir=NULL;

View File

@ -204,7 +204,7 @@ bool Virtual_Drive::Rename(char * oldname,char * newname) {
return false;
}
bool Virtual_Drive::AllocationInfo(Bit16u * _bytes_sector,Bit16u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) {
bool Virtual_Drive::AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) {
/* Always report 100 mb free should be enough */
/* Total size is always 1 gb */
*_bytes_sector=512;

View File

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

View File

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

View File

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

View File

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

View File

@ -84,7 +84,7 @@ install_sh = @install_sh@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libgui.a
libgui_a_SOURCES = sdlmain.cpp render.cpp
libgui_a_SOURCES = sdlmain.cpp render.cpp render_support.h
subdir = src/gui
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
@ -110,6 +110,11 @@ CXXLD = $(CXX)
CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
-o $@
CXXFLAGS = @CXXFLAGS@
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
DIST_SOURCES = $(libgui_a_SOURCES)
DIST_COMMON = Makefile.am Makefile.in
SOURCES = $(libgui_a_SOURCES)

View File

@ -26,9 +26,10 @@
#include "keyboard.h"
#include "cross.h"
#define MAX_RES 2048
typedef void (* RENDER_Part_Handler)(Bit8u * src,Bitu x,Bitu y,Bitu dx,Bitu dy);
struct PalData {
struct {
@ -39,6 +40,10 @@ struct PalData {
} rgb[256];
Bitu first;
Bitu last;
union {
Bit32u bpp32[256];
Bit16u bpp16[256];
} lookup;
};
@ -48,18 +53,40 @@ static struct {
Bitu height;
Bitu bpp;
Bitu pitch;
Bitu flags;
float ratio;
RENDER_Part_Handler part_handler;
} src;
struct {
Bitu width;
Bitu height;
Bitu pitch;
Bitu next_line;
Bitu next_pixel;
Bitu bpp; /* The type of BPP the operation requires for input */
RENDER_Operation want_type;
RENDER_Operation type;
void * dest;
void * buffer;
void * pixels;
} op;
struct {
Bitu count;
Bitu max;
} frameskip;
Bitu flags;
RENDER_Handler * handler;
Bitu stretch_x[MAX_RES];
Bitu stretch_y[MAX_RES];
PalData pal;
bool remake;
bool enlarge;
bool keep_small;
bool screenshot;
bool active;
} render;
/* Forward declerations */
static void RENDER_ResetPal(void);
/* Include the different rendering routines */
#include "render_support.h"
static const char * snapshots_dir;
/* Take a screenshot of the data that should be rendered */
@ -150,7 +177,6 @@ static void TakeScreenShot(Bit8u * bitmap) {
/*clean up dynamically allocated RAM.*/
free(row_pointers);
}
@ -158,56 +184,38 @@ static void TakeScreenShot(Bit8u * bitmap) {
/* This could go kinda bad with multiple threads */
static void Check_Palette(void) {
if (render.pal.first>render.pal.last) return;
GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]);
switch (render.op.bpp) {
case 8:
GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]);
break;
case 16:
for (;render.pal.first<=render.pal.last;render.pal.first++) {
render.pal.lookup.bpp16[render.pal.first]=GFX_GetRGB(
render.pal.rgb[render.pal.first].red,
render.pal.rgb[render.pal.first].green,
render.pal.rgb[render.pal.first].blue);
}
break;
case 32:
for (;render.pal.first<=render.pal.last;render.pal.first++) {
render.pal.lookup.bpp32[render.pal.first]=
GFX_GetRGB(
render.pal.rgb[render.pal.first].red,
render.pal.rgb[render.pal.first].green,
render.pal.rgb[render.pal.first].blue);
}
break;
};
/* Setup pal index to startup values */
render.pal.first=256;
render.pal.last=0;
}
static void MakeTables(void) {
//The stretching tables
Bitu i;Bit32u c,a;
c=0;a=(render.src.width<<16)/gfx_info.width;
for (i=0;i<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 RENDER_ResetPal(void) {
render.pal.first=0;
render.pal.last=255;
}
static void Draw_8_Normal(Bit8u * src_data,Bit8u * dst_data) {
for (Bitu y=0;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) {
render.pal.rgb[entry].red=red;
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;
}
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) {
/* Calculate the new size the window should be */
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);
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) {
if (!width) return;
if (!height) return;
GFX_Stop();
void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,Bitu pitch,float ratio,Bitu flags) {
if ((!width) || (!height) || (!pitch)) {
render.active=false;return;
}
render.src.width=width;
render.src.height=height;
render.src.bpp=bpp;
render.src.ratio=ratio;
render.src.pitch=pitch;
render.handler=handler;
render.src.ratio=ratio;
render.src.flags=flags;
switch (bpp) {
case 8:
GFX_Resize(width,height,bpp,&RENDER_Resize);
GFX_SetDrawHandler(RENDER_Draw);
break;
GFX_ModeCallBack callback;
switch (render.op.want_type) {
case OP_None:
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:
E_Exit("RENDER:Illegal bpp %d",bpp);
};
/* Setup the internal render structures to correctly render this screen */
MakeTables();
GFX_Start();
goto normalop;
}
GFX_SetSize(width,height,bpp,flags,callback);
}
static void EnableScreenShot(void) {
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) {
Section_prop * section=static_cast<Section_prop *>(sec);
snapshots_dir=section->Get_string("snapshots");
render.pal.first=256;
render.pal.last=0;
render.enlarge=false;
render.keep_small=section->Get_bool("keepsmall");
render.frameskip.max=section->Get_int("frameskip");
render.frameskip.count=0;
KEYBOARD_AddEvent(KBD_f5,CTRL_PRESSED,EnableScreenShot);
KEYBOARD_AddEvent(KBD_f7,CTRL_PRESSED,DecreaseFrameSkip);
KEYBOARD_AddEvent(KBD_f8,CTRL_PRESSED,IncreaseFrameSkip);
}

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

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 \
memory.cpp mixer.cpp pcspeaker.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \
vga.cpp vga.h vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_fonts.cpp vga_gfx.cpp \
vga_memory.cpp vga_misc.cpp vga_seq.cpp font-switch.h ega-switch.h
vga_memory.cpp vga_misc.cpp vga_seq.cpp font-switch.h ega-switch.h cmos.cpp disney.cpp \
gus.cpp

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

View File

@ -22,7 +22,7 @@
#include "dosbox.h"
#include "inout.h"
#include "mixer.h"
#include "timer.h"
#include "pic.h"
#include "hardware.h"
#include "setup.h"
/*
@ -32,27 +32,45 @@
namespace MAME {
/* Defines */
# define logerror(x)
/* Disable recurring warnings */
#pragma warning ( disable : 4018 )
#pragma warning ( disable : 4244 )
/* Bring in Tatsuyuki Satoh's OPL emulation */
#define HAS_YM3812 1
#include "fmopl.c"
/* Disable recurring warnings */
# pragma warning ( disable : 4018 )
# pragma warning ( disable : 4244 )
/* Work around ANSI compliance problem (see driver.h) */
struct __MALLOCPTR {
void* m_ptr;
__MALLOCPTR(void) : m_ptr(NULL) { }
__MALLOCPTR(void* src) : m_ptr(src) { }
void* operator=(void* rhs) { return (m_ptr = rhs); }
operator int*() const { return (int*)m_ptr; }
operator int**() const { return (int**)m_ptr; }
operator char*() const { return (char*)m_ptr; }
};
/* Bring in the MAME OPL emulation */
# define HAS_YM3812 1
# include "fmopl.c"
}
struct OPLTimer_t {
bool isEnabled;
bool isMasked;
bool isOverflowed;
Bit32u count;
Bit32u base;
Bit64u count;
Bit64u base;
};
static OPLTimer_t timer1,timer2;
static MAME::FM_OPL * myopl;
static Bit8u regsel;
#define OPL_INTERNAL_FREQ 3600000 // The OPL operates at 3.6MHz
#define OPL_NUM_CHIPS 1 // Number of OPL chips
#define OPL_CHIP0 0
static MIXER_Channel * adlib_chan;
static void ADLIB_CallBack(Bit8u *stream, Bit32u len) {
@ -60,25 +78,25 @@ static void ADLIB_CallBack(Bit8u *stream, Bit32u len) {
/* Calculate teh machine ms we are at now */
/* update 1 ms of data */
MAME::YM3812UpdateOne(myopl,(MAME::INT16 *)stream,len);
MAME::YM3812UpdateOne(0,(MAME::INT16 *)stream,len);
}
static Bit8u read_p388(Bit32u port) {
Bit8u ret=0;
Bit32u new_ticks=GetTicks();
Bit64u micro=PIC_MicroCount();
if (timer1.isEnabled) {
if ((new_ticks-timer1.base)>timer1.count) {
if ((micro-timer1.base)>timer1.count) {
timer1.isOverflowed=true;
timer1.base=new_ticks;
timer1.base=micro;
}
if (timer1.isOverflowed || !timer1.isMasked) {
ret|=0xc0;
}
}
if (timer2.isEnabled) {
if ((new_ticks-timer2.base)>timer2.count) {
if ((micro-timer2.base)>timer2.count) {
timer2.isOverflowed=true;
timer2.base=new_ticks;
timer2.base=micro;
}
if (timer2.isOverflowed || !timer2.isMasked) {
ret|=0xA0;
@ -94,10 +112,10 @@ static void write_p388(Bit32u port,Bit8u val) {
static void write_p389(Bit32u port,Bit8u val) {
switch (regsel) {
case 0x02: /* Timer 1 */
timer1.count=(val*80/1000);
timer1.count=val*80;
return;
case 0x03: /* Timer 2 */
timer2.count=(val*320/1000);
timer2.count=val*320;
return;
case 0x04: /* IRQ clear / mask and Timer enable */
if (val&0x80) {
@ -105,25 +123,24 @@ static void write_p389(Bit32u port,Bit8u val) {
timer2.isOverflowed=false;
return;
}
if (val&0x40) {
timer1.isMasked=true;
} else {
timer1.isMasked=false;
timer1.isEnabled=((val&1)>0);
timer1.base=GetTicks();
}
if (val&0x20) {
timer2.isMasked=true;
} else {
timer2.isMasked=false;
timer2.isEnabled=((val&2)>0);
timer2.base=GetTicks();
}
if (val&0x40) timer1.isMasked=true;
else timer1.isMasked=false;
if (val&1) {
timer1.isEnabled=true;
timer1.base=PIC_MicroCount();
} else timer1.isEnabled=false;
if (val&0x20) timer2.isMasked=true;
else timer2.isMasked=false;
if (val&2) {
timer2.isEnabled=true;
timer2.base=PIC_MicroCount();
} else timer2.isEnabled=false;
return;
default: /* Normal OPL call queue it */
MAME::OPLWriteReg(myopl,regsel,val);
/* Use a little hack to directly write to the register */
MAME::OPLWriteReg(MAME::OPL_YM3812[0],regsel,val);
}
}
static bool adlib_enabled;
@ -169,7 +186,10 @@ void ADLIB_Init(Section* sec) {
timer2.isOverflowed=false;
#define ADLIB_FREQ 22050
myopl=MAME::OPLCreate(0,OPL_INTERNAL_FREQ,ADLIB_FREQ);
if (MAME::YM3812Init(OPL_NUM_CHIPS,OPL_INTERNAL_FREQ,ADLIB_FREQ)) {
E_Exit("Can't create adlib OPL Emulator");
};
adlib_chan=MIXER_AddChannel(ADLIB_CallBack,ADLIB_FREQ,"ADLIB");
MIXER_SetMode(adlib_chan,MIXER_16MONO);

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

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,7 @@
#define BUILD_YM3526 (HAS_YM3526)
#define BUILD_Y8950 (HAS_Y8950)
/* --- system optimize --- */
/* select bit size of output : 8 or 16 */
/* select output bits size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16
/* compiler dependence */
@ -25,167 +24,88 @@ typedef signed int INT32; /* signed 32bit */
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_SAMPLE_BITS==8)
typedef unsigned char OPLSAMPLE;
typedef INT8 OPLSAMPLE;
#endif
#if BUILD_Y8950
#include "ymdeltat.h"
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
/* !!!!! here is private section , do not access there member direct !!!!! */
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
#define OPL_TYPE_IO 0x08 /* I/O port */
#if BUILD_YM3812
/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL slot ---------- */
typedef struct fm_opl_slot {
const UINT32 *AR; /* attack rate tab :&eg_table[AR<<2]*/
const UINT32 *DR; /* decay rate tab :&eg_table[DR<<2]*/
const UINT32 *RR; /* release rate tab:&eg_table[RR<<2]*/
UINT8 KSR; /* key scale rate */
UINT8 ARval; /* current AR */
UINT8 ksl; /* keyscale level */
UINT8 ksr; /* key scale rate :kcode>>KSR */
UINT8 mul; /* multiple :ML_TABLE[ML] */
int YM3812Init(int num, int clock, int rate);
void YM3812Shutdown(void);
void YM3812ResetChip(int which);
int YM3812Write(int which, int a, int v);
unsigned char YM3812Read(int which, int a);
int YM3812TimerOver(int which, int c);
void YM3812UpdateOne(int which, INT16 *buffer, int length);
/* Phase Generator */
UINT32 Cnt; /* frequency count */
UINT32 Incr; /* frequency step */
void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
void YM3812SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param);
void YM3812SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param);
/* Envelope Generator */
UINT8 eg_type; /* percussive/non-percussive mode */
UINT8 state; /* phase type */
UINT32 TL; /* total level :TL << 3 */
INT32 TLL; /* adjusted now TL */
INT32 volume; /* envelope counter */
UINT32 sl; /* sustain level :SL_TABLE[SL] */
UINT32 delta_ar; /* envelope step for Attack */
UINT32 delta_dr; /* envelope step for Decay */
UINT32 delta_rr; /* envelope step for Release */
#endif
UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
/* LFO */
UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
#if BUILD_YM3526
/* waveform select */
unsigned int *wavetable;
}OPL_SLOT;
/*
** Initialize YM3526 emulator(s).
**
** 'num' is the number of virtual YM3526's to allocate
** 'clock' is the chip clock in Hz
** 'rate' is sampling rate
*/
int YM3526Init(int num, int clock, int rate);
/* shutdown the YM3526 emulators*/
void YM3526Shutdown(void);
void YM3526ResetChip(int which);
int YM3526Write(int which, int a, int v);
unsigned char YM3526Read(int which, int a);
int YM3526TimerOver(int which, int c);
/*
** Generate samples for one of the YM3526's
**
** 'which' is the virtual YM3526 number
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
void YM3526UpdateOne(int which, INT16 *buffer, int length);
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
UINT8 FB; /* feedback shift value */
INT32 *connect1; /* slot1 output pointer */
INT32 op1_out[2]; /* slot1 output for feedback */
void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
void YM3526SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param);
void YM3526SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param);
/* phase generator state */
UINT32 block_fnum; /* block+fnum */
UINT32 fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 kcode; /* key code (for key scaling) */
#endif
UINT8 CON; /* connection (algorithm) type */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
/* FM channel slots */
OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels */
UINT8 rhythm; /* Rhythm mode */
UINT32 eg_tab[16+64+16]; /* EG rate table: 16 (dummy) + 64 rates + 16 RKS */
UINT32 fn_tab[1024]; /* fnumber -> increment counter */
/* LFO */
UINT8 lfo_am_depth;
UINT8 lfo_pm_depth_range;
UINT32 lfo_am_cnt;
UINT32 lfo_am_inc;
UINT32 lfo_pm_cnt;
UINT32 lfo_pm_inc;
UINT32 noise_rng; /* 23 bit noise shift register */
UINT32 noise_p; /* current noise 'phase' */
UINT32 noise_f; /* current noise period */
UINT8 wavesel; /* waveform select enable flag */
int T[2]; /* timer counters */
UINT8 st[2]; /* timer enable */
#if BUILD_Y8950
/* Delta-T ADPCM unit (Y8950) */
YM_DELTAT *deltat;
#include "ymdeltat.h"
/* Keyboard / I/O interface unit*/
UINT8 portDirection;
UINT8 portLatch;
OPL_PORTHANDLER_R porthandler_r;
OPL_PORTHANDLER_W porthandler_w;
int port_param;
OPL_PORTHANDLER_R keyboardhandler_r;
OPL_PORTHANDLER_W keyboardhandler_w;
int keyboard_param;
#endif
/* external event callback handlers */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
int IRQParam; /* IRQ parameter */
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
int UpdateParam; /* stream update parameter */
UINT8 type; /* chip type */
UINT8 address; /* address register */
UINT8 status; /* status flag */
UINT8 statusmask; /* status mask */
UINT8 mode; /* Reg.08 : CSM,notesel,etc. */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time)*/
} FM_OPL;
/* ---------- Generic interface section ---------- */
#define OPL_TYPE_YM3526 (0)
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
FM_OPL *OPLCreate(int type, int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
/* Y8950 port handlers */
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
void Y8950SetPortHandler(int which, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, int param);
void Y8950SetKeyboardHandler(int which, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, int param);
void Y8950SetDeltaTMemory(int which, void * deltat_rom, int deltat_rom_size );
void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);
int Y8950Init (int num, int clock, int rate);
void Y8950Shutdown (void);
void Y8950ResetChip (int which);
int Y8950Write (int which, int a, int v);
unsigned char Y8950Read (int which, int a);
int Y8950TimerOver (int which, int c);
void Y8950UpdateOne (int which, INT16 *buffer, int length);
void Y8950SetTimerHandler (int which, OPL_TIMERHANDLER TimerHandler, int channelOffset);
void Y8950SetIRQHandler (int which, OPL_IRQHANDLER IRQHandler, int param);
void Y8950SetUpdateHandler (int which, OPL_UPDATEHANDLER UpdateHandler, int param);
#endif
/* YM3626/YM3812 local section */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
#endif

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].xcount) stick[0].xcount--; else ret&=~1;
if (stick[0].ycount) stick[0].ycount--; else ret&=~2;
if (stick[0].button[0]) ret&=16;
if (stick[0].button[1]) ret&=32;
if (stick[0].button[0]) ret&=~16;
if (stick[0].button[1]) ret&=~32;
}
if (stick[1].enabled) {
if (stick[1].xcount) stick[1].xcount--; else ret&=~4;
if (stick[1].ycount) stick[1].ycount--; else ret&=~8;
if (stick[1].button[0]) ret&=64;
if (stick[1].button[1]) ret&=128;
if (stick[1].button[0]) ret&=~64;
if (stick[1].button[1]) ret&=~128;
}
return ret;
}

View File

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

View File

@ -20,6 +20,7 @@
#include "dosbox.h"
#include "mixer.h"
#include "timer.h"
#include "setup.h"
#ifndef PI
@ -30,20 +31,25 @@
#define SPKR_RATE 22050
#define SPKR_VOLUME 5000
#define FREQ_SHIFT 16
#define FREQ_MAX (2 << FREQ_SHIFT)
#define SPKR_SHIFT 16
#define SIN_ENT 1024
#define SIN_MAX (SIN_ENT << SPKR_SHIFT)
#define FREQ_MAX (2 << SPKR_SHIFT)
#define FREQ_HALF (FREQ_MAX >> 1)
struct Speaker {
Bit32u freq_add;
Bit32u freq_pos;
Bitu freq_add;
Bitu freq_pos;
Bit16s volume;
MIXER_Channel * chan;
bool enabled;
bool realsound;
bool sinewave;
Bitu mode;
Bit16u buffer[SPKR_BUF];
Bit16s table[SIN_ENT];
Bitu buf_pos;
};
@ -52,6 +58,7 @@ static Speaker spkr;
void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) {
spkr.mode=mode;
switch (mode) {
case 0:
if (cntr>72) cntr=72;
@ -59,8 +66,14 @@ void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) {
if (spkr.buf_pos<SPKR_BUF) spkr.buffer[spkr.buf_pos++]=(cntr-36)*600;
break;
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;
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) {
if (spkr.realsound) {
/* Generate the "RealSound" */
Bitu buf_add=(spkr.buf_pos<<16)/len;
Bitu buf_pos=0;
spkr.buf_pos=0;spkr.realsound=0;
while (len-->0) {
*(Bit16s*)(stream)=spkr.buffer[buf_pos >> 16];
buf_pos+=buf_add;
stream+=2;
switch (spkr.mode) {
case 0:
/* Generate the "RealSound" */
{
Bitu buf_add=(spkr.buf_pos<<16)/len;
Bitu buf_pos=0;
spkr.buf_pos=0;spkr.realsound=0;
while (len-->0) {
*(Bit16s*)(stream)=spkr.buffer[buf_pos >> 16];
buf_pos+=buf_add;
stream+=2;
}
break;
}
} else {
/* Generate a square wave */
while (len-->0) {
case 3:
if (spkr.sinewave) while (len-->0) {
spkr.freq_pos+=spkr.freq_add;
spkr.freq_pos&=(SIN_MAX-1);
*(Bit16s*)(stream)=spkr.table[spkr.freq_pos>>SPKR_SHIFT];
stream+=2;
} else while (len-->0) {
spkr.freq_pos+=spkr.freq_add;
if (spkr.freq_pos>=FREQ_MAX) spkr.freq_pos-=FREQ_MAX;
if (spkr.freq_pos>=FREQ_HALF) {
@ -92,11 +113,26 @@ static void PCSPEAKER_CallBack(Bit8u * stream,Bit32u len) {
}
stream+=2;
}
break;
case 4:
while (len-->0) {
if (spkr.freq_pos) {
*(Bit16s*)(stream)=spkr.volume;
spkr.freq_pos--;
} else {
*(Bit16s*)(stream)=-spkr.volume;
}
stream+=2;
}
break;
}
}
void PCSPEAKER_Init(Section* sec) {
MSG_Add("SPEAKER_CONFIGFILE_HELP","pcspeaker related options.\n");
Section_prop * section=static_cast<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");
MIXER_Enable(spkr.chan,false);
MIXER_SetMode(spkr.chan,MIXER_16MONO);
@ -104,4 +140,8 @@ void PCSPEAKER_Init(Section* sec) {
spkr.enabled=false;
spkr.realsound=false;
spkr.buf_pos=0;
/* Generate the sine wave */
for (Bitu i=0;i<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 "pic.h"
#define PIC_QUEUESIZE 128
struct IRQ_Block {
bool masked;
bool active;
@ -31,9 +33,10 @@ struct IRQ_Block {
PIC_EOIHandler * handler;
};
Bitu PIC_Ticks=0;
Bitu PIC_IRQCheck;
Bitu PIC_IRQActive;
bool PIC_IRQAgain;
static IRQ_Block irqs[16];
static Bit8u pic0_icws=0;
@ -42,10 +45,29 @@ static Bit8u pic0_icw_state=0;
static Bit8u pic1_icw_state=0;
static bool pic0_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) {
switch (val) {
case 0x0A: /* select read interrupt request register */
@ -63,7 +85,14 @@ static void write_p20(Bit32u port,Bit8u val) {
pic0_icw_state=1;
break;
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) {
irqs[PIC_IRQActive].inservice=false;
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);
};
break;
case 1: /* icw2 */
case 1: /* icw2 */
LOG_DEBUG("PIC0:Base vector %X",val);
for (i=0;i<=7;i++) {
irqs[i].vector=(val&0xf8)+i;
};
default: /* icw2, 3, and 4*/
if(pic0_icw_state++ >= pic0_icws) pic0_icw_state=0;
}
}
static Bit8u read_p20(Bit32u port) {
@ -174,6 +203,13 @@ static void write_pa0(Bit32u port,Bit8u val) {
pic1_icw_state=1;
break;
case 0x20: /* end of interrupt command */
case 0x21: /* end of interrupt command */
case 0x22: /* end of interrupt command */
case 0x23: /* end of interrupt command */
case 0x24: /* end of interrupt command */
case 0x25: /* end of interrupt command */
case 0x26: /* end of interrupt command */
case 0x27: /* end of interrupt command */
/* clear highest current in service bit */
if (PIC_IRQActive>7 && PIC_IRQActive <16) {
irqs[PIC_IRQActive].inservice=false;
@ -218,7 +254,6 @@ static void write_pa1(Bit32u port,Bit8u val) {
case 0: /* mask register */
for (i=0;i<=7;i++) {
irqs[i+8].masked=(val&1 <<i)>0;
if (!irqs[8].masked) LOG_DEBUG("Someone unmasked RTC irq");
};
break;
case 1: /* icw2 */
@ -292,7 +327,7 @@ void PIC_DeActivateIRQ(Bit32u irq) {
}
void PIC_runIRQs(void) {
Bit32u i;
Bitu i;
if (!flags.intf) return;
if (PIC_IRQActive!=PIC_NOIRQ) return;
if (!PIC_IRQCheck) return;
@ -304,19 +339,166 @@ void PIC_runIRQs(void) {
PIC_IRQCheck&=~(1 << i);
Interrupt(irqs[i].vector);
PIC_IRQActive=i;
PIC_IRQAgain=true;
return;
}
}
}
}
static void AddEntry(PICEntry * entry) {
PICEntry * find_entry=pic.next_entry;
if (!find_entry) {
entry->next=0;
pic.next_entry=entry;
return;
}
if (find_entry->index>entry->index) {
pic.next_entry=entry;
entry->next=find_entry;
return;
}
while (find_entry) {
if (find_entry->next) {
/* See if the next index comes later than this one */
if (find_entry->next->index>entry->index) {
entry->next=find_entry->next;
find_entry->next=entry;
return;
} else {
find_entry=find_entry->next;
}
} else {
entry->next=find_entry->next;
find_entry->next=entry;
return;
}
}
}
void PIC_AddEvent(PIC_EventHandler handler,Bitu delay) {
if (!pic.free_entry) {
LOG_WARN("PIC:No free queue entries");
return;
}
PICEntry * entry=pic.free_entry;
Bitu index=delay+PIC_Index();
entry->index=index;
entry->event=handler;
entry->type=EVENT;
pic.free_entry=pic.free_entry->next;
AddEntry(entry);
}
void PIC_AddIRQ(Bitu irq,Bitu delay) {
if (irq>15) E_Exit("PIC:Illegal IRQ");
if (!pic.free_entry) {
LOG_WARN("PIC:No free queue entries");
return;
}
PICEntry * entry=pic.free_entry;
Bitu index=delay+PIC_Index();
entry->index=index;
entry->irq=irq;
entry->type=IRQ;
pic.free_entry=pic.free_entry->next;
AddEntry(entry);
}
void PIC_RemoveEvents(PIC_EventHandler handler) {
PICEntry * entry=pic.next_entry;
PICEntry * prev_entry;
prev_entry=0;
while (entry) {
switch (entry->type) {
case EVENT:
if (entry->event==handler) {
if (prev_entry) {
prev_entry->next=entry->next;
entry->next=pic.free_entry;
pic.free_entry=entry;
entry=prev_entry->next;
continue;
} else {
pic.next_entry=entry->next;
entry->next=pic.free_entry;
pic.free_entry=entry;
entry=pic.next_entry;
continue;
}
}
break;
}
prev_entry=entry;
entry=entry->next;
}
}
Bitu PIC_RunQueue(void) {
Bitu ret;
/* Check to see if a new milisecond needs to be started */
if (CPU_Cycles>0) {
CPU_CycleLeft+=CPU_Cycles;
CPU_Cycles=0;
}
if (CPU_CycleLeft<=0) {
CPU_CycleLeft=CPU_CycleMax;
}
while (CPU_CycleLeft>0) {
/* Check the queue for an entry */
Bitu index=PIC_Index();
while (pic.next_entry && pic.next_entry->index<=index) {
PICEntry * entry=pic.next_entry;
pic.next_entry=entry->next;
switch (entry->type) {
case EVENT:
(entry->event)();
break;
case IRQ:
PIC_ActivateIRQ(entry->irq);
break;
}
/* Put the entry in the free list */
entry->next=pic.free_entry;
pic.free_entry=entry;
}
/* Check when to set the new cycle end */
if (pic.next_entry) {
Bits cycles=PIC_MakeCycles(pic.next_entry->index-index);
if (!cycles) cycles=1;
if (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) {
/* Setup pic0 and pic1 with initial values like DOS has normally */
PIC_IRQCheck=0;
PIC_IRQActive=PIC_NOIRQ;
Bit8u i;
PIC_Ticks=0;
Bitu i;
for (i=0;i<=7;i++) {
irqs[i].active=false;
irqs[i].masked=true;
@ -338,6 +520,14 @@ void PIC_Init(Section* sec) {
IO_RegisterReadHandler(0xa1,read_pa1,"Slave PIC Data");
IO_RegisterWriteHandler(0xa0,write_pa0,"Slave PIC Command");
IO_RegisterWriteHandler(0xa1,write_pa1,"Slave PIC Data");
/* Initialize the pic queue */
for (i=0;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 {
Bit8u mode; /* Current Counter Mode */
Bit32s cntr;
Bitu cntr;
Bits micro;
Bit64u start;
Bit8u latch_mode;
Bit8u read_state;
Bit16s read_latch;
Bit8u write_state;
Bit16u write_latch;
Bit32u last_ticks;
};
bool TimerAgain;
Bit32u LastTicks;
static PIT_Block pit[3];
static Bit32u pit_ticks; /* The amount of pit ticks one host tick is bit shifted */
static Bit32u timer_ticks; /* The amount of pit ticks bitshifted one timer cycle needs */
static Bit32u timer_buildup; /* The amount of pit ticks waiting */
#define 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) {
/* Fill the read_latch of the selected counter with current count */
PIT_Block * p=&pit[counter];
timer.req_count++;
float pos=timer.req_average*timer.req_count;
Bit16u ticks=pos*p->cntr;
Bit64s micro=PIC_MicroCount()-p->start;
switch (p->mode) {
case 0:
if (micro>p->micro) p->read_latch=p->write_latch;
else p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr));
break;
case 2:
micro%=p->micro;
p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr));
break;
case 3:
p->read_latch=(Bit16u)ticks;
micro%=p->micro;
micro*=2;
if (micro>p->micro) micro-=p->micro;
p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr));
break;
default:
LOG_ERROR("PIT:Illegal Mode %d for reading counter %d",p->mode,counter);
p->read_latch=(Bit16u)ticks;
micro%=p->micro;
p->read_latch=(Bit16u)(p->cntr-(((float)micro/(float)p->micro)*(float)p->cntr));
break;
}
}
static void write_latch(Bit32u port,Bit8u val) {
Bit32u counter=port-0x40;
Bitu counter=port-0x40;
PIT_Block * p=&pit[counter];
switch (p->write_state) {
case 0:
@ -104,21 +103,21 @@ static void write_latch(Bit32u port,Bit8u val) {
if (p->write_state != 0) {
if (p->write_latch == 0) p->cntr = 0x10000;
else p->cntr = p->write_latch;
p->last_ticks=LastTicks;
p->start=PIC_MicroCount();
p->micro=1000000/((float)PIT_TICK_RATE/(float)p->cntr);
switch (counter) {
case 0x00: /* Timer hooked to IRQ 0 */
PIC_DeActivateIRQ(0);
timer_ticks=p->cntr << PIT_SHIFT;
timer_buildup=0;
PIC_RemoveEvents(PIT0_Event);
PIC_AddEvent(PIT0_Event,p->micro);
LOG_DEBUG("PIT 0 Timer at %.3g Hz mode %d",PIT_TICK_RATE/(double)p->cntr,p->mode);
break;
case 0x02: /* Timer hooked to PC-Speaker */
// LOG_DEBUG("PIT 2 Timer at %.3g Hz mode %d",PIT_TICK_RATE/(double)p->cntr,p->mode);
PCSPEAKER_SetCounter(p->cntr,p->mode);
break;
default:
LOG_ERROR("PIT:Illegal timer selected for writing");
}
}
}
@ -194,14 +193,10 @@ struct Timer {
TIMER_TickHandler handler;
} tick;
struct{
Bitu count;
Bitu total;
Bits left;
Bits total;
TIMER_MicroHandler handler;
} micro;
struct {
Bitu end;
TIMER_DelayHandler handler;
} delay;
};
};
@ -220,85 +215,51 @@ TIMER_Block * TIMER_RegisterMicroHandler(TIMER_MicroHandler handler,Bitu micro)
Timer * new_timer=new(Timer);
new_timer->type=T_MICRO;
new_timer->micro.handler=handler;
new_timer->micro.total=micro;
new_timer->micro.count=0;
Timers.push_front(new_timer);
TIMER_SetNewMicro(new_timer,micro);
return (TIMER_Block *)new_timer;
}
TIMER_Block * TIMER_RegisterDelayHandler(TIMER_DelayHandler handler,Bitu delay) {
//Todo maybe check for a too long delay
Timer * new_timer=new(Timer);
new_timer->type=T_DELAY;
new_timer->delay.handler=handler;
new_timer->delay.end=LastTicks+delay;
Timers.push_front(new_timer);
return (TIMER_Block *)new_timer;
}
void TIMER_SetNewMicro(TIMER_Block * block,Bitu micro) {
Timer * timer=(Timer *)block;
if (timer->type!=T_MICRO) E_Exit("TIMER:Illegal handler type");
timer->micro.count=0;
timer->micro.total=micro;
Bitu index=PIC_Index();
while ((1000-index)>micro) {
PIC_AddEvent(timer->micro.handler,micro);
micro+=micro;
index+=micro;
}
timer->micro.left=timer->micro.total-(1000-index);
}
void TIMER_AddTicks(Bit32u ticks) {
/* Add pit ticks to the counter */
timer_buildup+=ticks*pit_ticks;
if (timer_buildup>MAX_PASSED) timer_buildup=MAX_PASSED;
void TIMER_AddTick(void) {
Bits index;
/* Check if there are timer handlers that need to be called */
Bitu add_micro=timer.ticks*1000;
std::list<Timer *>::iterator i;
for(i=Timers.begin(); i != Timers.end(); ++i) {
Timer * timers=(*i);
switch (timers->type) {
case T_TICK:
if (timer.ticks) timers->tick.handler(timer.ticks);
timers->tick.handler(1);
break;
case T_MICRO:
timers->micro.count+=add_micro;
if (timers->micro.count>=timers->micro.total) {
timers->micro.count-=timers->micro.total;
timers->micro.handler();
}
break;
case T_DELAY:
/* Also unregister the timer handler from the list */
if (LastTicks>timers->delay.end) {
std::list<Timer *>::iterator remove;
timers->delay.handler();
remove=i++;
Timers.erase(remove);
index=1000;
while (index>=timers->micro.left) {
PIC_AddEvent(timers->micro.handler,timers->micro.left);
index-=timers->micro.left;
timers->micro.left=timers->micro.total;
}
timers->micro.left-=index;
break;
default:
E_Exit("TIMER:Illegal handler type");
};
}
};
timer.ticks=ticks;
}
void TIMER_CheckPIT(void) {
if (timer_buildup>timer_ticks) {
timer_buildup-=timer_ticks;
/* Calculate amount of times the time index was requested */
timer.req[timer.req_index]=timer.req_count;
timer.req_index++;if (timer.req_index>=TIMER_AVERAGE) timer.req_index=0;
timer.req_count=0;
Bitu l;float total=0;
for (l=0;l<TIMER_AVERAGE;l++) total+=timer.req[l];
timer.req_average=1/(total/TIMER_AVERAGE);
PIC_ActivateIRQ(0);
return;
}
}
void TIMER_Init(Section* sect) {
Bitu i;
IO_RegisterWriteHandler(0x40,write_latch,"PIT Timer 0");
IO_RegisterWriteHandler(0x42,write_latch,"PIT Timer 2");
IO_RegisterWriteHandler(0x43,write_p43,"PIT Mode Control");
@ -312,11 +273,9 @@ void TIMER_Init(Section* sect) {
pit[0].read_latch=-1;
pit[0].write_latch=0;
pit[0].mode=3;
timer_ticks=pit[0].cntr << PIT_SHIFT;
timer_buildup=0;
timer.req_index=0;
for (i=0;i<TIMER_AVERAGE;i++) timer.req[i]=0;
pit_ticks=(PIT_TICK_RATE << PIT_SHIFT)/1000;
PIC_RegisterIRQ(0,&TIMER_CheckPIT,"PIT 0 Timer");
pit[0].micro=1000000/((float)PIT_TICK_RATE/(float)pit[0].cntr);
pit[2].micro=100;
PIC_AddEvent(PIT0_Event,pit[0].micro);
}

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);
void VGA_Render_GFX_256C(Bit8u * * data);
void VGA_Render_GFX_256U(Bit8u * * data);
void VGA_Render_TEXT_16(Bit8u * * data);
}
norender:
RENDER_EndUpdate();
}
VGA_StartRetrace();
}
void VGA_FindSettings(void) {
/* Sets up the correct memory handler from the vga.mode setting */
@ -67,8 +126,10 @@ void VGA_FindSettings(void) {
} else if (vga.config.cga_enabled) {
/* 4 color cga */
//TODO Detect hercules modes, probably set them up in bios too
if (vga.config.pixel_double) vga.mode=GFX_4;
else vga.mode=GFX_2;
if (vga.seq.clocking_mode & 0x8) {
vga.mode=GFX_4;
// MEM_SetupPageHandlers(PAGE_COUNT(0x0b8000),PAGE_COUNT(0x10000),&VGA_GFX_4_ReadHandler,&VGA_GFX_4_WriteHandler);
} else vga.mode=GFX_2;
//TODO Maybe also use a page handler for cga mode
} else {
/* 16 color ega */
@ -83,69 +144,96 @@ void VGA_FindSettings(void) {
}
static void VGA_DoResize(void) {
vga.draw.resizing=false;
Bitu width,height,pitch;
RENDER_Handler * renderer;
/* Calculate the FPS for this screen */
double fps;
Bitu vtotal=2 + (vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8) | ((vga.crtc.overflow & 0x20) << 4) );
Bitu htotal=5 + vga.crtc.horizontal_total;
Bitu vdispend = 1 + (vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2)<<7) | ((vga.crtc.overflow & 0x40) << 3) );
Bitu hdispend = 1 + (vga.crtc.horizontal_display_end);
//TODO Maybe check if blanking comes before display_end
height=vga.config.vdisplayend+1;
if (vga.config.vline_height>0) {
height/=(vga.config.vline_height+1);
}
if (vga.config.vline_double) height>>=1;
width=vga.config.hdisplayend;
double clock=(double)vga.config.clock;
/* Check for 8 for 9 character clock mode */
if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9;
/* Check for pixel doubling, master clock/2 */
if (vga.seq.clocking_mode & 0x8) clock/=2;
LOG_VGA("H total %d, V Total %d",htotal,vtotal);
LOG_VGA("H D End %d, V D End %d",hdispend,vdispend);
fps=clock/(vtotal*htotal);
vga.draw.resizing=false;
Bitu width,height,pitch,flags;
flags=0;
vga.draw.lines=height=vdispend;
width=hdispend;
vga.draw.double_height=vga.config.vline_double;
vga.draw.double_width=(vga.seq.clocking_mode & 0x8)>0;
vga.draw.font_height=vga.config.vline_height+1;
switch (vga.mode) {
case GFX_256C:
renderer=&VGA_Render_GFX_256C;
width<<=2;
pitch=vga.config.scan_len*8;
break;
case GFX_256U:
vga.draw.double_width=true; //Hack since 256 color modes use 2 clocks for a pixel
/* Don't know might do this different sometime, will have to do for now */
if (!vga.draw.double_height) {
if (vga.config.vline_height&1) {
vga.draw.double_height=true;
vga.draw.font_height/=2;
}
}
width<<=2;
pitch=vga.config.scan_len*8;
renderer=&VGA_Render_GFX_256U;
break;
case GFX_16:
width<<=3;
pitch=vga.config.scan_len*16;
renderer=&VGA_Render_GFX_16;
break;
case GFX_4:
width<<=3;
height<<=1;
pitch=width;
renderer=&VGA_Render_GFX_4;
break;
case GFX_2:
width<<=3;
height<<=1;
pitch=width;
renderer=&VGA_Render_GFX_2;
break;
case TEXT_16:
/* probably a 16-color text mode, got to detect mono mode somehow */
width<<=3; /* 8 bit wide text font */
height<<=4; /* 16 bit font height */
width<<=3; /* 8 bit wide text font */
if (width>640) width=640;
if (height>480) height=480;
pitch=width;
renderer=&VGA_Render_TEXT_16;
};
if (vga.draw.double_height) {
flags|=DoubleHeight;
height/=2;
}
if (vga.draw.double_width) {
flags|=DoubleWidth;
/* Double width is dividing main clock, the width should be correct already for this */
}
if (( width != vga.draw.width) || (height != vga.draw.height) || (pitch != vga.draw.pitch)) {
PIC_RemoveEvents(VGA_BlankTimer);
vga.draw.width=width;
vga.draw.height=height;
vga.draw.pitch=pitch;
vga.draw.width=width;
vga.draw.height=height;
RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),0,renderer);
LOG_VGA("Width %d, Height %d",width,height);
LOG_VGA("Flags %X, fps %f",flags,fps);
RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),flags);
vga.draw.blank=(Bitu)(1000000/fps);
PIC_AddEvent(VGA_BlankTimer,vga.draw.blank);
}
};
void VGA_StartResize(void) {
if (!vga.draw.resizing) {
vga.draw.resizing=true;
/* Start a resize after 50 ms */
TIMER_RegisterDelayHandler(VGA_DoResize,50);
PIC_AddEvent(VGA_DoResize,50000);
}
}
void VGA_Init(Section* sec) {
vga.draw.resizing=false;
VGA_SetupMemory();

View File

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

View File

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

View File

@ -40,9 +40,10 @@ void write_p3d5(Bit32u port,Bit8u val) {
/* 0-7 Horizontal Total Character Clocks-5 */
break;
case 0x01: /* Horizontal Display End Register */
crtc(horizontal_display_end)=val;
vga.config.hdisplayend=val+1;
VGA_StartResize();
if (val != crtc(horizontal_display_end)) {
crtc(horizontal_display_end)=val;
VGA_StartResize();
}
/* 0-7 Number of Character Clocks Displayed -1 */
break;
case 0x02: /* Start Horizontal Blanking Register */
@ -75,7 +76,10 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/
break;
case 0x06: /* Vertical Total Register */
crtc(vertical_total)=val;
if (val != crtc(vertical_total)) {
crtc(vertical_total)=val;
VGA_StartResize();
}
/* 0-7 Lower 8 bits of the Vertical Total. Bit 8 is found in 3d4h index 7
bit 0. Bit 9 is found in 3d4h index 7 bit 5.
Note: For the VGA this value is the number of scan lines in the display -2.
@ -83,8 +87,11 @@ void write_p3d5(Bit32u port,Bit8u val) {
break;
case 0x07: /* Overflow Register */
crtc(overflow)=val;
vga.config.vdisplayend=(vga.config.vdisplayend&0xFF)|(((val>>1) & 1)<<8)|(((val>>6) & 1)<<9);
VGA_StartResize();
vga.config.line_compare=(vga.config.line_compare & 0x2ff) | (val & 0x10) << 4;
if ((vga.crtc.overflow ^ val) & 0xef) {
crtc(overflow)=val;
VGA_StartResize();
} else crtc(overflow)=val;
/*
0 Bit 8 of Vertical Total (3d4h index 6)
1 Bit 8 of Vertical Display End (3d4h index 12h)
@ -110,10 +117,13 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/
break;
case 0x09: /* Maximum Scan Line Register */
crtc(maximum_scan_line)=val;
vga.config.vline_double=(val & 128)>1;
vga.config.vline_height=(val & 0xf);
VGA_StartResize();
vga.config.line_compare=(vga.config.line_compare & 0x1ff)|(val&0x40)<<3;
if ((vga.crtc.maximum_scan_line ^ val) & 0xbf) {
crtc(maximum_scan_line)=val;
VGA_StartResize();
} else crtc(maximum_scan_line)=val;
/*
0-4 Number of scan lines in a character row -1. In graphics modes this is
the number of times (-1) the line is displayed before passing on to
@ -152,16 +162,16 @@ void write_p3d5(Bit32u port,Bit8u val) {
case 0x0E: /*Cursor Location High Register */
crtc(cursor_location_high)=val;
if (vga.config.scan_len<2) break;
vga.draw.cursor_row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2);
vga.draw.cursor_col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2);
vga.draw.cursor.row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2);
vga.draw.cursor.col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2);
/* 0-7 Upper 8 bits of the address of the cursor */
break;
case 0x0F: /* Cursor Location Low Register */
//TODO update cursor on screen
crtc(cursor_location_low)=val;
if (vga.config.scan_len<2) break;
vga.draw.cursor_row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2);
vga.draw.cursor_col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2);
vga.draw.cursor.row=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))/(vga.config.scan_len*2);
vga.draw.cursor.col=(crtc(cursor_location_high)<<8|crtc(cursor_location_low))%(vga.config.scan_len*2);
/* 0-7 Lower 8 bits of the address of the cursor */
break;
case 0x10: /* Vertical Retrace Start Register */
@ -186,9 +196,10 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/
break;
case 0x12: /* Vertical Display End Register */
crtc(vertical_display_end)=val;
vga.config.vdisplayend=(vga.config.vdisplayend & 0x300)|val;
VGA_StartResize();
if (val!=crtc(vertical_display_end)) {
crtc(vertical_display_end)=val;
VGA_StartResize();
}
/*
0-7 Lower 8 bits of Vertical Display End. The display ends when the line
counter reaches this value. Bit 8 is found in 3d4h index 7 bit 1.
@ -196,9 +207,11 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/
break;
case 0x13: /* Offset register */
crtc(offset)=val;
vga.config.scan_len=val;
VGA_StartResize();
if (val!=crtc(offset)) {
crtc(offset)=val;
vga.config.scan_len=val;
VGA_StartResize();
}
/*
0-7 Number of bytes in a scanline / K. Where K is 2 for byte mode, 4 for
word mode and 8 for Double Word mode.
@ -228,9 +241,11 @@ void write_p3d5(Bit32u port,Bit8u val) {
*/
break;
case 0x17: /* Mode Control Register */
crtc(mode_control)=val;
vga.config.cga_enabled=!((val&1)>0);
VGA_FindSettings();
if (val!=crtc(mode_control)) {
crtc(mode_control)=val;
vga.config.cga_enabled=!((val&1)>0);
VGA_FindSettings();
}
/*
0 If clear use CGA compatible memory addressing system
by substituting character row scan counter bit 0 for address bit 13,
@ -249,6 +264,7 @@ void write_p3d5(Bit32u port,Bit8u val) {
break;
case 0x18: /* Line Compare Register */
crtc(line_compare)=val;
vga.config.line_compare=(vga.config.line_compare & 0x300) | val;
/*
0-7 Lower 8 bits of the Line Compare. When the Line counter reaches this
value, the display address wraps to 0. Provides Split Screen

View File

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

View File

@ -21,43 +21,11 @@
#include "video.h"
#include "vga.h"
//TODO Make the full draw like the vga really does from video memory.
/* This Should draw a complete 16 colour screen */
void VGA_Render_GFX_2(Bit8u * * data) {
*data=vga.buffer;
VGA_DrawGFX2_Full(vga.buffer,vga.draw.width);
vga.config.retrace=true;
}
void VGA_Render_GFX_4(Bit8u * * data) {
*data=vga.buffer;
VGA_DrawGFX4_Full(vga.buffer,vga.draw.width);
vga.config.retrace=true;
}
void VGA_Render_GFX_16(Bit8u * * data) {
*data=&vga.buffer[vga.config.display_start*8+vga.config.pel_panning];
vga.config.retrace=true;
}
void VGA_Render_GFX_256U(Bit8u * * data) {
*data=&vga.mem.linear[vga.config.display_start*4+vga.config.pel_panning];
vga.config.retrace=true;
}
void VGA_Render_GFX_256C(Bit8u * * data) {
*data=memory+0xa0000;
vga.config.retrace=true;
}
void VGA_Render_TEXT_16(Bit8u * * data) {
*data=vga.buffer;
if (!vga.draw.resizing) VGA_DrawTEXT(vga.buffer,vga.draw.width);
vga.config.retrace=true;
}
void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu pitch) {
void VGA_DrawGFX2_Fast(Bit8u * bitdata,Bitu pitch) {
Bit8u * reader=HostMake(0xB800,0);
Bit8u * flip=HostMake(0xB800,8*1024);
Bit8u * draw;
for (Bitu y=0;y<vga.draw.height;y++) {
Bit8u * tempread;
@ -68,7 +36,7 @@ void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu pitch) {
};
draw=bitdata;
//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++);
*(draw+0)=(val>>7)&1;
*(draw+1)=(val>>6)&1;
@ -81,14 +49,12 @@ void VGA_DrawGFX2_Full(Bit8u * bitdata,Bitu pitch) {
draw+=8;
}
bitdata+=pitch;
};
vga.config.retrace=true;
}
}
void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) {
Bit8u * reader=HostMake(0xB800,0);
void VGA_DrawGFX4_Fast(Bit8u * bitdata,Bitu pitch) {
Bit8u * reader=HostMake(0xB800,vga.config.display_start*2);
Bit8u * flip=HostMake(0xB800,8*1024);
Bit8u * draw;
for (Bitu y=0;y<vga.draw.height;y++) {
Bit8u * tempread;
@ -96,7 +62,8 @@ void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) {
if (y&1) {
tempread+=8*1024;
reader+=80;
};
if (reader>=flip) reader-=8*1024;
}
draw=bitdata;
for (Bit32u x=0;x<vga.draw.width>>2;x++) {
Bit8u val=*(tempread++);
@ -104,12 +71,10 @@ void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu pitch) {
draw+=4;
}
bitdata+=pitch;
};
vga.config.retrace=true;
}
}
/* Draw the screen using the lookup buffer */
//TODO include split screen or something
void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line) {
Bit8u * reader=&vga.buffer[vga.config.display_start*8+vga.config.pel_panning];
for (Bitu y=0;y<vga.draw.height;y++) {
@ -117,12 +82,9 @@ void VGA_DrawGFX16_Fast(Bit8u * bitdata,Bitu next_line) {
bitdata+=vga.draw.width+next_line;
reader+=vga.config.scan_len*16;
}
vga.config.retrace=true;
};
}
void VGA_DrawGFX256_Full(Bit8u * bitdata,Bitu next_line) {
void VGA_DrawGFX256U_Fast(Bit8u * bitdata,Bitu next_line) {
Bit16u yreader=vga.config.display_start*1;
/* TODO add pel panning */
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;
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) {
Bit8u * reader=HostMake(0xB800,0);
Bit8u * draw_start=bitdata;;
Bit8u * draw_start=bitdata;
/* Todo Blinking and high intensity colors */
for (Bitu cy=0;cy<(vga.draw.height/16);cy++) {
Bit8u * draw_char=draw_start;
@ -173,16 +122,16 @@ void VGA_DrawTEXT(Bit8u * bitdata,Bitu pitch) {
};
draw_start+=16*pitch;
};
vga.config.retrace=true;
/* Draw a cursor */
if (((Bitu)vga.draw.cursor_col*8)>=vga.draw.width) return;
if (((Bitu)vga.draw.cursor_row*16)>=vga.draw.height) return;
Bit8u * cursor_draw=bitdata+(vga.draw.cursor_row*16+15)*pitch+vga.draw.cursor_col*8;
if (vga.draw.cursor_count>8) {
for (Bit8u loop=0;loop<8;loop++) *cursor_draw++=15;
}
vga.draw.cursor_count++;
if (vga.draw.cursor_count>16) vga.draw.cursor_count=0;
if(!(vga.internal.cursor & 0x2000)) {
/* Draw a cursor */
if (((Bitu)vga.draw.cursor.col*8)>=vga.draw.width) return;
if (((Bitu)vga.draw.cursor.row*16)>=vga.draw.height) return;
Bit8u * cursor_draw=bitdata+(vga.draw.cursor.row*16+15)*pitch+vga.draw.cursor.col*8;
if (vga.draw.cursor.count>8) {
for (Bit8u loop=0;loop<8;loop++) *cursor_draw++=15;
}
vga.draw.cursor.count++;
if (vga.draw.cursor.count>16) vga.draw.cursor.count=0;
}
};

View File

@ -70,6 +70,7 @@ void write_p3cf(Bit32u port,Bit8u val) {
case 3: /* Data Rotate */
gfx(data_rotate)=val;
vga.config.data_rotate=val & 7;
if (vga.config.data_rotate) LOG_WARN("VGA:Data Rotate used %d",val &7);
vga.config.raster_op=(val>>3) & 3;
/*
0-2 Number of positions to rotate data right before it is written to

View File

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

View File

@ -18,9 +18,10 @@
#include "dosbox.h"
#include "inout.h"
#include "timer.h"
#include "pic.h"
#include "vga.h"
static Bit8u flip=0;
static Bit32u keep_vretrace;
static bool keeping=false;
@ -34,22 +35,12 @@ Bit8u read_p3d5(Bit32u port);
static Bit8u read_p3da(Bit32u port) {
vga.internal.attrindex=false;
if (vga.config.retrace) {
vga.config.retrace=false;
vga.config.real_start=vga.config.display_start;
keep_vretrace=LastTicks+1;
keeping=true;
flip=0;
return 9;
}
if (keeping) {
if (LastTicks>(keep_vretrace)) keeping=false;
return 9;
} else {
flip++;
if (flip>10) flip=0;
if (flip>5) return 1;
return 0;
}
flip++;
if (flip>10) flip=0;
if (flip>5) return 1;
return 0;
/*
0 Either Vertical or Horizontal Retrace active if set
3 Vertical Retrace in progress if set
@ -58,6 +49,7 @@ static Bit8u read_p3da(Bit32u port) {
static void write_p3d8(Bit32u port,Bit8u val) {
LOG_DEBUG("Write %2X to 3da",val);
/*
3 Vertical Sync Select. If set Vertical Sync to the monitor is the
logical OR of the vertical sync and the vertical display enable.
@ -66,7 +58,8 @@ static void write_p3d8(Bit32u port,Bit8u val) {
static void write_p3c2(Bit32u port,Bit8u val) {
p3c2data=val;
if (val & 1) {
if (val & 0x1) {
IO_RegisterWriteHandler(0x3d4,write_p3d4,"VGA:CRTC Index Select");
IO_RegisterReadHandler(0x3d4,read_p3d4,"VGA:CRTC Index Select");
IO_RegisterWriteHandler(0x3d5,write_p3d5,"VGA:CRTC Data Register");
@ -75,7 +68,6 @@ static void write_p3c2(Bit32u port,Bit8u val) {
IO_FreeReadHandler(0x3b4);
IO_FreeWriteHandler(0x3b5);
IO_FreeReadHandler(0x3b5);
} else {
IO_RegisterWriteHandler(0x3b4,write_p3d4,"VGA:CRTC Index Select");
IO_RegisterReadHandler(0x3b4,read_p3d4,"VGA:CRTC Index Select");
@ -86,6 +78,11 @@ static void write_p3c2(Bit32u port,Bit8u val) {
IO_FreeWriteHandler(0x3d5);
IO_FreeReadHandler(0x3d5);
}
if (val & 0x4) vga.config.clock=28322000;
else vga.config.clock=25175000;
VGA_StartResize();
/*
0 If set Color Emulation. Base Address=3Dxh else Mono Emulation. Base Address=3Bxh.
2-3 Clock Select. 0: 25MHz, 1: 28MHz
@ -105,6 +102,17 @@ static Bit8u read_p3cc(Bit32u port) {
}
static void EndRetrace(void) {
vga.config.retrace=false;
}
void VGA_StartRetrace(void) {
/* Setup a timer to destroy the vertical retrace bit in a few microseconds */
vga.config.real_start=vga.config.display_start;
vga.config.retrace=true;
PIC_AddEvent(EndRetrace,667);
}
void VGA_SetupMisc(void) {
IO_RegisterReadHandler(0x3da,read_p3da,"VGA Input Status 1");
IO_RegisterReadHandler(0x3ba,read_p3da,"VGA Input Status 1");

View File

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

View File

@ -22,9 +22,10 @@
#include "callback.h"
#include "inout.h"
#include "mem.h"
#include "timer.h"
#include "pic.h"
static Bitu call_int1a,call_int11,call_int8,call_int17,call_int12,call_int15,call_int1c;
static Bitu call_int1;
static Bitu INT1A_Handler(void) {
switch (reg_ah) {
@ -104,9 +105,19 @@ static Bitu INT8_Handler(void) {
/* decrease floppy motor timer */
Bit8u val = mem_readb(BIOS_DISK_MOTOR_TIMEOUT);
if (val>0) mem_writeb(BIOS_DISK_MOTOR_TIMEOUT,val-1);
/* and running drive */
mem_writeb(BIOS_DRIVE_RUNNING,mem_readb(BIOS_DRIVE_RUNNING) & 0xF0);
// Save ds,dx,ax
Bit16u oldds = SegValue(ds);
Bit16u olddx = reg_dx;
Bit16u oldax = reg_ax;
// run int 1c
CALLBACK_RunRealInt(0x1c);
IO_Write(0x20,0x20);
// restore old values
SegSet16(ds,oldds);
reg_dx = olddx;
reg_ax = oldax;
return CBRET_NONE;
};
@ -159,7 +170,8 @@ static Bitu INT15_Handler(void) {
mem_writed(BIOS_WAIT_FLAG_POINTER,RealMake(SegValue(es),reg_bx));
mem_writed(BIOS_WAIT_FLAG_COUNT,reg_cx<<16|reg_dx);
mem_writeb(BIOS_WAIT_FLAG_ACTIVE,1);
TIMER_RegisterDelayHandler(&WaitFlagEvent,reg_cx<<16|reg_dx);
PIC_RemoveEvents(&WaitFlagEvent);
PIC_AddEvent(&WaitFlagEvent,reg_cx<<16|reg_dx);
break;
case 0x84: /* BIOS - JOYSTICK SUPPORT (XT after 11/8/82,AT,XT286,PS) */
//Does anyone even use this?
@ -177,7 +189,11 @@ static Bitu INT15_Handler(void) {
CALLBACK_SCF(false);
break;
case 0x90: /* OS HOOK - DEVICE BUSY */
CALLBACK_SCF(true);
CALLBACK_SCF(false);
reg_ah=0;
break;
case 0x91: /* OS HOOK - DEVICE POST */
CALLBACK_SCF(false);
reg_ah=0;
break;
case 0xc2: /* BIOS PS2 Pointing Device Support */
@ -197,12 +213,16 @@ static Bitu INT15_Handler(void) {
CALLBACK_SCF(false);
}
return CBRET_NONE;
};
static void INT15_StartUp(void) {
/* TODO Start the time correctly */
};
}
static Bitu INT1_Single_Step(void) {
static bool warned=false;
if (!warned) {
warned=true;
LOG_WARN("INT 1:Single Step called");
}
return CBRET_NONE;
}
void BIOS_SetupKeyboard(void);
void BIOS_SetupDisks(void);
@ -244,13 +264,20 @@ void BIOS_Init(Section* sec) {
RealSetVec(0x17,CALLBACK_RealPointer(call_int17));
/* INT 1A TIME and some other functions */
call_int1a=CALLBACK_Allocate();
CALLBACK_Setup(call_int1a,&INT1A_Handler,CB_IRET);
CALLBACK_Setup(call_int1a,&INT1A_Handler,CB_IRET_STI);
RealSetVec(0x1A,CALLBACK_RealPointer(call_int1a));
/* INT 1C System Timer tick called from INT 8 */
call_int1c=CALLBACK_Allocate();
call_int1c=CALLBACK_Allocate();
CALLBACK_Setup(call_int1c,&INT1C_Handler,CB_IRET);
RealSetVec(0x1C,CALLBACK_RealPointer(call_int1c));
/* Some defeault CPU error interrupt handlers */
call_int1=CALLBACK_Allocate();
CALLBACK_Setup(call_int1,&INT1_Single_Step,CB_IRET);
RealSetVec(0x1,CALLBACK_RealPointer(call_int1));
/* Test for some hardware */
if (IO_Read(0x378)!=0xff) real_writed(0x40,0x08,0x378);
}

View File

@ -21,7 +21,7 @@
#include "bios.h"
#include "regs.h"
#include "mem.h"
#include "dos_inc.h" /* for Drives[] */
static Bitu call_int13;
static BIOS_Disk * Floppys[2];
@ -31,11 +31,28 @@ static Bit8u last_status;
static Bitu INT13_SmallHandler(void) {
switch (reg_ah) {
case 0x0:
reg_ah=0x00;
CALLBACK_SCF(false);
LOG_DEBUG("reset disk return succesfull");
break;
case 0x02: /* Read Disk Sectors */
LOG_DEBUG("INT13:02:Read Disk Sectors not supported failing");
reg_ah=0xff;
reg_ah=0x80;
CALLBACK_SCF(true);
break;
case 0x04:
if(Drives[reg_dl]!=NULL) {
reg_ah=0;
CALLBACK_SCF(false);
}
else{
reg_ah=0x80;
CALLBACK_SCF(true);
}
LOG_DEBUG("INT 13:04 Verify sector used on %d, with result %d",reg_dl,reg_ah);
break;
case 0x08: /* Get Drive Parameters */
LOG_DEBUG("INT13:08:Get Drive parameters not supported failing");
reg_ah=0xff;

View File

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

View File

@ -34,7 +34,7 @@
#define EMM_PAGEFRAME 0xE000
#define EMM_MAX_HANDLES 50 /* 255 Max */
#define EMM_PAGE_SIZE (16*1024)
#define EMM_MAX_PAGES (C_MEM_EMS_SIZE * 1024 / 16 )
#define EMM_MAX_PAGES (32 * 1024 / 16 )
#define EMM_MAX_PHYS 4 /* 4 16kb pages in pageframe */
#define EMM_VERSION 0x40
@ -83,7 +83,7 @@ struct EMM_Mapping {
};
struct EMM_Page {
void * memory;
HostPt * memory;
Bit16u handle;
Bit16u next;
};
@ -91,7 +91,7 @@ struct EMM_Page {
struct EMM_Handle {
Bit16u first_page;
Bit16u pages;
char name[9];
char name[8];
bool saved_page_map;
EMM_Mapping page_map[EMM_MAX_PHYS];
};
@ -100,8 +100,21 @@ static EMM_Handle emm_handles[EMM_MAX_HANDLES];
static EMM_Page emm_pages[EMM_MAX_PAGES];
static EMM_Mapping emm_mappings[EMM_MAX_PHYS];
static HostPt emm_pagebase[EMM_MAX_PHYS];
static Bitu emm_page_count;
Bitu call_int67;
struct MoveRegion {
Bit32u bytes;
Bit8u src_type;
Bit16u src_handle;
Bit16u src_offset;
Bit16u src_page_seg;
Bit8u dest_type;
Bit16u dest_handle;
Bit16u dest_offset;
Bit16u dest_page_seg;
};
#if EMM_USEHANDLER
Bit8u EMM_ReadHandler(PhysPt start) {
start-=EMM_PAGEFRAME * 16;
@ -118,12 +131,18 @@ void EMM_WriteHandler(PhysPt start,Bit8u val) {
static Bit16u EMM_GetFreePages(void) {
Bit16u count=0;
for (Bitu index=0;index<EMM_MAX_PAGES;index++) {
for (Bitu index=0;index<emm_page_count;index++) {
if (emm_pages[index].handle==NULL_HANDLE) 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) {
/* Check for 0 page allocation */
if (!pages) return EMM_ZERO_PAGES;
@ -140,14 +159,14 @@ static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) {
while (pages) {
if (emm_pages[page].handle==NULL_HANDLE) {
emm_pages[page].handle=handle;
emm_pages[page].memory=malloc(EMM_PAGE_SIZE);
emm_pages[page].memory=(HostPt *)malloc(EMM_PAGE_SIZE);
if (!emm_pages[page].memory) E_Exit("EMM:Cannont allocate memory");
if (last!=NULL_PAGE) emm_pages[last].next=page;
else emm_handles[handle].first_page=page;
last=page;
pages--;
} else {
if (++page>=EMM_MAX_PAGES) E_Exit("EMM:Ran out of pages");
if (++page>=emm_page_count) E_Exit("EMM:Ran out of pages");
}
}
return EMM_NO_ERROR;
@ -190,14 +209,14 @@ static Bit8u EMM_ReallocatePages(Bit16u handle,Bit16u & pages) {
while (pages) {
if (emm_pages[page].handle==NULL_HANDLE) {
emm_pages[page].handle=handle;
emm_pages[page].memory=malloc(EMM_PAGE_SIZE);
emm_pages[page].memory=(HostPt *)malloc(EMM_PAGE_SIZE);
if (!emm_pages[page].memory) E_Exit("EMM:Cannont allocate memory");
if (last!=NULL_PAGE) emm_pages[last].next=page;
else emm_handles[handle].first_page=page;
last=page;
pages--;
} else {
if (++page>=EMM_MAX_PAGES) E_Exit("EMM:Ran out of pages");
if (++page>=emm_page_count) E_Exit("EMM:Ran out of pages");
}
}
pages=emm_handles[handle].pages;
@ -264,7 +283,7 @@ static Bit8u EMM_ReleaseMemory(Bit16u handle) {
emm_handles[handle].first_page=NULL_PAGE;
emm_handles[handle].pages=NULL_HANDLE;
emm_handles[handle].saved_page_map=false;
memset(&emm_handles[handle].name,0,9);
memset(&emm_handles[handle].name,0,8);
return EMM_NO_ERROR;
}
@ -351,9 +370,143 @@ static Bit8u EMM_PartialPageMapping(void) {
LOG_ERROR("EMS:Call %2X Subfunction %2X not supported",reg_ah,reg_al);
return EMM_FUNC_NOSUP;
}
return 0;
return EMM_NO_ERROR;
}
static Bit8u HandleNameSearch(void) {
Bit16u handle=0;PhysPt data;
switch (reg_al) {
case 0x00: /* Get all handle names */
reg_al=0;data=SegPhys(es)+reg_di;
for (handle=0;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) {
Bitu i;
@ -366,7 +519,7 @@ static Bitu INT67_Handler(void) {
reg_ah=EMM_NO_ERROR;
break;
case 0x42: /* Get number of pages */
reg_dx=EMM_MAX_PAGES;
reg_dx=emm_page_count;
reg_bx=EMM_GetFreePages();
reg_ah=EMM_NO_ERROR;
break;
@ -395,8 +548,7 @@ static Bitu INT67_Handler(void) {
reg_ah=EMM_NO_ERROR;
break;
case 0x4c: /* Get Pages for one Handle */
/* Check for valid handle */
if (reg_bx>=EMM_MAX_HANDLES || emm_handles[reg_bx].pages==NULL_HANDLE) {reg_ah=EMM_INVALID_HANDLE;break;}
if (!ValidHandle(reg_bx)) {reg_ah=EMM_INVALID_HANDLE;break;}
reg_bx=emm_handles[reg_dx].pages;
reg_ah=EMM_NO_ERROR;
break;
@ -431,7 +583,6 @@ static Bitu INT67_Handler(void) {
case 0x4f: /* Save/Restore Partial Page Map */
reg_ah=EMM_PartialPageMapping();
break;
case 0x50: /* Map/Unmap multiple handle pages */
reg_ah = EMM_NO_ERROR;
switch (reg_al) {
@ -467,6 +618,13 @@ static Bitu INT67_Handler(void) {
reg_ah=EMM_NO_ERROR;
}
break;
case 0x54: /* Handle Functions */
reg_ah=HandleNameSearch();
break;
case 0x57: /* Memory region */
reg_ah=MemoryRegion();
if (reg_ah) LOG_WARN("ems 57 move failed");
break;
case 0x58: // Get mappable physical array address array
if (reg_al==0x00) {
PhysPt data = SegPhys(es)+reg_di;
@ -498,6 +656,12 @@ void EMS_Init(Section* sec) {
Section_prop * section=static_cast<Section_prop *>(sec);
Bitu size=section->Get_int("emssize");
if (!size) return;
if ((size*(1024/16))>EMM_MAX_PAGES) {
LOG_DEBUG("EMS Max size is %d",EMM_MAX_PAGES/(1024/16));
emm_page_count=EMM_MAX_PAGES;
} else {
emm_page_count=size*(1024/16);
}
call_int67=CALLBACK_Allocate();
CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET);
/* Register the ems device */
@ -515,7 +679,7 @@ void EMS_Init(Section* sec) {
RealSetVec(0x67,RealMake(seg,0));
/* Clear handle and page tables */
Bitu i;
for (i=0;i<EMM_MAX_PAGES;i++) {
for (i=0;i<emm_page_count;i++) {
emm_pages[i].memory=0;
emm_pages[i].handle=NULL_HANDLE;
emm_pages[i].next=NULL_PAGE;
@ -523,7 +687,7 @@ void EMS_Init(Section* sec) {
for (i=0;i<EMM_MAX_HANDLES;i++) {
emm_handles[i].first_page=NULL_PAGE;
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++) {
emm_mappings[i].page=NULL_PAGE;

View File

@ -25,12 +25,13 @@
#include "video.h"
#include "inout.h"
#include "int10.h"
#include "../hardware/vga.h" /* Maybe move this thing */
#define TEXT_SEG 0xb800
static Bitu call_10;
static bool warned_ff=false;
static bool warned_int10_0b=false;
static Bitu INT10_Handler(void) {
switch (reg_ah) {
@ -38,7 +39,8 @@ static Bitu INT10_Handler(void) {
INT10_SetVideoMode(reg_al);
break;
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;
case 0x02: /* Set Cursor Pos */
//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);
break;
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;
E_Exit("Unsupported int 10 call %02X" ,reg_ah);
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_GetDACBlock(Bit16u index,Bit16u count,PhysPt data);
/* Mouse pointer */
void INT10_SetGfxControllerToDefault(void);
/* Sup Groups */
void INT10_SetupRomMemory(void);

View File

@ -24,6 +24,17 @@
#include "inout.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) {
PhysPt src,dest;Bitu copy;
dest=base+(curmode->twidth*rnew)*curmode->cheight+cleft;
@ -38,7 +49,6 @@ static INLINE void PLANAR4_CopyRow(VGAMODES * curmode,Bit8u cleft,Bit8u cright,B
for (;copy>0;copy--) {
for (Bitu x=0;x<rowsize;x++) mem_writeb(dest+x,mem_readb(src+x));
dest+=nextline;src+=nextline;
}
/* Restore registers */
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);
}
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) {
/* Set Bitmask / Color / Full Set Reset */
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);
dest+=2;
}
}
void INT10_ScrollWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8s nlines,Bit8u attr,Bit8u page) {
/* Do some range checking */
BIOS_NCOLS;BIOS_NROWS;
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 CTEXT:
TEXT_CopyRow(curmode,cul,clr,start,start+nlines,base);break;
case CGA:
CGA_CopyRow(curmode,cul,clr,start,start+nlines,base);break;
case PLANAR4:
PLANAR4_CopyRow(curmode,cul,clr,start,start+nlines,base);break;
}
} while (start!=end);
/* Fill some lines */
@ -134,6 +156,8 @@ filling:
case MTEXT:
case CTEXT:
TEXT_FillRow(curmode,cul,clr,start,base,attr);break;
case CGA:
CGA_FillRow(curmode,cul,clr,start,base,attr);break;
case PLANAR4:
PLANAR4_FillRow(curmode,cul,clr,start,base,attr);break;
}
@ -260,9 +284,6 @@ INLINE static void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit8u chr,Bit8u at
}
}
void INT10_WriteChar(Bit8u chr,Bit8u attr,Bit8u page,Bit16u count,bool showattr) {
if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
Bit8u cur_row=CURSOR_POS_ROW(page);

View File

@ -20,6 +20,7 @@
#include "mem.h"
#include "inout.h"
#include "int10.h"
#include "mouse.h"
//TODO Maybe also add PCJR Video Modes could be nice :)
//TODO include some credits to bochs/plex86 bios i used for info/tables
@ -387,8 +388,7 @@ void INT10_SetVideoMode(Bit8u mode) {
real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,theight-1);
real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,cheight);
real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem << 7)));
real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0);
real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0x09);
real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
// FIXME We nearly have the good tables. to be reworked
@ -410,4 +410,18 @@ void INT10_SetVideoMode(Bit8u mode) {
INT10_SetActivePage(0);
/* Set some interrupt vectors */
RealSetVec(0x43,int10_romarea.font_8_first);
/* Tell mouse resolution change */
Mouse_SetResolution(vga_modes[line].swidth,vga_modes[line].sheight);
};
void INT10_SetGfxControllerToDefault()
// reset gfx controller to default values
// needed for drawing mouse pointer
{
Bit8u line=FindVideoMode(real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)&127);
// Set Grafx Ctl
for(Bit8u i=0;i<=GRDC_MAX_REG;i++) {
IO_Write(VGAREG_GRDC_ADDRESS,(Bit8u)i);
IO_Write(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]);
}
};

View File

@ -29,6 +29,9 @@
static Bitu call_int33,call_int74;
// forward
void WriteMouseIntVector(void);
struct button_event {
Bit16u type;
Bit16u buttons;
@ -40,6 +43,30 @@ struct button_event {
#define POS_X (Bit16s)(mouse.x)
#define POS_Y (Bit16s)(mouse.y)
#define CURSORX 16
#define CURSORY 16
#define HIGHESTBIT (1<<(CURSORX-1))
static Bit16u defaultTextAndMask = 0x77FF;
static Bit16u defaultTextXorMask = 0x7700;
static Bit16u defaultScreenMask[CURSORY] = {
0x3FFF, 0x1FFF, 0x0FFF, 0x07FF,
0x03FF, 0x01FF, 0x00FF, 0x007F,
0x003F, 0x001F, 0x01FF, 0x00FF,
0x30FF, 0xF87F, 0xF87F, 0xFCFF
};
static Bit16u defaultCursorMask[CURSORY] = {
0x0000, 0x4000, 0x6000, 0x7000,
0x7800, 0x7C00, 0x7E00, 0x7F00,
0x7F80, 0x7C00, 0x6C00, 0x4600,
0x0600, 0x0300, 0x0300, 0x0000
};
static Bit16u userdefScreenMask[CURSORY];
static Bit16u userdefCursorMask[CURSORY];
static struct {
Bit16u buttons;
Bit16u times_pressed[MOUSE_BUTTONS];
@ -57,6 +84,22 @@ static struct {
Bit32u events;
Bit16u sub_seg,sub_ofs;
Bit16u sub_mask;
bool background;
Bit16s backposx, backposy;
Bit8u backData[CURSORX*CURSORY];
Bit16u* screenMask;
Bit16u* cursorMask;
Bit16s clipx,clipy;
Bit16s hotx,hoty;
Bit16u textAndMask, textXorMask;
Bit16u resy;
float mickeysPerPixel_x;
float mickeysPerPixel_y;
float pixelPerMickey_x;
float pixelPerMickey_y;
} mouse;
#define X_MICKEY 8
@ -79,17 +122,211 @@ INLINE void Mouse_AddEvent(Bit16u type) {
PIC_ActivateIRQ(12);
}
static void DrawCursor() {
// ***************************************************************************
// Mouse cursor - text mode
// ***************************************************************************
void RestoreCursorBackgroundText()
{
if (mouse.shown<0) return;
if (mouse.background) {
// Save old Cursorposition
Bit8u oldx = CURSOR_POS_ROW(0);
Bit8u oldy = CURSOR_POS_COL(0);
// Restore background
INT10_SetCursorPos ((Bit8u)mouse.backposy,(Bit8u)mouse.backposx,0);
INT10_WriteChar (mouse.backData[0],mouse.backData[1],0,1,true);
// Restore old cursor position
INT10_SetCursorPos (oldx,oldy,0);
mouse.background = false;
}
};
void DrawCursorText()
{
// Restore Background
RestoreCursorBackgroundText();
// Save old Cursorposition
Bit8u oldx = CURSOR_POS_ROW(0);
Bit8u oldy = CURSOR_POS_COL(0);
// Save Background
Bit16u result;
INT10_SetCursorPos (POS_Y>>3,POS_X>>3,0);
INT10_ReadCharAttr (&result,0);
mouse.backData[0] = result & 0xFF;
mouse.backData[1] = result>>8;
mouse.backposx = POS_X>>3;
mouse.backposy = POS_Y>>3;
mouse.background = true;
// Write Cursor
result = (result & mouse.textAndMask) ^ mouse.textXorMask;
INT10_WriteChar (result&0xFF,result>>8,0,1,true);
// Restore old cursor position
INT10_SetCursorPos (oldx,oldy,0);
};
// ***************************************************************************
// Mouse cursor - graphic mode
// ***************************************************************************
static Bit8u gfxReg[9];
void SaveVgaRegisters()
{
for (int i=0; i<9; i++) {
IO_Write (0x3CE,i);
gfxReg[i] = IO_Read(0x3CF);
};
// Set default
INT10_SetGfxControllerToDefault();
};
void RestoreVgaRegisters()
{
for (int i=0; i<9; i++) {
IO_Write(0x3CE,i);
IO_Write(0x3CF,gfxReg[i]);
};
};
void ClipCursorArea(Bit16s& x1, Bit16s& x2, Bit16s& y1, Bit16s& y2, Bit16u& addx1, Bit16u& addx2, Bit16u& addy)
{
addx1 = addx2 = addy = 0;
// Clip up
if (y1<0) {
addy += (-y1);
y1 = 0;
}
// Clip down
if (y2>mouse.clipy) {
y2 = mouse.clipy;
};
// Clip left
if (x1<0) {
addx1 += (-x1);
x1 = 0;
};
// Clip right
if (x2>mouse.clipx) {
addx2 = x2 - mouse.clipx;
x2 = mouse.clipx;
};
};
void RestoreCursorBackground()
{
if (mouse.shown<0) return;
SaveVgaRegisters();
if (mouse.background) {
// Restore background
Bit16s x,y;
Bit16u addx1,addx2,addy;
Bit16u dataPos = 0;
Bit16s x1 = mouse.backposx;
Bit16s y1 = mouse.backposy;
Bit16s x2 = x1 + CURSORX - 1;
Bit16s y2 = y1 + CURSORY - 1;
ClipCursorArea(x1, x2, y1, y2, addx1, addx2, addy);
dataPos = addy * CURSORX;
for (y=y1; y<=y2; y++) {
dataPos += addx1;
for (x=x1; x<=x2; x++) {
INT10_PutPixel(x,y,0,mouse.backData[dataPos++]);
};
dataPos += addx2;
};
mouse.background = false;
};
RestoreVgaRegisters();
};
void DrawCursor() {
if (mouse.shown<0) return;
// Get Clipping ranges
VGAMODES * curmode=GetCurrentMode();
if (!curmode) return;
// In Textmode ?
if (curmode->type==TEXT) {
DrawCursorText();
return;
}
mouse.clipx = curmode->swidth-1;
mouse.clipy = curmode->sheight-1;
RestoreCursorBackground();
SaveVgaRegisters();
// Save Background
Bit16s x,y;
Bit16u addx1,addx2,addy;
Bit16u dataPos = 0;
Bit16s x1 = POS_X - mouse.hotx;
Bit16s y1 = POS_Y - mouse.hoty;
Bit16s x2 = x1 + CURSORX - 1;
Bit16s y2 = y1 + CURSORY - 1;
ClipCursorArea(x1,x2,y1,y2, addx1, addx2, addy);
dataPos = addy * CURSORX;
for (y=y1; y<=y2; y++) {
dataPos += addx1;
for (x=x1; x<=x2; x++) {
INT10_GetPixel(x,y,0,&mouse.backData[dataPos++]);
};
dataPos += addx2;
};
mouse.background= true;
mouse.backposx = POS_X - mouse.hotx;
mouse.backposy = POS_Y - mouse.hoty;
// Draw Mousecursor
dataPos = addy * CURSORX;
for (y=y1; y<=y2; y++) {
Bit16u scMask = mouse.screenMask[addy+y-y1];
Bit16u cuMask = mouse.cursorMask[addy+y-y1];
if (addx1>0) { scMask<<=addx1; cuMask<<=addx1; dataPos += addx1; };
for (x=x1; x<=x2; x++) {
Bit8u pixel = 0;
// ScreenMask
if (scMask & HIGHESTBIT) pixel = mouse.backData[dataPos];
scMask<<=1;
// CursorMask
if (cuMask & HIGHESTBIT) pixel = pixel ^ 0x0F;
cuMask<<=1;
// Set Pixel
INT10_PutPixel(x,y,0,pixel);
dataPos++;
};
dataPos += addx2;
};
RestoreVgaRegisters();
}
void Mouse_CursorMoved(float x,float y) {
mouse.mickey_x+=x;
mouse.mickey_y+=y;
mouse.x+=x;
float dx = x * mouse.pixelPerMickey_x;
float dy = y * mouse.pixelPerMickey_y;
mouse.mickey_x += dx;
mouse.mickey_y += dy;
mouse.x += dx;
if (mouse.x>mouse.max_x) mouse.x=mouse.max_x;;
if (mouse.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.min_y) mouse.y=mouse.min_y;
Mouse_AddEvent(MOUSE_MOVED);
@ -142,14 +379,32 @@ void Mouse_ButtonReleased(Bit8u button) {
mouse.last_released_y[button]=POS_Y;
}
static void mouse_reset(void) {
real_writed(0,(0x33<<2),CALLBACK_RealPointer(call_int33));
static void SetMickeyPixelRate(Bit16s px, Bit16s py)
{
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));
mouse.shown=-1;
mouse.min_x=0;
mouse.max_x=639;
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.y=100;
mouse.events=0;
@ -158,10 +413,21 @@ static void mouse_reset(void) {
mouse.sub_mask=0;
mouse.sub_seg=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) {
// LOG_DEBUG("MOUSE: %04X",reg_ax);
switch (reg_ax) {
case 0x00: /* Reset Driver and Read Status */
reg_ax=0xffff;
@ -172,9 +438,15 @@ static Bitu INT33_Handler(void) {
case 0x01: /* Show Mouse */
mouse.shown++;
if (mouse.shown>0) mouse.shown=0;
DrawCursor();
break;
case 0x02: /* Hide Mouse */
mouse.shown--;
{
VGAMODES * curmode=GetCurrentMode();
if (curmode && curmode->type==GRAPH) RestoreCursorBackground();
else RestoreCursorBackgroundText();
mouse.shown--;
}
break;
case 0x03: /* Return position and Button Status */
reg_bx=mouse.buttons;
@ -184,6 +456,7 @@ static Bitu INT33_Handler(void) {
case 0x04: /* Position Mouse */
mouse.x=(float)reg_cx;
mouse.y=(float)reg_dx;
DrawCursor();
break;
case 0x05: /* Return Button Press Data */
{
@ -212,18 +485,38 @@ static Bitu INT33_Handler(void) {
break;
}
case 0x07: /* Define horizontal cursor range */
mouse.min_x=reg_cx;
mouse.max_x=reg_dx;
if (reg_cx<reg_dx) {
mouse.min_x=reg_cx;
mouse.max_x=reg_dx;
} else {
mouse.min_x=reg_dx;
mouse.max_x=reg_cx;
};
break;
case 0x08: /* Define vertical cursor range */
mouse.min_y=reg_cx;
mouse.max_y=reg_dx;
if (reg_cx<reg_dx) {
mouse.min_y=reg_cx;
mouse.max_y=reg_dx;
} else {
mouse.min_y=reg_dx;
mouse.max_y=reg_cx;
};
break;
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;
case 0x0a: /* Define Text Cursor */
/* Don't see much need for supporting this */
mouse.textAndMask = reg_cx;
mouse.textXorMask = reg_dx;
break;
case 0x0c: /* Define interrupt subroutine parameters */
mouse.sub_mask=reg_cx;
@ -231,11 +524,11 @@ static Bitu INT33_Handler(void) {
mouse.sub_ofs=reg_dx;
break;
case 0x0f: /* Define mickey/pixel rate */
//TODO Maybe dunno for sure might be possible */
SetMickeyPixelRate(reg_cx,reg_dx);
break;
case 0x0B: /* Read Motion Data */
reg_cx=(Bit16s)(mouse.mickey_x*X_MICKEY);
reg_dx=(Bit16s)(mouse.mickey_y*Y_MICKEY);
reg_cx=(Bit16s)(mouse.mickey_x*mouse.mickeysPerPixel_x);
reg_dx=(Bit16s)(mouse.mickey_y*mouse.mickeysPerPixel_y);
mouse.mickey_x=0;
mouse.mickey_y=0;
break;
@ -254,6 +547,16 @@ static Bitu INT33_Handler(void) {
SegSet16(es,oldSeg);
}
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 */
/* Can't really set a rate this is host determined */
break;
@ -288,12 +591,13 @@ static Bitu INT74_Handler(void) {
reg_bx=mouse.event_queue[mouse.events].buttons;
reg_cx=POS_X;
reg_dx=POS_Y;
reg_si=(Bit16s)(mouse.mickey_x*X_MICKEY);
reg_di=(Bit16s)(mouse.mickey_y*Y_MICKEY);
if (mouse.event_queue[mouse.events].type==MOUSE_MOVED) {
reg_si=(Bit16s)(mouse.mickey_x*mouse.mickeysPerPixel_x);
reg_di=(Bit16s)(mouse.mickey_y*mouse.mickeysPerPixel_y);
// 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_y=0;
}
}*/
CALLBACK_RunRealFar(mouse.sub_seg,mouse.sub_ofs);
reg_eax=oldeax;reg_ebx=oldebx;reg_ecx=oldecx;reg_edx=oldedx;
reg_esi=oldesi;reg_edi=oldedi;reg_ebp=oldebp;reg_esp=oldesp;
@ -309,16 +613,41 @@ static Bitu INT74_Handler(void) {
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();
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();
CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRET);
real_writed(0,(0x74<<2),CALLBACK_RealPointer(call_int74));
memset(&mouse,0,sizeof(mouse));
mouse.resy = 199; // Init with startup value
mouse_reset();
}

View File

@ -118,7 +118,8 @@ Bitu XMS_Handler(void) {
case XMS_LOCAL_ENABLE_A20: /* 05 */
case XMS_LOCAL_DISABLE_A20: /* 06 */
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 */
/* Scan the tree for free memory and find largest free block */
{
@ -177,7 +178,7 @@ foundnew:
return CBRET_NONE;
}
/* 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;
}
/* Found no good blocks give some errors */
@ -311,7 +312,7 @@ foundnew:
}
reg_bh=xms_handles[reg_dx].locked;
/* 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;
break;
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) {
if (!fname) return;
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 */
if (!mfile) {
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) {
FILE* out=fopen(location,"w+b");
FILE* out=fopen(location,"w+t");
if(out==NULL) return;//maybe an error?
for(itmb tel=Lang.begin();tel!=Lang.end();tel++){
fprintf(out,":%s\n%s.\n",(*tel).name.c_str(),(*tel).val.c_str());

View File

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

View File

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

View File

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

View File

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

View File

@ -79,7 +79,7 @@ void DOS_Shell::ParseLine(char * line) {
char * fname1=0;
/* Check for a leading @ */
if (line[0]=='@') line[0]=' ';
if (line[0]=='@') line[0]=' ';
line=trim(line);
Bit32u num=0; /* Number of commands in this line */
@ -96,9 +96,10 @@ void DOS_Shell::ParseLine(char * line) {
void DOS_Shell::Run(void) {
char input_line[CMD_MAXLINE];
std::string line;
if (cmd->FindString("/C",line,true)) {
if (cmd->FindStringRemain("/C",line)) {
strcpy(input_line,line.c_str());
line.erase();
ParseLine(input_line);
return;
}
/* Start a normal shell and check for a first command init */
@ -179,13 +180,15 @@ static char * init_line="/INIT AUTOEXEC.BAT";
void SHELL_Init() {
/* Add messages */
MSG_Add("SHELL_ILLEGAL_PATH","Illegal Path\n");
MSG_Add("SHELL_CMD_HELP","supported commands are:\n");
MSG_Add("SHELL_CMD_ECHO_ON","ECHO is on\n");
MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off\n");
MSG_Add("SHELL_ILLEGAL_SWITCH","Illegal switch: %s\n");
MSG_Add("SHELL_CMD_CHDIR_ERROR","Unable to change to: %s\n");
MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %s\n");
MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %\n");
MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %s\n");
MSG_Add("SHELL_CMD_DEL_ERROR","Unable to delete: %s\n");
MSG_Add("SHELL_SYNTAXERROR","The syntax of the command is incorrect.\n");
MSG_Add("SHELL_CMD_SET_NOT_SET","Environment variable %s not defined\n");
MSG_Add("SHELL_CMD_SET_OUT_OF_SPACE","Not enough environment space left.\n");
@ -197,12 +200,22 @@ void SHELL_Init() {
MSG_Add("SHELL_CMD_FILE_NOT_FOUND","File %s not found.\n");
MSG_Add("SHELL_CMD_FILE_EXISTS","File %s already exists.\n");
MSG_Add("SHELL_CMD_DIR_INTRO","Directory of %s.\n");
MSG_Add("SHELL_CMD_DIR_PATH_ERROR","Illegal Path\n");
MSG_Add("SHELL_CMD_DIR_BYTES_USED","%5d File(s) %17s Bytes\n");
MSG_Add("SHELL_CMD_DIR_BYTES_FREE","%5d Dir(s) %17s Bytes free\n");
MSG_Add("SHELL_EXECUTE_DRIVE_NOT_FOUND","Drive %c does not exist!\n");
MSG_Add("SHELL_EXECUTE_ILLEGAL_COMMAND","Illegal command: %s.\n");
MSG_Add("SHELL_STARTUP","DOSBox Shell v" VERSION "\nFor Help and supported commands type: HELP\n\nHAVE FUN!\nThe DOSBox Team\n\n");
MSG_Add("SHELL_STARTUP","DOSBox Shell v" VERSION "\n"
"DOSBox doesn't not run protected mode games!\n"
"For supported shell commands type: HELP\n"
#if! defined (WIN32)
"DOSBox only works with upcase filenames as dos is case-insensitive.\n"
"You can use the UPCASE command for this, but please be careful.\n"
#endif
"For more information read the README file in DOSBox directory.\n"
"\nHAVE FUN!\nThe DOSBox Team\n\n"
);
MSG_Add("SHELL_CMD_CHDIR_HELP","Change Directory.\n");
MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n");
MSG_Add("SHELL_CMD_DIR_HELP","Directory View.\n");
@ -216,9 +229,15 @@ void SHELL_Init() {
MSG_Add("SHELL_CMD_GOTO_HELP","Jump to a labeled line in a batch script.\n");
MSG_Add("SHELL_CMD_TYPE_HELP","Display the contents of a text-file.\n");
MSG_Add("SHELL_CMD_REM_HELP","Add comments in a batch file.\n");
MSG_Add("SHELL_CMD_NO_WILD","This is a simple version of the command, no wildcards allowed!\n");
MSG_Add("SHELL_CMD_RENAME_HELP","Renames files.\n");
MSG_Add("SHELL_CMD_DELETE_HELP","Removes files.\n");
/* Regular startup */
call_shellstop=CALLBACK_Allocate();
/* Setup the startup CS:IP to kill the last running machine when exitted */
RealPt newcsip=CALLBACK_RealPointer(call_shellstop);
SegSet16(cs,RealSeg(newcsip));
reg_ip=RealOff(newcsip);
CALLBACK_Setup(call_shellstop,shellstop_handler,CB_IRET);
PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart);

View File

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

View File

@ -28,6 +28,8 @@ static SHELL_Cmd cmd_list[]={
"CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP",
// "COPY", 0, &DOS_Shell::CMD_COPY, "Copy Files.",
"DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP",
"DEL", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP",
"DELETE", 0, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP",
"ECHO", 0, &DOS_Shell::CMD_ECHO, "SHELL_CMD_ECHO_HELP",
"EXIT", 0, &DOS_Shell::CMD_EXIT, "SHELL_CMD_EXIT_HELP",
"HELP", 0, &DOS_Shell::CMD_HELP, "SHELL_CMD_HELP_HELP",
@ -38,7 +40,8 @@ static SHELL_Cmd cmd_list[]={
"GOTO", 0, &DOS_Shell::CMD_GOTO, "SHELL_CMD_GOTO_HELP",
"TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP",
"REM", 0, &DOS_Shell::CMD_REM, "SHELL_CMD_REM_HELP",
"RENAME", 0, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP",
"REN", 1, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP",
/*
"CHDIR", 0, &DOS_Shell::CMD_CHDIR, "Change Directory",
"MKDIR", 0, &DOS_Shell::CMD_MKDIR, "Make Directory",
@ -56,6 +59,7 @@ void DOS_Shell::DoCommand(char * line) {
if (*line==32) break;
if (*line=='/') break;
if ((*line=='.') && (*(line+1)=='.')) break;
// if ((*line=='.') && (*(line+1)==0)) break;
*cmd_write++=*line++;
}
*cmd_write=0;
@ -80,6 +84,33 @@ void DOS_Shell::CMD_CLS(char * args) {
CALLBACK_RunRealInt(0x10);
};
void DOS_Shell::CMD_DELETE(char * args) {
char * rem=ScanCMDRemain(args);
if (rem) {
WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem);
return;
}
char full[DOS_PATHLENGTH];
if (!DOS_Canonicalize(args,full)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH"));return; }
//TODO Maybe support confirmation for *.* like dos does.
bool res=DOS_FindFirst(args,0xff);
if (!res) {
WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),args);return;
}
//end can't be 0, but if it is we'll get a nice crash, who cares :)
char * end=strrchr(full,'\\')+1;*end=0;
char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u time,date;Bit8u attr;
DOS_DTA dta(dos.dta);
while (res) {
dta.GetResult(name,size,date,time,attr);
if (!(attr & (DOS_ATTR_DIRECTORY|DOS_ATTR_READ_ONLY))) {
strcpy(end,name);
if (!DOS_UnlinkFile(full)) WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),full);
}
res=DOS_FindNext();
}
}
void DOS_Shell::CMD_HELP(char * args){
/* Print the help */
WriteOut(MSG_Get("SHELL_CMD_HELP"));
@ -91,6 +122,17 @@ void DOS_Shell::CMD_HELP(char * args){
}
void DOS_Shell::CMD_RENAME(char * args){
if(!*args) {SyntaxError();return;}
if((strchr(args,'*')!=NULL) || (strchr(args,'?')!=NULL) ) { WriteOut(MSG_Get("SHELL_CMD_NO_WILD"));return;}
char * arg2 =StripWord(args);
DOS_Rename(args,arg2);
}
void DOS_Shell::CMD_ECHO(char * args) {
if (!*args) {
if (echo) { WriteOut(MSG_Get("SHELL_CMD_ECHO_ON"));}
@ -187,7 +229,7 @@ void DOS_Shell::CMD_DIR(char * args) {
/* Make a full path in the args */
if (!DOS_Canonicalize(args,path)) {
WriteOut(MSG_Get("SHELL_CMD_DIR_PATH_ERROR"));
WriteOut(MSG_Get("SHELL_CMD_ILLEGAL_PATH"));
return;
}
*(strrchr(path,'\\')+1)=0;
@ -250,7 +292,7 @@ void DOS_Shell::CMD_DIR(char * args) {
//TODO Free Space
Bitu free_space=1024*1024*100;
if (Drives[drive]) {
Bit16u bytes_sector;Bit16u sectors_cluster;Bit16u total_clusters;Bit16u free_clusters;
Bit16u bytes_sector;Bit8u sectors_cluster;Bit16u total_clusters;Bit16u free_clusters;
Drives[drive]->AllocationInfo(&bytes_sector,&sectors_cluster,&total_clusters,&free_clusters);
free_space=bytes_sector*sectors_cluster*free_clusters;
}
@ -385,3 +427,4 @@ nextfile:
void DOS_Shell::CMD_REM(char * args) {
}

View File

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

View File

@ -47,6 +47,7 @@ void DOS_Shell::InputCommand(char * line) {
Bitu str_len=0;Bitu str_index=0;
while (size) {
dos.echo=false;
DOS_ReadFile(input_handle,&c,&n);
if (!n) {
size=0; //Kill the while loop
@ -164,10 +165,18 @@ void DOS_Shell::Execute(char * name,char * args) {
cmd.buffer[strlen(line)]=0xd;
/* Copy command line in stack block too */
MEM_BlockWrite(SegPhys(ss)+reg_sp+0x100,&cmd,128);
/* Parse FCB (first two parameters) and put them into the current DOS_PSP */
Bit8u add;
FCB_Parsename(dos.psp,0x5C,0x00,cmd.buffer,&add);
FCB_Parsename(dos.psp,0x6C,0x00,&cmd.buffer[add],&add);
block.exec.fcb1=RealMake(dos.psp,0x5C);
block.exec.fcb2=RealMake(dos.psp,0x6C);
/* Set the command line in the block and save it */
block.exec.cmdtail=RealMakeSeg(ss,reg_sp+0x100);
block.SaveData();
/* Save CS:IP to some point where i can return them from */
Bit32u oldeip=reg_eip;
Bit16u oldcs=SegValue(cs);
RealPt newcsip=CALLBACK_RealPointer(call_shellstop);
SegSet16(cs,RealSeg(newcsip));
reg_ip=RealOff(newcsip);
@ -181,7 +190,10 @@ void DOS_Shell::Execute(char * name,char * args) {
reg_bx=reg_sp;
flags.intf=false;
CALLBACK_RunRealInt(0x21);
/* Restore CS:IP and the stack */
reg_sp+=0x200;
reg_eip=oldeip;
SegSet16(cs,oldcs);
}
}

View File

@ -271,6 +271,10 @@ SOURCE=..\include\render.h
# End Source File
# Begin Source File
SOURCE=..\src\gui\render_support.h
# End Source File
# Begin Source File
SOURCE=..\src\gui\sdlmain.cpp
# End Source File
# Begin Source File
@ -335,6 +339,14 @@ SOURCE=..\src\hardware\adlib.cpp
# End Source File
# Begin Source File
SOURCE=..\src\hardware\cmos.cpp
# End Source File
# Begin Source File
SOURCE=..\src\hardware\disney.cpp
# End Source File
# Begin Source File
SOURCE=..\src\hardware\dma.cpp
# End Source File
# Begin Source File
@ -343,6 +355,10 @@ SOURCE=..\src\hardware\gameblaster.cpp
# End Source File
# Begin Source File
SOURCE=..\src\hardware\gus.cpp
# End Source File
# Begin Source File
SOURCE=..\src\hardware\hardware.cpp
# End Source File
# Begin Source File