mirror of
https://github.com/retro100/dosbox-wii.git
synced 2025-01-12 18:29:07 +01:00
DOSBox 0.57
This commit is contained in:
parent
44c0450545
commit
0e247f1518
41
ChangeLog
41
ChangeLog
@ -1,3 +1,44 @@
|
||||
0.57
|
||||
- added support for command /C
|
||||
- fixed all fcb-write functions
|
||||
- fixed fcb-parseline
|
||||
- added debugger under linux/freebsd
|
||||
- added debugger memory breakpoints and autolog function (heavy debug)
|
||||
- added loadfix.com program that eats up memory (default 64kb)
|
||||
Usage : loadfix [-option] [programname] [parameters]...
|
||||
Example: loadfix mm2 (Allocates 64kb and starts executable mm2)
|
||||
loadfix -32 mm2 (Allocates 32kb and starts executable mm2)
|
||||
loadfix -128 (Allocates 128kb)
|
||||
loadfix -f (frees all previous allocated memory)
|
||||
- added echoing of characters for input function
|
||||
- added support for backspace for input function
|
||||
- added partial support for int10:01 set cursortype
|
||||
- fixed most of the problems/bugs with character input.
|
||||
- fixed allocationinfo call.(darksun series)
|
||||
- improved dos support for non-existant functions
|
||||
- Split screen support
|
||||
- prefix 66 67 support
|
||||
- rewrote timingscheme so 1000 hz timers don't cause problems anymore
|
||||
- update adlib emulation
|
||||
- fixed some isues with the mouse (double clicks and visible when it shouldn't be)
|
||||
- improved mouse behaviour (mickey/pixel rate) and detection routines.
|
||||
- basic ansi.sys support
|
||||
- Disney sound system emulation
|
||||
- rewrote upcase/lowcase functions so they work fine with gcc3.2
|
||||
- SHELL: added rename and delete
|
||||
- added support for command /C. Fixed crashes in the shell
|
||||
- fixed various bugs when exiting dosbox
|
||||
- fixed a bug in XMS
|
||||
- fixed a bug with the joystick when pressing a button
|
||||
- create nicer configfiles.
|
||||
- bios_disk function improved.
|
||||
- trapflag support
|
||||
- improved vertical retrace timing.
|
||||
- PIT Timer improvements and many bug fixes
|
||||
- Many many bug fixes to the DOS subsystem
|
||||
- Support for memory allocation strategy
|
||||
- rewrote cpu mainloop to act more like a real cpu
|
||||
|
||||
0.56
|
||||
- added support for a configclass/configfile
|
||||
- added support for writing out the configclass into a configfile
|
||||
|
96
NEWS
96
NEWS
@ -1,4 +1,45 @@
|
||||
0.56:
|
||||
0.57
|
||||
- added support for command /C
|
||||
- fixed all fcb-write functions
|
||||
- fixed fcb-parseline
|
||||
- added debugger under linux/freebsd
|
||||
- added debugger memory breakpoints and autolog function (heavy debug)
|
||||
- added loadfix.com program that eats up memory (default 64kb)
|
||||
Usage : loadfix [-option] [programname] [parameters]...
|
||||
Example: loadfix mm2 (Allocates 64kb and starts executable mm2)
|
||||
loadfix -32 mm2 (Allocates 32kb and starts executable mm2)
|
||||
loadfix -128 (Allocates 128kb)
|
||||
loadfix -f (frees all previous allocated memory)
|
||||
- added echoing of characters for input function
|
||||
- added support for backspace for input function
|
||||
- added partial support for int10:01 set cursortype
|
||||
- fixed most of the problems/bugs with character input.
|
||||
- fixed allocationinfo call.(darksun series)
|
||||
- improved dos support for non-existant functions
|
||||
- Split screen support
|
||||
- prefix 66 67 support
|
||||
- rewrote timingscheme so 1000 hz timers don't cause problems anymore
|
||||
- update adlib emulation
|
||||
- fixed some isues with the mouse (double clicks and visible when it shouldn't be)
|
||||
- improved mouse behaviour (mickey/pixel rate) and detection routines.
|
||||
- basic ansi.sys support
|
||||
- Disney sound system emulation
|
||||
- rewrote upcase/lowcase functions so they work fine with gcc3.2
|
||||
- SHELL: added rename and delete
|
||||
- added support for command /C. Fixed crashes in the shell
|
||||
- fixed various bugs when exiting dosbox
|
||||
- fixed a bug in XMS
|
||||
- fixed a bug with the joystick when pressing a button
|
||||
- create nicer configfiles.
|
||||
- bios_disk function improved.
|
||||
- trapflag support
|
||||
- improved vertical retrace timing.
|
||||
- PIT Timer improvements and many bug fixes
|
||||
- Many many bug fixes to the DOS subsystem
|
||||
- Support for memory allocation strategy
|
||||
- rewrote cpu mainloop to act more like a real cpu
|
||||
|
||||
0.56
|
||||
- added support for a configclass/configfile
|
||||
- added support for writing out the configclass into a configfile
|
||||
- removed the language file and made it internal
|
||||
@ -18,31 +59,34 @@
|
||||
- Added more cpu instructions and changed the string operations.
|
||||
- Added classes for most of the internal dos structures.
|
||||
- Rewrote most of the fcb calls to use normal dos calls.
|
||||
|
||||
|
||||
|
||||
0.55:
|
||||
- changed basedir handling. (linux/winXP)
|
||||
- added some FCB-calls
|
||||
- improved support for user mousehandlers
|
||||
- fixed EGA graphics
|
||||
- fixed VGA graphics
|
||||
- fixed the displaying of text in some graphics modes
|
||||
- fixed write with size 0
|
||||
- changed memory management.
|
||||
- added full emm 3.2 support.
|
||||
- fixed and cleaned up the cpu flags.
|
||||
changed interrupt handler.
|
||||
- speeded up the graphics.
|
||||
- speeded up the cpu-core
|
||||
- added new features to the debugger: breakpoint support / data view / command line
|
||||
- partial support of list of lists (dos info block)
|
||||
- partial emm 4.0 support
|
||||
- fixes to graphics core fonts (text in sierra games is now correct)
|
||||
- changed dma
|
||||
- improved dma streams from emm memory
|
||||
- added some cga videomodes
|
||||
- added more funtions to the keyboard handler
|
||||
|
||||
0.55
|
||||
- fixed the errors/warnings in prefix_66.h and prefix_66_of.h (decimal too large becomming unsigned).
|
||||
- fixed compilation error on FreeBSD when #disable_joystick was defined
|
||||
- int10_writechar has been updated to move the cursor position.
|
||||
- changed the basedir routines to use the current working dir instead of argv[0]. This will fix and brake things :)
|
||||
- illegal command, now displays the command
|
||||
- wildcmp updated to be case insensitive
|
||||
- added fcb:open,close,findfirst, findnext.
|
||||
- fixed rename in drive_local
|
||||
- added new features to the debugger: breakpoint support / data view / command line
|
||||
- partial support of list of lists (dos info block)
|
||||
- full emm 3.2 support
|
||||
- partial emm 4.0 support
|
||||
- fixes to graphics core fonts (text in sierra games is now correct)
|
||||
- improved support for user mousehandlers
|
||||
- fixed EGA graphics
|
||||
- fixed VGA graphics
|
||||
- fixed write with size 0
|
||||
- changed memory management.
|
||||
- fixed and cleaned up the cpu flags.
|
||||
- changed interrupt handler.
|
||||
- speeded up the graphics.
|
||||
- speeded up the cpu-core
|
||||
- changed dma
|
||||
- improved dma streams from emm memory
|
||||
- added some cga videomodes
|
||||
- added more funtions to the keyboard handler
|
||||
|
||||
0.50:
|
||||
-added F3 to repeat the last typed command.
|
||||
|
3
README
3
README
@ -1,4 +1,4 @@
|
||||
DOSBox v0.56
|
||||
DOSBox v0.57
|
||||
|
||||
Usage:
|
||||
======
|
||||
@ -122,6 +122,7 @@ Vlad R. of the vdmsound project for excellent sound blaster info.
|
||||
Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator.
|
||||
The Bochs and DOSemu projects which I used for information.
|
||||
Freedos for ideas in making my shell.
|
||||
The Beta Testers.
|
||||
|
||||
Contact:
|
||||
========
|
||||
|
1
THANKS
1
THANKS
@ -6,3 +6,4 @@ Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator.
|
||||
The Bochs and DOSemu projects which I used for information.
|
||||
Freedos for ideas in making my shell.
|
||||
All the people who submitted a bug.
|
||||
The Beta Testers.
|
||||
|
20
configure
vendored
20
configure
vendored
@ -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'`\\"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
13
settings.h
13
settings.h
@ -17,18 +17,15 @@
|
||||
*/
|
||||
|
||||
#ifndef _SETTINGS_H_
|
||||
#define _SETTINSG_H_
|
||||
#define _SETTINGS_H_
|
||||
|
||||
/* Enable the debugger, this only seems to work in win32 for now. */
|
||||
/* Enable the debugger, under linux/freebsd dosbox must be started in an xterm under X */
|
||||
#define C_DEBUG 0
|
||||
#define C_HEAVY_DEBUG 0
|
||||
|
||||
/* Enable the logging of extra information for debugging to the console */
|
||||
#define C_LOGGING 0
|
||||
|
||||
/* Use multi threading to speed up things on multi cpu's, also gives a nice frame-skipping effect :) */
|
||||
#define C_THREADED 1
|
||||
|
||||
/* Enable some big compile-time increasing inlines, great for speed though */
|
||||
#define C_EXTRAINLINE 0
|
||||
|
||||
@ -38,12 +35,6 @@
|
||||
/* Maximum memory range in megabytes */
|
||||
#define C_MEM_MAX_SIZE 12
|
||||
|
||||
/* Maximum memory available for xms, should be lower than maxsize-1 */
|
||||
#define C_MEM_XMS_SIZE 8
|
||||
|
||||
/* Maximum memory available for ems, should be lower than 32 */
|
||||
#define C_MEM_EMS_SIZE 4
|
||||
|
||||
/* Enable debug messages for several modules, requires C_LOGGING */
|
||||
#define DEBUG_SBLASTER 0 /* SoundBlaster Debugging*/
|
||||
#define DEBUG_DMA 0 /* DMA Debugging */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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); \
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) ) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -16,4 +16,6 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
decode_end:
|
||||
|
||||
SAVEIP;
|
||||
|
@ -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
|
||||
|
@ -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};
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
157
src/dos/dos.cpp
157
src/dos/dos.cpp
@ -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,®_cx,®_ax,®_dx)) reg_al=0xff;
|
||||
if (!DOS_GetAllocationInfo(0,®_cx,®_al,®_dx)) reg_al=0xff;
|
||||
break;
|
||||
case 0x1c: /* Get allocation info for specific drive */
|
||||
if (!DOS_GetAllocationInfo(reg_dl,®_cx,®_ax,®_dx)) reg_al=0xff;
|
||||
if (!DOS_GetAllocationInfo(reg_dl,®_cx,®_al,®_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,§ors,&clusters,&free)) {
|
||||
reg_ax=sectors;
|
||||
reg_bx=free;
|
||||
@ -459,7 +454,7 @@ static Bitu DOS_21Handler(void) {
|
||||
case 0x3f: /* READ Read from file or device */
|
||||
{
|
||||
Bit16u toread=reg_cx;
|
||||
if (reg_cx+reg_dx>0xffff) LOG_DEBUG("DOS:READ:Buffer overflow %d",reg_cx+reg_dx);
|
||||
dos.echo=true;
|
||||
if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
|
||||
MEM_BlockWrite(SegPhys(ds)+reg_dx,dos_copybuf,toread);
|
||||
reg_ax=toread;
|
||||
@ -468,12 +463,12 @@ static Bitu DOS_21Handler(void) {
|
||||
reg_ax=dos.errorcode;
|
||||
CALLBACK_SCF(true);
|
||||
}
|
||||
dos.echo=false;
|
||||
break;
|
||||
}
|
||||
case 0x40: /* WRITE Write to file or device */
|
||||
{
|
||||
Bit16u towrite=reg_cx;
|
||||
if (reg_cx+reg_dx>0xffff) LOG_DEBUG("DOS:WRITE:Buffer overflow %d",reg_cx+reg_dx);
|
||||
MEM_BlockRead(SegPhys(ds)+reg_dx,dos_copybuf,towrite);
|
||||
if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) {
|
||||
reg_ax=towrite;
|
||||
@ -604,8 +599,11 @@ static Bitu DOS_21Handler(void) {
|
||||
}
|
||||
break;
|
||||
//TODO Check for use of execution state AL=5
|
||||
case 0x00:
|
||||
reg_ax=0x4c00; /* Terminate Program */
|
||||
case 0x4c: /* EXIT Terminate with return code */
|
||||
{
|
||||
|
||||
{
|
||||
if (DOS_Terminate(false)) {
|
||||
/* This can't ever return false normally */
|
||||
} else {
|
||||
@ -652,9 +650,10 @@ static Bitu DOS_21Handler(void) {
|
||||
//TODO Think hard how shit this is gonna be
|
||||
//And will any game ever use this :)
|
||||
case 0x53: /* Translate BIOS parameter block to drive parameter block */
|
||||
//YEAH RIGHT
|
||||
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
|
||||
break;
|
||||
case 0x54: /* Get verify flag */
|
||||
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
|
||||
reg_al=dos.verify?1:0;
|
||||
break;
|
||||
case 0x55: /* Create Child PSP*/
|
||||
DOS_NewPSP(reg_dx,reg_si);
|
||||
@ -686,9 +685,10 @@ static Bitu DOS_21Handler(void) {
|
||||
case 0x58: /* Get/Set Memory allocation strategy */
|
||||
switch (reg_al) {
|
||||
case 0: /* Get Strategy */
|
||||
reg_ax=0; //Low memory first fit
|
||||
reg_ax=DOS_GetMemAllocStrategy();
|
||||
break;
|
||||
case 1: /* Set Strategy */
|
||||
DOS_SetMemAllocStrategy(reg_bx);
|
||||
break;
|
||||
default:
|
||||
LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al);
|
||||
@ -733,8 +733,8 @@ static Bitu DOS_21Handler(void) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x5c: /* FLOCK File region locking */
|
||||
case 0x5d: /* Network Functions */
|
||||
case 0x5e: /* More Network Functions */
|
||||
case 0x5f: /* And Even More Network Functions */
|
||||
E_Exit("DOS:Unhandled call %02X",reg_ah);
|
||||
@ -752,10 +752,6 @@ static Bitu DOS_21Handler(void) {
|
||||
case 0x62: /* Get Current PSP Address */
|
||||
reg_bx=dos.psp;
|
||||
break;
|
||||
case 0x63: /* Weirdo double byte stuff */
|
||||
reg_al=0xff;
|
||||
LOG_WARN("DOS:0x63:Doubly byte characters not supported");
|
||||
break;
|
||||
case 0x64: /* Set device driver lookahead flag */
|
||||
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
|
||||
break;
|
||||
@ -792,9 +788,6 @@ static Bitu DOS_21Handler(void) {
|
||||
LOG_DEBUG("DOS:67:Set Handle Count not working");
|
||||
CALLBACK_SCF(false);
|
||||
break;
|
||||
case 0x68: /* FFLUSH Commit file */
|
||||
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
|
||||
break;
|
||||
case 0x69: /* Get/Set disk serial number */
|
||||
{
|
||||
switch(reg_al) {
|
||||
@ -817,11 +810,21 @@ static Bitu DOS_21Handler(void) {
|
||||
CALLBACK_SCF(true);
|
||||
LOG_WARN("DOS:Windows long file name support call %2X",reg_al);
|
||||
break;
|
||||
case 0xE0:
|
||||
LOG_DEBUG("DOS:E0:Unhandled, what should this call do?");
|
||||
break;
|
||||
case 0x68: /* FFLUSH Commit file */
|
||||
case 0x63: /* Weirdo double byte stuff (fails but say it succeeded) available only in MSDOS 2.25 */
|
||||
CALLBACK_SCF(false); //mirek
|
||||
case 0xE0:
|
||||
case 0x18: /* NULL Function for CP/M compatibility or Extended rename FCB */
|
||||
case 0x1d: /* NULL Function for CP/M compatibility or Extended rename FCB */
|
||||
case 0x1e: /* NULL Function for CP/M compatibility or Extended rename FCB */
|
||||
case 0x20: /* NULL Function for CP/M compatibility or Extended rename FCB */
|
||||
case 0x6b: /* NULL Function */
|
||||
case 0x61: /* UNUSED */
|
||||
case 0xEF: /* Used in Ancient Art Of War CGA */
|
||||
case 0x5d: /* Network Functions */
|
||||
default:
|
||||
E_Exit("DOS:Unhandled call %02X",reg_ah);
|
||||
LOG_DEBUG("DOS:Unhandled call %02X al=%02X. Set al to default of 0",reg_ah,reg_al);
|
||||
reg_al=0x00; /* default value */
|
||||
break;
|
||||
};
|
||||
return CBRET_NONE;
|
||||
@ -837,6 +840,22 @@ static Bitu DOS_20Handler(void) {
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
static Bitu DOS_27Handler(void)
|
||||
{
|
||||
// Terminate & stay resident
|
||||
Bit16u para = (reg_dx/16)+((reg_dx % 16)>0);
|
||||
if (DOS_ResizeMemory(dos.psp,¶)) DOS_Terminate(true);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
static Bitu DOS_28Handler(void) {
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
static Bitu DOS_29Handler(void) {
|
||||
LOG_DEBUG("int 29 called");
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
void DOS_Init(Section* sec) {
|
||||
MSG_Add("DOS_CONFIGFILE_HELP","Setting a memory size to 0 will disable it.\n");
|
||||
@ -845,9 +864,21 @@ void DOS_Init(Section* sec) {
|
||||
RealSetVec(0x20,CALLBACK_RealPointer(call_20));
|
||||
|
||||
call_21=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET);
|
||||
CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET_STI);
|
||||
RealSetVec(0x21,CALLBACK_RealPointer(call_21));
|
||||
|
||||
call_27=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_27,DOS_27Handler,CB_IRET);
|
||||
RealSetVec(0x27,CALLBACK_RealPointer(call_27));
|
||||
|
||||
call_28=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_28,DOS_28Handler,CB_IRET);
|
||||
RealSetVec(0x28,CALLBACK_RealPointer(call_28));
|
||||
|
||||
call_29=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_29,DOS_29Handler,CB_IRET);
|
||||
RealSetVec(0x29,CALLBACK_RealPointer(call_29));
|
||||
|
||||
DOS_SetupFiles(); /* Setup system File tables */
|
||||
DOS_SetupDevices(); /* Setup dos devices */
|
||||
DOS_SetupTables();
|
||||
@ -855,8 +886,16 @@ void DOS_Init(Section* sec) {
|
||||
DOS_SetupPrograms();
|
||||
DOS_SetupMisc(); /* Some additional dos interrupts */
|
||||
DOS_SetDefaultDrive(25);
|
||||
/* Execute the file that should be */
|
||||
|
||||
dos.version.major=5;
|
||||
dos.version.minor=0;
|
||||
// DOS_RunProgram(startname);
|
||||
};
|
||||
/* Setup time and date */
|
||||
time_t curtime;struct tm *loctime;
|
||||
curtime = time (NULL);loctime = localtime (&curtime);
|
||||
|
||||
dos.date.day=(Bit8u)loctime->tm_mday;
|
||||
dos.date.month=(Bit8u)loctime->tm_mon+1;
|
||||
dos.date.year=(Bit16u)loctime->tm_year+1900;
|
||||
Bit32u ticks=(Bit32u)((loctime->tm_hour*3600+loctime->tm_min*60+loctime->tm_sec)*18.2);
|
||||
mem_writed(BIOS_TIMER,ticks);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
228
src/gui/render_support.h
Normal 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();
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
||||
|
@ -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@
|
||||
|
@ -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
118
src/hardware/cmos.cpp
Normal 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
102
src/hardware/disney.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
1499
src/hardware/fmopl.c
1499
src/hardware/fmopl.c
File diff suppressed because it is too large
Load Diff
@ -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
23
src/hardware/gus.cpp
Normal 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) {
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
196
src/ints/ems.cpp
196
src/ints/ems.cpp
@ -34,7 +34,7 @@
|
||||
#define EMM_PAGEFRAME 0xE000
|
||||
#define EMM_MAX_HANDLES 50 /* 255 Max */
|
||||
#define EMM_PAGE_SIZE (16*1024)
|
||||
#define EMM_MAX_PAGES (C_MEM_EMS_SIZE * 1024 / 16 )
|
||||
#define EMM_MAX_PAGES (32 * 1024 / 16 )
|
||||
#define EMM_MAX_PHYS 4 /* 4 16kb pages in pageframe */
|
||||
|
||||
#define EMM_VERSION 0x40
|
||||
@ -83,7 +83,7 @@ struct EMM_Mapping {
|
||||
};
|
||||
|
||||
struct EMM_Page {
|
||||
void * memory;
|
||||
HostPt * memory;
|
||||
Bit16u handle;
|
||||
Bit16u next;
|
||||
};
|
||||
@ -91,7 +91,7 @@ struct EMM_Page {
|
||||
struct EMM_Handle {
|
||||
Bit16u first_page;
|
||||
Bit16u pages;
|
||||
char name[9];
|
||||
char name[8];
|
||||
bool saved_page_map;
|
||||
EMM_Mapping page_map[EMM_MAX_PHYS];
|
||||
};
|
||||
@ -100,8 +100,21 @@ static EMM_Handle emm_handles[EMM_MAX_HANDLES];
|
||||
static EMM_Page emm_pages[EMM_MAX_PAGES];
|
||||
static EMM_Mapping emm_mappings[EMM_MAX_PHYS];
|
||||
static HostPt emm_pagebase[EMM_MAX_PHYS];
|
||||
static Bitu emm_page_count;
|
||||
Bitu call_int67;
|
||||
|
||||
struct MoveRegion {
|
||||
Bit32u bytes;
|
||||
Bit8u src_type;
|
||||
Bit16u src_handle;
|
||||
Bit16u src_offset;
|
||||
Bit16u src_page_seg;
|
||||
Bit8u dest_type;
|
||||
Bit16u dest_handle;
|
||||
Bit16u dest_offset;
|
||||
Bit16u dest_page_seg;
|
||||
};
|
||||
|
||||
#if EMM_USEHANDLER
|
||||
Bit8u EMM_ReadHandler(PhysPt start) {
|
||||
start-=EMM_PAGEFRAME * 16;
|
||||
@ -118,12 +131,18 @@ void EMM_WriteHandler(PhysPt start,Bit8u val) {
|
||||
|
||||
static Bit16u EMM_GetFreePages(void) {
|
||||
Bit16u count=0;
|
||||
for (Bitu index=0;index<EMM_MAX_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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
}
|
||||
};
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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());
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#define INLINE __forceinline
|
||||
|
||||
#define VERSION "0.56"
|
||||
#define VERSION "0.57"
|
||||
|
||||
#define GCC_ATTRIBUTE(x) /* attribute not supported */
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -28,6 +28,8 @@ static SHELL_Cmd cmd_list[]={
|
||||
"CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP",
|
||||
// "COPY", 0, &DOS_Shell::CMD_COPY, "Copy Files.",
|
||||
"DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP",
|
||||
"DEL", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP",
|
||||
"DELETE", 0, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP",
|
||||
"ECHO", 0, &DOS_Shell::CMD_ECHO, "SHELL_CMD_ECHO_HELP",
|
||||
"EXIT", 0, &DOS_Shell::CMD_EXIT, "SHELL_CMD_EXIT_HELP",
|
||||
"HELP", 0, &DOS_Shell::CMD_HELP, "SHELL_CMD_HELP_HELP",
|
||||
@ -38,7 +40,8 @@ static SHELL_Cmd cmd_list[]={
|
||||
"GOTO", 0, &DOS_Shell::CMD_GOTO, "SHELL_CMD_GOTO_HELP",
|
||||
"TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP",
|
||||
"REM", 0, &DOS_Shell::CMD_REM, "SHELL_CMD_REM_HELP",
|
||||
|
||||
"RENAME", 0, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP",
|
||||
"REN", 1, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP",
|
||||
/*
|
||||
"CHDIR", 0, &DOS_Shell::CMD_CHDIR, "Change Directory",
|
||||
"MKDIR", 0, &DOS_Shell::CMD_MKDIR, "Make Directory",
|
||||
@ -56,6 +59,7 @@ void DOS_Shell::DoCommand(char * line) {
|
||||
if (*line==32) break;
|
||||
if (*line=='/') break;
|
||||
if ((*line=='.') && (*(line+1)=='.')) break;
|
||||
// if ((*line=='.') && (*(line+1)==0)) break;
|
||||
*cmd_write++=*line++;
|
||||
}
|
||||
*cmd_write=0;
|
||||
@ -80,6 +84,33 @@ void DOS_Shell::CMD_CLS(char * args) {
|
||||
CALLBACK_RunRealInt(0x10);
|
||||
};
|
||||
|
||||
void DOS_Shell::CMD_DELETE(char * args) {
|
||||
char * rem=ScanCMDRemain(args);
|
||||
if (rem) {
|
||||
WriteOut(MSG_Get("SHELL_ILLEGAL_SWITCH"),rem);
|
||||
return;
|
||||
}
|
||||
char full[DOS_PATHLENGTH];
|
||||
if (!DOS_Canonicalize(args,full)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH"));return; }
|
||||
//TODO Maybe support confirmation for *.* like dos does.
|
||||
bool res=DOS_FindFirst(args,0xff);
|
||||
if (!res) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),args);return;
|
||||
}
|
||||
//end can't be 0, but if it is we'll get a nice crash, who cares :)
|
||||
char * end=strrchr(full,'\\')+1;*end=0;
|
||||
char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u time,date;Bit8u attr;
|
||||
DOS_DTA dta(dos.dta);
|
||||
while (res) {
|
||||
dta.GetResult(name,size,date,time,attr);
|
||||
if (!(attr & (DOS_ATTR_DIRECTORY|DOS_ATTR_READ_ONLY))) {
|
||||
strcpy(end,name);
|
||||
if (!DOS_UnlinkFile(full)) WriteOut(MSG_Get("SHELL_CMD_DEL_ERROR"),full);
|
||||
}
|
||||
res=DOS_FindNext();
|
||||
}
|
||||
}
|
||||
|
||||
void DOS_Shell::CMD_HELP(char * args){
|
||||
/* Print the help */
|
||||
WriteOut(MSG_Get("SHELL_CMD_HELP"));
|
||||
@ -91,6 +122,17 @@ void DOS_Shell::CMD_HELP(char * args){
|
||||
|
||||
}
|
||||
|
||||
void DOS_Shell::CMD_RENAME(char * args){
|
||||
if(!*args) {SyntaxError();return;}
|
||||
if((strchr(args,'*')!=NULL) || (strchr(args,'?')!=NULL) ) { WriteOut(MSG_Get("SHELL_CMD_NO_WILD"));return;}
|
||||
char * arg2 =StripWord(args);
|
||||
DOS_Rename(args,arg2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void DOS_Shell::CMD_ECHO(char * args) {
|
||||
if (!*args) {
|
||||
if (echo) { WriteOut(MSG_Get("SHELL_CMD_ECHO_ON"));}
|
||||
@ -187,7 +229,7 @@ void DOS_Shell::CMD_DIR(char * args) {
|
||||
|
||||
/* Make a full path in the args */
|
||||
if (!DOS_Canonicalize(args,path)) {
|
||||
WriteOut(MSG_Get("SHELL_CMD_DIR_PATH_ERROR"));
|
||||
WriteOut(MSG_Get("SHELL_CMD_ILLEGAL_PATH"));
|
||||
return;
|
||||
}
|
||||
*(strrchr(path,'\\')+1)=0;
|
||||
@ -250,7 +292,7 @@ void DOS_Shell::CMD_DIR(char * args) {
|
||||
//TODO Free Space
|
||||
Bitu free_space=1024*1024*100;
|
||||
if (Drives[drive]) {
|
||||
Bit16u bytes_sector;Bit16u sectors_cluster;Bit16u total_clusters;Bit16u free_clusters;
|
||||
Bit16u bytes_sector;Bit8u sectors_cluster;Bit16u total_clusters;Bit16u free_clusters;
|
||||
Drives[drive]->AllocationInfo(&bytes_sector,§ors_cluster,&total_clusters,&free_clusters);
|
||||
free_space=bytes_sector*sectors_cluster*free_clusters;
|
||||
}
|
||||
@ -385,3 +427,4 @@ nextfile:
|
||||
void DOS_Shell::CMD_REM(char * args) {
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user