1
0
Fork 0

First CVS upload.

Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@80
This commit is contained in:
Sjoerd van der Berg 2002-07-27 13:08:48 +00:00
parent 7d1ca9bdd4
commit 42e5d0b779
158 changed files with 42940 additions and 0 deletions

10
src/Makefile.am Normal file
View file

@ -0,0 +1,10 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
SUBDIRS = cpu debug dos fpu gui hardware ints misc shell platform
bin_PROGRAMS = dosbox
dosbox_SOURCES = dosbox.cpp
dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a hardware/libhardware.a gui/libgui.a \
ints/libints.a misc/libmisc.a shell/libshell.a -lcurses
EXTRA_DIST = dosbox.lang

5
src/cpu/Makefile.am Normal file
View file

@ -0,0 +1,5 @@
SUBDIRS = core_16
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libcpu.a
libcpu_a_SOURCES = callback.cpp cpu.cpp flags.cpp modrm.cpp modrm.h slow_16.cpp

171
src/cpu/callback.cpp Normal file
View file

@ -0,0 +1,171 @@
/*
* 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 <stdlib.h>
#include <stdio.h>
#include "dosbox.h"
#include "callback.h"
#include "mem.h"
#include "cpu.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
far return or and IRET
*/
CallBack_Handler CallBack_Handlers[CB_MAX];
static Bitu call_runint16,call_idle,call_default,call_runfar16;
static Bitu illegal_handler(void) {
E_Exit("Illegal CallBack Called");
return 1;
}
Bitu CALLBACK_Allocate(void) {
for (Bitu i=0;(i<CB_MAX);i++) {
if (CallBack_Handlers[i]==&illegal_handler) {
CallBack_Handlers[i]=0;
return i;
}
}
E_Exit("CALLBACK:Can't allocate handler.");
return 0;
}
void CALLBACK_Idle(void) {
/* this makes the cpu execute instructions to handle irq's and then come back */
Bit16u oldcs=Segs[cs].value;
Bit32u oldeip=reg_eip;
SetSegment_16(cs,CB_SEG);
reg_eip=call_idle<<4;
DOSBOX_RunMachine();
reg_eip=oldeip;
SetSegment_16(cs,oldcs);
}
static Bitu default_handler(void) {
LOG_WARN("Illegal Unhandled Interrupt Called %d",lastint);
return CBRET_NONE;
};
static Bitu stop_handler(void) {
return CBRET_STOP;
};
void CALLBACK_RunRealFar(Bit16u seg,Bit16u off) {
real_writew((Bit16u)CB_SEG,(call_runfar16<<4)+1,off);
real_writew((Bit16u)CB_SEG,(call_runfar16<<4)+3,seg);
Bit32u oldeip=reg_eip;
Bit16u oldcs=Segs[cs].value;
reg_eip=call_runfar16<<4;
SetSegment_16(cs,CB_SEG);
DOSBOX_RunMachine();
reg_eip=oldeip;
SetSegment_16(cs,oldcs);
}
void CALLBACK_RunRealInt(Bit8u intnum) {
real_writeb((Bit16u)CB_SEG,(call_runint16<<4)+1,intnum);
Bit32u oldeip=reg_eip;
Bit16u oldcs=Segs[cs].value;
reg_eip=call_runint16<<4;
SetSegment_16(cs,CB_SEG);
DOSBOX_RunMachine();
reg_eip=oldeip;
SetSegment_16(cs,oldcs);
}
void CALLBACK_SZF(bool val) {
Bit16u tempf=real_readw(Segs[ss].value,reg_sp+4) & 0xFFBF;
Bit16u newZF=(val==true) << 6;
real_writew(Segs[ss].value,reg_sp+4,(tempf | newZF));
};
void CALLBACK_SCF(bool val) {
Bit16u tempf=real_readw(Segs[ss].value,reg_sp+4) & 0xFFFE;
Bit16u newCF=(val==true);
real_writew(Segs[ss].value,reg_sp+4,(tempf | newCF));
};
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)+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)+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;
default:
E_Exit("CALLBACK:Setup:Illegal type %d",type);
}
CallBack_Handlers[callback]=handler;
return true;
}
void CALLBACK_Init(void) {
Bitu i;
for (i=0;i<CB_MAX;i++) {
CallBack_Handlers[i]=&illegal_handler;
}
/* Setup the Software interrupt handler */
call_runint16=CALLBACK_Allocate();
CallBack_Handlers[call_runint16]=stop_handler;
real_writeb((Bit16u)CB_SEG,(call_runint16<<4),0xCD);
real_writeb((Bit16u)CB_SEG,(call_runint16<<4)+2,0xFE);
real_writeb((Bit16u)CB_SEG,(call_runint16<<4)+3,0x38);
real_writew((Bit16u)CB_SEG,(call_runint16<<4)+4,call_runint16);
/* Setup the Far Call handler */
call_runfar16=CALLBACK_Allocate();
CallBack_Handlers[call_runfar16]=stop_handler;
real_writeb((Bit16u)CB_SEG,(call_runfar16<<4),0x9A);
real_writeb((Bit16u)CB_SEG,(call_runfar16<<4)+5,0xFE);
real_writeb((Bit16u)CB_SEG,(call_runfar16<<4)+6,0x38);
real_writew((Bit16u)CB_SEG,(call_runfar16<<4)+7,call_runfar16);
/* Setup the idle handler */
call_idle=CALLBACK_Allocate();
CallBack_Handlers[call_idle]=stop_handler;
for (i=0;i<=11;i++) real_writeb((Bit16u)CB_SEG,(call_idle<<4)+i,0x90);
real_writeb((Bit16u)CB_SEG,(call_idle<<4)+12,0xFE);
real_writeb((Bit16u)CB_SEG,(call_idle<<4)+13,0x38);
real_writew((Bit16u)CB_SEG,(call_idle<<4)+14,call_idle);
/* Setup all Interrupt to point to the default handler */
call_default=CALLBACK_Allocate();
CALLBACK_Setup(call_default,&default_handler,CB_IRET);
for (i=0;i<256;i++) {
real_writed(0,i*4,CALLBACK_RealPointer(call_default));
}
}

View file

@ -0,0 +1,3 @@
noinst_HEADERS = helpers.h instructions.h main.h prefix_66.h prefix_of.h start.h stop.h support.h table_ea.h \
prefix_66_of.h

76
src/cpu/core_16/helpers.h Normal file
View file

@ -0,0 +1,76 @@
/*
* 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.
*/
#define GetEAa \
EAPoint eaa=(*lookupEATable)[rm]();
#define GetRMEAa \
GetRM; \
GetEAa;
#define RMEbGb(inst) \
{ \
GetRMrb; \
if (rm >= 0xc0 ) {GetEArb;inst(*earb,*rmrb,LoadRb,SaveRb);} \
else {GetEAa;inst(eaa,*rmrb,LoadMb,SaveMb);} \
}
#define RMGbEb(inst) \
{ \
GetRMrb; \
if (rm >= 0xc0 ) {GetEArb;inst(*rmrb,*earb,LoadRb,SaveRb);} \
else {GetEAa;inst(*rmrb,LoadMb(eaa),LoadRb,SaveRb);} \
}
#define RMEwGw(inst) \
{ \
GetRMrw; \
if (rm >= 0xc0 ) {GetEArw;inst(*earw,*rmrw,LoadRw,SaveRw);} \
else {GetEAa;inst(eaa,*rmrw,LoadMw,SaveMw);} \
}
#define RMGwEw(inst) \
{ \
GetRMrw; \
if (rm >= 0xc0 ) {GetEArw;inst(*rmrw,*earw,LoadRw,SaveRw);} \
else {GetEAa;inst(*rmrw,LoadMw(eaa),LoadRw,SaveRw);} \
}
#define RMEdGd(inst) \
{ \
GetRMrd; \
if (rm >= 0xc0 ) {GetEArd;inst(*eard,*rmrd,LoadRd,SaveRd);} \
else {GetEAa;inst(eaa,*rmrd,LoadMd,SaveMd);} \
}
#define RMGdEd(inst) \
{ \
GetRMrd; \
if (rm >= 0xc0 ) {GetEArd;inst(*rmrd,*eard,LoadRd,SaveRd);} \
else {GetEAa;inst(*rmrd,LoadMd(eaa),LoadRd,SaveRd);} \
}
#define ALIb(inst) \
{ inst(reg_al,Fetchb(),LoadRb,SaveRb)}
#define AXIw(inst) \
{ inst(reg_ax,Fetchw(),LoadRw,SaveRw);}
#define EAXId(inst) \
{ inst(reg_eax,Fetchd(),LoadRd,SaveRd);}

View file

@ -0,0 +1,593 @@
/*
* 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.
*/
/* Jumps */
/*
Could perhaps do some things with 8 and 16 bit operations like shifts, doing them in 32 bit regs
*/
#define JumpSIb(blah) \
if (blah) { \
ADDIPFAST(Fetchbs()); \
} else { \
ADDIPFAST(1); \
}
#define JumpSIw(blah) \
if (blah) { \
ADDIPFAST(Fetchws()); \
} else { \
ADDIPFAST(2); \
}
#define INTERRUPT(blah) \
{ \
Bit8u new_num=blah; \
SAVEIP; \
Interrupt(new_num); \
LOADIP; \
}
/* All Byte genereal instructions */
#define ADDB(op1,op2,load,save) \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b+flags.var2.b; \
save(op1,flags.result.b); \
flags.type=t_ADDb;
#define ADCB(op1,op2,load,save) \
flags.oldcf=get_CF(); \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b+flags.var2.b+flags.oldcf; \
save(op1,flags.result.b); \
flags.type=t_ADCb;
#define SBBB(op1,op2,load,save) \
flags.oldcf=get_CF(); \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b-(flags.var2.b+flags.oldcf); \
save(op1,flags.result.b); \
flags.type=t_SBBb;
#define SUBB(op1,op2,load,save) \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b-flags.var2.b; \
save(op1,flags.result.b); \
flags.type=t_SUBb;
#define ORB(op1,op2,load,save) \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b | flags.var2.b; \
save(op1,flags.result.b); \
flags.type=t_ORb;
#define XORB(op1,op2,load,save) \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b ^ flags.var2.b; \
save(op1,flags.result.b); \
flags.type=t_XORb;
#define ANDB(op1,op2,load,save) \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b & flags.var2.b; \
save(op1,flags.result.b); \
flags.type=t_ANDb;
#define CMPB(op1,op2,load,save) \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b-flags.var2.b; \
flags.type=t_CMPb;
#define TESTB(op1,op2,load,save) \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b & flags.var2.b; \
flags.type=t_TESTb;
/* All Word General instructions */
#define ADDW(op1,op2,load,save) \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w+flags.var2.w; \
save(op1,flags.result.w); \
flags.type=t_ADDw;
#define ADCW(op1,op2,load,save) \
flags.oldcf=get_CF(); \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w+flags.var2.w+flags.oldcf; \
save(op1,flags.result.w); \
flags.type=t_ADCw;
#define SBBW(op1,op2,load,save) \
flags.oldcf=get_CF(); \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w-(flags.var2.w+flags.oldcf); \
save(op1,flags.result.w); \
flags.type=t_SBBw;
#define SUBW(op1,op2,load,save) \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w-flags.var2.w; \
save(op1,flags.result.w); \
flags.type=t_SUBw;
#define ORW(op1,op2,load,save) \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w | flags.var2.w; \
save(op1,flags.result.w); \
flags.type=t_ORw;
#define XORW(op1,op2,load,save) \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w ^ flags.var2.w; \
save(op1,flags.result.w); \
flags.type=t_XORw;
#define ANDW(op1,op2,load,save) \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w & flags.var2.w; \
save(op1,flags.result.w); \
flags.type=t_ANDw;
#define CMPW(op1,op2,load,save) \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w-flags.var2.w; \
flags.type=t_CMPw;
#define TESTW(op1,op2,load,save) \
flags.var1.w=load(op1);flags.var2.w=op2; \
flags.result.w=flags.var1.w & flags.var2.w; \
flags.type=t_TESTw;
/* All DWORD General Instructions */
#define ADDD(op1,op2,load,save) \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d+flags.var2.d; \
save(op1,flags.result.d); \
flags.type=t_ADDd;
#define ADCD(op1,op2,load,save) \
flags.oldcf=get_CF(); \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d+flags.var2.d+flags.oldcf; \
save(op1,flags.result.d); \
flags.type=t_ADCd;
#define SBBD(op1,op2,load,save) \
flags.oldcf=get_CF(); \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d-(flags.var2.d+flags.oldcf); \
save(op1,flags.result.d); \
flags.type=t_SBBd;
#define SUBD(op1,op2,load,save) \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d-flags.var2.d; \
save(op1,flags.result.d); \
flags.type=t_SUBd;
#define ORD(op1,op2,load,save) \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d | flags.var2.d; \
save(op1,flags.result.d); \
flags.type=t_ORd;
#define XORD(op1,op2,load,save) \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d ^ flags.var2.d; \
save(op1,flags.result.d); \
flags.type=t_XORd;
#define ANDD(op1,op2,load,save) \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d & flags.var2.d; \
save(op1,flags.result.d); \
flags.type=t_ANDd;
#define CMPD(op1,op2,load,save) \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d-flags.var2.d; \
flags.type=t_CMPd;
#define TESTD(op1,op2,load,save) \
flags.var1.d=load(op1);flags.var2.d=op2; \
flags.result.d=flags.var1.d & flags.var2.d; \
flags.type=t_TESTd;
#define INCB(op1,load,save) \
LoadCF;flags.result.b=load(op1)+1; \
save(op1,flags.result.b); \
flags.type=t_INCb; \
#define INCW(op1,load,save) \
LoadCF;flags.result.w=load(op1)+1; \
save(op1,flags.result.w); \
flags.type=t_INCw;
#define INCD(op1,load,save) \
LoadCF;flags.result.d=load(op1)+1; \
save(op1,flags.result.d); \
flags.type=t_INCd;
#define DECB(op1,load,save) \
LoadCF;flags.result.b=load(op1)-1; \
save(op1,flags.result.b); \
flags.type=t_DECb;
#define DECW(op1,load,save) \
LoadCF;flags.result.w=load(op1)-1; \
save(op1,flags.result.w); \
flags.type=t_DECw;
#define DECD(op1,load,save) \
LoadCF;flags.result.d=load(op1)-1; \
save(op1,flags.result.d); \
flags.type=t_DECd;
#define NOTDONE \
SUBIP(1);E_Exit("CPU:Opcode %2X Unhandled",Fetchb());
#define NOTDONE66 \
SUBIP(1);E_Exit("CPU:Opcode 66:%2X Unhandled",Fetchb());
//TODO Maybe make this into a bigger split up because of the rm >=0xc0 this seems make it a bit slower
//TODO set Zero and Sign flag in one run
#define ROLB(op1,op2,load,save) \
if (!(op2&0x07)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.var1.b=load(op1);flags.var2.b=op2&0x07; \
flags.result.b=(flags.var1.b << flags.var2.b) | \
(flags.var1.b >> (8-flags.var2.b)); \
save(op1,flags.result.b); \
flags.type=t_ROLb;
#define ROLW(op1,op2,load,save) \
if (!(op2&0x0F)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.var1.w=load(op1);flags.var2.b=op2&0x0F; \
flags.result.w=(flags.var1.w << flags.var2.b) | \
(flags.var1.w >> (16-flags.var2.b)); \
save(op1,flags.result.w); \
flags.type=t_ROLw;
#define ROLD(op1,op2,load,save) \
if (!(op2&0x0F)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.var1.d=load(op1);flags.var2.b=op2&0x0F; \
flags.result.d=(flags.var1.d << flags.var2.b) | \
(flags.var1.d >> (32-flags.var2.b)); \
save(op1,flags.result.d); \
flags.type=t_ROLd;
#define RORB(op1,op2,load,save) \
if (!(op2&0x07)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.var1.b=load(op1);flags.var2.b=op2&0x07; \
flags.result.b=(flags.var1.b >> flags.var2.b) | \
(flags.var1.b << (8-flags.var2.b)); \
save(op1,flags.result.b); \
flags.type=t_RORb;
#define RORW(op1,op2,load,save) \
if (!(op2&0x0F)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.var1.w=load(op1);flags.var2.b=op2&0x0F; \
flags.result.w=(flags.var1.w >> flags.var2.b) | \
(flags.var1.w << (16-flags.var2.b)); \
save(op1,flags.result.w); \
flags.type=t_RORw;
#define RORD(op1,op2,load,save) \
if (!(op2&0x0F)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.var1.d=load(op1);flags.var2.b=op2&0x0F; \
flags.result.d=(flags.var1.d >> flags.var2.b) | \
(flags.var1.d << (32-flags.var2.b)); \
save(op1,flags.result.d); \
flags.type=t_RORd;
#define RCLB(op1,op2,load,save) \
if (!(op2%9)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.cf=get_CF();flags.type=t_RCLb; \
flags.var1.b=load(op1);flags.var2.b=op2%9; \
flags.result.b=(flags.var1.b << flags.var2.b) | \
(flags.cf << (flags.var2.b-1)) | \
(flags.var1.b >> (9-flags.var2.b)); \
save(op1,flags.result.b);
#define RCLW(op1,op2,load,save) \
if (!(op2%17)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.cf=get_CF();flags.type=t_RCLw; \
flags.var1.w=load(op1);flags.var2.b=op2%17; \
flags.result.w=(flags.var1.w << flags.var2.b) | \
(flags.cf << (flags.var2.b-1)) | \
(flags.var1.w >> (17-flags.var2.b)); \
save(op1,flags.result.w);
#define RCLD(op1,op2,load,save) \
if (!op2) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.cf=get_CF();flags.type=t_RCLd; \
flags.var1.d=load(op1);flags.var2.b=op2; \
if (flags.var2.b==1) { \
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.var1.d >> (33-flags.var2.b)); \
} \
save(op1,flags.result.d);
#define RCRB(op1,op2,load,save) \
if (!(op2%9)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.cf=get_CF();flags.type=t_RCRb; \
flags.var1.b=load(op1);flags.var2.b=op2%9; \
flags.result.b=(flags.var1.b >> flags.var2.b) | \
(flags.cf << (8-flags.var2.b)) | \
(flags.var1.b << (9-flags.var2.b)); \
save(op1,flags.result.b);
#define RCRW(op1,op2,load,save) \
if (!(op2%17)) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.cf=get_CF();flags.type=t_RCRw; \
flags.var1.w=load(op1);flags.var2.b=op2%17; \
flags.result.w=(flags.var1.w >> flags.var2.b) | \
(flags.cf << (16-flags.var2.b)) | \
(flags.var1.w << (17-flags.var2.b)); \
save(op1,flags.result.w);
#define RCRD(op1,op2,load,save) \
if (!op2) break; \
flags.zf=get_ZF();flags.sf=get_SF();flags.af=get_AF(); \
flags.cf=get_CF();flags.type=t_RCRd; \
flags.var1.d=load(op1);flags.var2.b=op2; \
if (flags.var2.b==1) { \
flags.result.d=flags.var1.d >> 1 | flags.cf << 31; \
} else { \
flags.result.d=(flags.var1.d >> flags.var2.b) | \
(flags.cf << (32-flags.var2.b)) | \
(flags.var1.d << (33-flags.var2.b)); \
} \
save(op1,flags.result.d);
#define SHLB(op1,op2,load,save) \
if (!op2) break; \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b << flags.var2.b; \
save(op1,flags.result.b); \
flags.type=t_SHLb;
#define SHLW(op1,op2,load,save) \
if (!op2) break; \
flags.var1.w=load(op1);flags.var2.b=op2; \
flags.result.w=flags.var1.w << flags.var2.b; \
save(op1,flags.result.w); \
flags.type=t_SHLw;
#define SHLD(op1,op2,load,save) \
if (!op2) break; \
flags.var1.d=load(op1);flags.var2.b=op2; \
flags.result.d=flags.var1.d << flags.var2.b; \
save(op1,flags.result.d); \
flags.type=t_SHLd;
#define SHRB(op1,op2,load,save) \
if (!op2) break; \
flags.var1.b=load(op1);flags.var2.b=op2; \
flags.result.b=flags.var1.b >> flags.var2.b; \
save(op1,flags.result.b); \
flags.type=t_SHRb;
#define SHRW(op1,op2,load,save) \
if (!op2) break; \
flags.var1.w=load(op1);flags.var2.b=op2; \
flags.result.w=flags.var1.w >> flags.var2.b; \
save(op1,flags.result.w); \
flags.type=t_SHRw;
#define SHRD(op1,op2,load,save) \
if (!op2) break; \
flags.var1.d=load(op1);flags.var2.b=op2; \
flags.result.d=flags.var1.d >> flags.var2.b; \
save(op1,flags.result.d); \
flags.type=t_SHRd;
#define SARB(op1,op2,load,save) \
if (!op2) break; \
flags.var1.b=load(op1);flags.var2.b=op2; \
if (flags.var2.b>8) flags.var2.b=8; \
if (flags.var1.b & 0x80) { \
flags.result.b=(flags.var1.b >> flags.var2.b)| \
(0xff << (8 - flags.var2.b)); \
} else { \
flags.result.b=flags.var1.b >> flags.var2.b; \
} \
save(op1,flags.result.b); \
flags.type=t_SARb;
#define SARW(op1,op2,load,save) \
if (!op2) break; \
flags.var1.w=load(op1);flags.var2.b=op2; \
if (flags.var2.b>16) flags.var2.b=16; \
if (flags.var1.w & 0x8000) { \
flags.result.w=(flags.var1.w >> flags.var2.b)| \
(0xffff << (16 - flags.var2.b)); \
} else { \
flags.result.w=flags.var1.w >> flags.var2.b; \
} \
save(op1,flags.result.w); \
flags.type=t_SARw;
#define SARD(op1,op2,load,save) \
if (!op2) break; \
flags.var1.d=load(op1);flags.var2.b=op2; \
if (flags.var1.d & 0x80000000) { \
flags.result.d=(flags.var1.d >> flags.var2.b)| \
(0xffffffff << (32 - flags.var2.b)); \
} else { \
flags.result.d=flags.var1.d >> flags.var2.b; \
} \
save(op1,flags.result.d); \
flags.type=t_SARd;
#define GRP2B(blah) \
{ \
GetRM; \
if (rm >= 0xc0) { \
GetEArb; \
Bit8u val=blah & 0x1f; \
switch (rm&0x38) { \
case 0x00:ROLB(*earb,val,LoadRb,SaveRb);break; \
case 0x08:RORB(*earb,val,LoadRb,SaveRb);break; \
case 0x10:RCLB(*earb,val,LoadRb,SaveRb);break; \
case 0x18:RCRB(*earb,val,LoadRb,SaveRb);break; \
case 0x20:/* SHL and SAL are the same */ \
case 0x30:SHLB(*earb,val,LoadRb,SaveRb);break; \
case 0x28:SHRB(*earb,val,LoadRb,SaveRb);break; \
case 0x38:SARB(*earb,val,LoadRb,SaveRb);break; \
} \
} else { \
GetEAa; \
Bit8u val=blah & 0x1f; \
switch (rm & 0x38) { \
case 0x00:ROLB(eaa,val,LoadMb,SaveMb);break; \
case 0x08:RORB(eaa,val,LoadMb,SaveMb);break; \
case 0x10:RCLB(eaa,val,LoadMb,SaveMb);break; \
case 0x18:RCRB(eaa,val,LoadMb,SaveMb);break; \
case 0x20:/* SHL and SAL are the same */ \
case 0x30:SHLB(eaa,val,LoadMb,SaveMb);break; \
case 0x28:SHRB(eaa,val,LoadMb,SaveMb);break; \
case 0x38:SARB(eaa,val,LoadMb,SaveMb);break; \
} \
} \
}
#define GRP2W(blah) \
{ \
GetRM; \
if (rm >= 0xc0) { \
GetEArw; \
Bit8u val=blah & 0x1f; \
switch (rm&0x38) { \
case 0x00:ROLW(*earw,val,LoadRw,SaveRw);break; \
case 0x08:RORW(*earw,val,LoadRw,SaveRw);break; \
case 0x10:RCLW(*earw,val,LoadRw,SaveRw);break; \
case 0x18:RCRW(*earw,val,LoadRw,SaveRw);break; \
case 0x20:/* SHL and SAL are the same */ \
case 0x30:SHLW(*earw,val,LoadRw,SaveRw);break; \
case 0x28:SHRW(*earw,val,LoadRw,SaveRw);break; \
case 0x38:SARW(*earw,val,LoadRw,SaveRw);break; \
} \
} else { \
GetEAa; \
Bit8u val=blah & 0x1f; \
switch (rm & 0x38) { \
case 0x00:ROLW(eaa,val,LoadMw,SaveMw);break; \
case 0x08:RORW(eaa,val,LoadMw,SaveMw);break; \
case 0x10:RCLW(eaa,val,LoadMw,SaveMw);break; \
case 0x18:RCRW(eaa,val,LoadMw,SaveMw);break; \
case 0x20:/* SHL and SAL are the same */ \
case 0x30:SHLW(eaa,val,LoadMw,SaveMw);break; \
case 0x28:SHRW(eaa,val,LoadMw,SaveMw);break; \
case 0x38:SARW(eaa,val,LoadMw,SaveMw);break; \
} \
} \
}
#define GRP2D(blah) \
{ \
GetRM; \
if (rm >= 0xc0) { \
GetEArd; \
Bit8u val=blah & 0x1f; \
switch (rm&0x38) { \
case 0x00:ROLD(*eard,val,LoadRd,SaveRd);break; \
case 0x08:RORD(*eard,val,LoadRd,SaveRd);break; \
case 0x10:RCLD(*eard,val,LoadRd,SaveRd);break; \
case 0x18:RCRD(*eard,val,LoadRd,SaveRd);break; \
case 0x20:/* SHL and SAL are the same */ \
case 0x30:SHLD(*eard,val,LoadRd,SaveRd);break; \
case 0x28:SHRD(*eard,val,LoadRd,SaveRd);break; \
case 0x38:SARD(*eard,val,LoadRd,SaveRd);break; \
} \
} else { \
GetEAa; \
Bit8u val=blah & 0x1f; \
switch (rm & 0x38) { \
case 0x00:ROLD(eaa,val,LoadMd,SaveMd);break; \
case 0x08:RORD(eaa,val,LoadMd,SaveMd);break; \
case 0x10:RCLD(eaa,val,LoadMd,SaveMd);break; \
case 0x18:RCRD(eaa,val,LoadMd,SaveMd);break; \
case 0x20:/* SHL and SAL are the same */ \
case 0x30:SHLD(eaa,val,LoadMd,SaveMd);break; \
case 0x28:SHRD(eaa,val,LoadMd,SaveMd);break; \
case 0x38:SARD(eaa,val,LoadMd,SaveMd);break; \
} \
} \
}
/* let's hope bochs has it correct with the higher than 16 shifts */
#define DSHLW(op1,op2,op3,load,save) \
flags.var1.d=(load(op1)<<16)|op2;flags.var2.b=op3; \
Bit32u tempd=flags.var1.d << flags.var2.b; \
if (flags.var2.b>16) tempd |= (op2 << (flags.var2.b - 16)); \
flags.result.w=(Bit16u)(tempd >> 16); \
save(op1,flags.result.w); \
flags.type=t_DSHLw;
#define DSHLD(op1,op2,op3,load,save) \
flags.var1.d=load(op1);flags.var2.b=op3; \
flags.result.d=(flags.var1.d << flags.var2.b) | (op2 >> (32-flags.var2.b)); \
save(op1,flags.result.d); \
flags.type=t_DSHLd;
#define DSHRW(op1,op2,op3,load,save) \
flags.var1.d=(load(op1)<<16)|op2;flags.var2.b=op3; \
Bit32u tempd=flags.var1.d >> flags.var2.b; \
if (flags.var2.b>16) tempd |= (op2 << (32-flags.var2.b )); \
flags.result.w=(Bit16u)(tempd); \
save(op1,flags.result.w); \
flags.type=t_DSHRw;
#define DSHRD(op1,op2,op3,load,save) \
flags.var1.d=load(op1);flags.var2.b=op3; \
flags.result.d=(flags.var1.d >> flags.var2.b) | (op2 << (32-flags.var2.b)); \
save(op1,flags.result.d); \
flags.type=t_DSHRd;

1488
src/cpu/core_16/main.h Normal file

File diff suppressed because it is too large Load diff

469
src/cpu/core_16/prefix_66.h Normal file
View file

@ -0,0 +1,469 @@
/*
* 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.
*/
restart_66:
switch(Fetchb()) {
case 0x01: /* ADD Ed,Gd */
RMEdGd(ADDD);break;
case 0x03: /* ADD Gd,Ed */
RMGdEd(ADDD);break;
case 0x05: /* ADD EAX,Id */
EAXId(ADDD);break;
case 0x09: /* OR Ew,Gw */
RMEdGd(ORD);break;
case 0x0b: /* OR Gd,Ed */
RMGdEd(ORD);break;
case 0x0d: /* OR EAX,Id */
EAXId(ORD);break;
case 0x0f: /* 2 Byte opcodes */
#include "prefix_66_of.h"
break;
case 0x11: /* ADC Ed,Gd */
RMEdGd(ADCD);break;
case 0x13: /* ADC Gd,Ed */
RMGdEd(ADCD);break;
case 0x15: /* ADC EAX,Id */
EAXId(ADCD);break;
case 0x19: /* SBB Ed,Gd */
RMEdGd(SBBD);break;
case 0x1b: /* SBB Gd,Ed */
RMGdEd(SBBD);break;
case 0x1d: /* SBB EAX,Id */
EAXId(SBBD);break;
case 0x21: /* AND Ed,Gd */
RMEdGd(ANDD);break;
case 0x23: /* AND Gd,Ed */
RMGdEd(ANDD);break;
case 0x25: /* AND EAX,Id */
EAXId(ANDD);break;
case 0x29: /* SUB Ed,Gd */
RMEdGd(SUBD);break;
case 0x2b: /* SUB Gd,Ed */
RMGdEd(SUBD);break;
case 0x2d: /* SUB EAX,Id */
EAXId(SUBD);break;
case 0x31: /* XOR Ed,Gd */
RMEdGd(XORD);break;
case 0x33: /* XOR Gd,Ed */
RMGdEd(XORD);break;
case 0x35: /* XOR EAX,Id */
EAXId(XORD);break;
case 0x39: /* CMP Ed,Gd */
RMEdGd(CMPD);break;
case 0x3b: /* CMP Gd,Ed */
RMGdEd(CMPD);break;
case 0x3d: /* CMP EAX,Id */
EAXId(CMPD);break;
case 0x26: /* SEG ES: */
SegPrefix_66(es);break;
case 0x2e: /* SEG CS: */
SegPrefix_66(cs);break;
case 0x36: /* SEG SS: */
SegPrefix_66(ss);break;
case 0x3e: /* SEG DS: */
SegPrefix_66(ds);break;
case 0x40: /* INC EAX */
INCD(reg_eax,LoadRd,SaveRd);break;
case 0x41: /* INC ECX */
INCD(reg_ecx,LoadRd,SaveRd);break;
case 0x42: /* INC EDX */
INCD(reg_edx,LoadRd,SaveRd);break;
case 0x43: /* INC EBX */
INCD(reg_ebx,LoadRd,SaveRd);break;
case 0x44: /* INC ESP */
INCD(reg_esp,LoadRd,SaveRd);break;
case 0x45: /* INC EBP */
INCD(reg_ebp,LoadRd,SaveRd);break;
case 0x46: /* INC ESI */
INCD(reg_esi,LoadRd,SaveRd);break;
case 0x47: /* INC EDI */
INCD(reg_edi,LoadRd,SaveRd);break;
case 0x48: /* DEC EAX */
DECD(reg_eax,LoadRd,SaveRd);break;
case 0x49: /* DEC ECX */
DECD(reg_ecx,LoadRd,SaveRd);break;
case 0x4a: /* DEC EDX */
DECD(reg_edx,LoadRd,SaveRd);break;
case 0x4b: /* DEC EBX */
DECD(reg_ebx,LoadRd,SaveRd);break;
case 0x4c: /* DEC ESP */
DECD(reg_esp,LoadRd,SaveRd);break;
case 0x4d: /* DEC EBP */
DECD(reg_ebp,LoadRd,SaveRd);break;
case 0x4e: /* DEC ESI */
DECD(reg_esi,LoadRd,SaveRd);break;
case 0x4f: /* DEC EDI */
DECD(reg_edi,LoadRd,SaveRd);break;
case 0x50: /* PUSH EAX */
Push_32(reg_eax);break;
case 0x51: /* PUSH ECX */
Push_32(reg_ecx);break;
case 0x52: /* PUSH EDX */
Push_32(reg_edx);break;
case 0x53: /* PUSH EBX */
Push_32(reg_ebx);break;
case 0x54: /* PUSH ESP */
Push_32(reg_esp);break;
case 0x55: /* PUSH EBP */
Push_32(reg_ebp);break;
case 0x56: /* PUSH ESI */
Push_32(reg_esi);break;
case 0x57: /* PUSH EDI */
Push_32(reg_edi);break;
case 0x58: /* POP EAX */
reg_eax=Pop_32();break;
case 0x59: /* POP ECX */
reg_ecx=Pop_32();break;
case 0x5a: /* POP EDX */
reg_edx=Pop_32();break;
case 0x5b: /* POP EBX */
reg_ebx=Pop_32();break;
case 0x5c: /* POP ESP */
reg_esp=Pop_32();break;
case 0x5d: /* POP EBP */
reg_ebp=Pop_32();break;
case 0x5e: /* POP ESI */
reg_esi=Pop_32();break;
case 0x5f: /* POP EDI */
reg_edi=Pop_32();break;
case 0x60: /* PUSHAD */
Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx);
Push_32(reg_esp);Push_32(reg_ebp);Push_32(reg_esi);Push_32(reg_edi);
break;
case 0x61: /* POPAD */
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 0x69: /* IMUL Gd,Ed,Id */
{
GetRMrd;
Bit64s res;
if (rm >= 0xc0 ) {GetEArd;res=(Bit64s)(*eards) * (Bit64s)Fetchds();}
else {GetEAa;res=(Bit64s)LoadMds(eaa) * (Bit64s)Fetchds();}
*rmrd=(Bit32s)(res);
flags.type=t_MUL;
if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {flags.cf=false;flags.of=false;}
else {flags.cf=true;flags.of=true;}
break;
};
case 0x6a: /* PUSH Ib */
Push_32(Fetchbs());break;
case 0x81: /* Grpl Ed,Id */
{
GetRM;
if (rm>= 0xc0) {
GetEArd;Bit32u id=Fetchd();
switch (rm & 0x38) {
case 0x00:ADDD(*eard,id,LoadRd,SaveRd);break;
case 0x08: ORD(*eard,id,LoadRd,SaveRd);break;
case 0x10:ADCD(*eard,id,LoadRd,SaveRd);break;
case 0x18:SBBD(*eard,id,LoadRd,SaveRd);break;
case 0x20:ANDD(*eard,id,LoadRd,SaveRd);break;
case 0x28:SUBD(*eard,id,LoadRd,SaveRd);break;
case 0x30:XORD(*eard,id,LoadRd,SaveRd);break;
case 0x38:CMPD(*eard,id,LoadRd,SaveRd);break;
}
} else {
GetEAa;Bit32u id=Fetchb();
switch (rm & 0x38) {
case 0x00:ADDD(eaa,id,LoadMd,SaveMd);break;
case 0x08: ORD(eaa,id,LoadMd,SaveMd);break;
case 0x10:ADCD(eaa,id,LoadMd,SaveMd);break;
case 0x18:SBBD(eaa,id,LoadMd,SaveMd);break;
case 0x20:ANDD(eaa,id,LoadMd,SaveMd);break;
case 0x28:SUBD(eaa,id,LoadMd,SaveMd);break;
case 0x30:XORD(eaa,id,LoadMd,SaveMd);break;
case 0x38:CMPD(eaa,id,LoadMd,SaveMd);break;
}
}
}
break;
case 0x83: /* Grpl Ed,Ix */
{
GetRM;
if (rm>= 0xc0) {
GetEArd;Bit32u id=(Bit32s)Fetchbs();
switch (rm & 0x38) {
case 0x00:ADDD(*eard,id,LoadRd,SaveRd);break;
case 0x08: ORD(*eard,id,LoadRd,SaveRd);break;
case 0x10:ADCD(*eard,id,LoadRd,SaveRd);break;
case 0x18:SBBD(*eard,id,LoadRd,SaveRd);break;
case 0x20:ANDD(*eard,id,LoadRd,SaveRd);break;
case 0x28:SUBD(*eard,id,LoadRd,SaveRd);break;
case 0x30:XORD(*eard,id,LoadRd,SaveRd);break;
case 0x38:CMPD(*eard,id,LoadRd,SaveRd);break;
}
} else {
GetEAa;Bit32u id=(Bit32s)Fetchbs();
switch (rm & 0x38) {
case 0x00:ADDD(eaa,id,LoadMd,SaveMd);break;
case 0x08: ORD(eaa,id,LoadMd,SaveMd);break;
case 0x10:ADCD(eaa,id,LoadMd,SaveMd);break;
case 0x18:SBBD(eaa,id,LoadMd,SaveMd);break;
case 0x20:ANDD(eaa,id,LoadMd,SaveMd);break;
case 0x28:SUBD(eaa,id,LoadMd,SaveMd);break;
case 0x30:XORD(eaa,id,LoadMd,SaveMd);break;
case 0x38:CMPD(eaa,id,LoadMd,SaveMd);break;
}
}
}
break;
case 0x8f: /* POP Ed */
{
GetRM;
if (rm >= 0xc0 ) {GetEArd;*eard=Pop_32();}
else {GetEAa;SaveMd(eaa,Pop_32());}
break;
}
case 0x89: /* MOV Ed,Gd */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArd;*eard=*rmrd;}
else {GetEAa;SaveMd(eaa,*rmrd);}
break;
}
case 0x99: /* CDQ */
if (reg_eax & 0x80000000) reg_edx=0xffffffff;
else reg_edx=0;
break;
case 0x8b: /* MOV Gd,Ed */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;}
else {GetEAa;*rmrd=LoadMd(eaa);}
break;
}
case 0x8c:
LOG_WARN("CPU:66:8c looped back");
break;
case 0x9c: /* PUSHFD */
{
Bit32u pflags=
(get_CF() << 0) | (get_PF() << 2) | (get_AF() << 4) |
(get_ZF() << 6) | (get_SF() << 7) | (flags.tf << 8) |
(flags.intf << 9) |(flags.df << 10) | (get_OF() << 11) |
(flags.io << 12) | (flags.nt <<14);
Push_32(pflags);
break;
}
case 0x9d: /* POPFD */
{
Save_Flagsw((Bit16u)(Pop_32()&0xffff));
break;
}
case 0xa1: /* MOV EAX,Ow */
if (segprefix_on) {
reg_eax=LoadMd(segprefix_base+Fetchw());
SegPrefixReset;
} else {
reg_eax=LoadMd(SegBase(ds)+Fetchw());
}
break;
case 0xa3: /* MOV Ow,EAX */
if (segprefix_on) {
SaveMd((segprefix_base+Fetchw()),reg_eax);
SegPrefixReset;
} else {
SaveMd((SegBase(ds)+Fetchw()),reg_eax);
}
break;
case 0xa5: /* MOVSD */
{
stringSI;stringDI;SaveMd(to,LoadMd(from));
if (flags.df) { reg_si-=4;reg_di-=4; }
else { reg_si+=4;reg_di+=4;}
}
break;
case 0xab: /* STOSD */
{
stringDI;
SaveMd(to,reg_eax);
if (flags.df) { reg_di-=4; }
else {reg_di+=4;}
break;
}
case 0xad: /* LODSD */
{
stringSI;
reg_eax=LoadMd(from);
if (flags.df) { reg_si-=4;}
else {reg_si+=4;}
break;
}
case 0xaf: /* SCASD */
{
stringDI;
CMPD(reg_eax,LoadMd(to),LoadRd,0);
if (flags.df) { reg_di-=4; }
else {reg_di+=4;}
break;
}
case 0xb8: /* MOV EAX,Id */
reg_eax=Fetchd();break;
case 0xb9: /* MOV ECX,Id */
reg_ecx=Fetchd();break;
case 0xba: /* MOV EDX,Iw */
reg_edx=Fetchd();break;
case 0xbb: /* MOV EBX,Id */
reg_ebx=Fetchd();break;
case 0xbc: /* MOV ESP,Id */
reg_esp=Fetchd();break;
case 0xbd: /* MOV EBP.Id */
reg_ebp=Fetchd();break;
case 0xbe: /* MOV ESI,Id */
reg_esi=Fetchd();break;
case 0xbf: /* MOV EDI,Id */
reg_edi=Fetchd();break;
case 0xc1: /* GRP2 Ed,Ib */
GRP2D(Fetchb());break;
case 0xc7: /* MOV Ed,Id */
{
GetRM;
if (rm>0xc0) {GetEArd;*eard=Fetchd();}
else {GetEAa;SaveMd(eaa,Fetchd());}
break;
}
case 0xd1: /* GRP2 Ed,1 */
GRP2D(1);break;
case 0xd3: /* GRP2 Ed,CL */
GRP2D(reg_cl);break;
case 0xf7: /* GRP3 Ed(,Id) */
{
union { Bit64u u;Bit64s s;} temp;
union {Bit64u u;Bit64s s;} quotient;
GetRM;
switch (rm & 0x38) {
case 0x00: /* TEST Ed,Id */
case 0x08: /* TEST Ed,Id Undocumented*/
{
if (rm >= 0xc0 ) {GetEArd;TESTD(*eard,Fetchd(),LoadRd,SaveRd);}
else {GetEAa;TESTD(eaa,Fetchd(),LoadMd,SaveMd);}
break;
}
case 0x10: /* NOT Ed */
{
if (rm >= 0xc0 ) {GetEArd;*eard=~*eard;}
else {GetEAa;SaveMd(eaa,~LoadMd(eaa));}
break;
}
case 0x18: /* NEG Ed */
{
flags.type=t_NEGd;
if (rm >= 0xc0 ) {
GetEArd;flags.var1.d=*eard;flags.result.d=0-flags.var1.d;
*eard=flags.result.d;
} else {
GetEAa;flags.var1.d=LoadMd(eaa);flags.result.d=0-flags.var1.d;
SaveMd(eaa,flags.result.d);
}
break;
}
case 0x20: /* MUL EAX,Ed */
{
flags.type=t_MUL;
if (rm >= 0xc0 ) {GetEArd;temp.u=(Bit64s)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);
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 ( (reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) {
flags.cf=flags.of=false;
} else if ( (reg_edx==0x00000000) && (reg_eax<0x80000000) ) {
flags.cf=flags.of=false;
} else {
flags.cf=flags.of=true;
}
break;
}
case 0x30: /* DIV Ed */
{
// flags.type=t_DIV;
Bit32u val;
if (rm >= 0xc0 ) {GetEArd;val=*eard;}
else {GetEAa;val=LoadMd(eaa);}
if (val==0) {Interrupt(0);break;}
temp.u=(((Bit64u)reg_edx)<<32)|reg_eax;
quotient.u=temp.u/val;
reg_edx=(Bit32u)(temp.u % val);
reg_eax=(Bit32u)(quotient.u & 0xffffffff);
if (quotient.u>0xffffffff)
Interrupt(0);
break;
}
case 0x38: /* IDIV Ed */
{
// flags.type=t_DIV;
Bit32s val;
if (rm >= 0xc0 ) {GetEArd;val=*eards;}
else {GetEAa;val=LoadMds(eaa);}
if (val==0) {Interrupt(0);break;}
temp.s=(((Bit64u)reg_edx)<<32)|reg_eax;
quotient.s=(temp.s/val);
reg_edx=(Bit32s)(temp.s % val);
reg_eax=(Bit32s)(quotient.s);
if (quotient.s!=(Bit32s)reg_eax)
Interrupt(0);
break;
}
}
break;
}
case 0xff: /* Group 5 */
{
GetRM;
switch (rm & 0x38) {
case 0x00: /* INC Ew */
flags.cf=get_CF();flags.type=t_INCd;
if (rm >= 0xc0 ) {GetEArd;flags.result.d=*eard+=1;}
else {GetEAa;flags.result.d=LoadMd(eaa)+1;SaveMd(eaa,flags.result.d);}
break;
case 0x08: /* DEC Ew */
flags.cf=get_CF();flags.type=t_DECd;
if (rm >= 0xc0 ) {GetEArd;flags.result.d=*eard-=1;}
else {GetEAa;flags.result.d=LoadMd(eaa)-1;SaveMd(eaa,flags.result.d);}
break;
case 0x30: /* Push Ed */
if (rm >= 0xc0 ) {GetEArd;Push_32(*eard);}
else {GetEAa;Push_32(LoadMd(eaa));}
break;
default:
E_Exit("CPU:66:GRP5:Illegal call %2X",rm & 0x38);
break;
}
break;
}
default:
NOTDONE66;
}

View file

@ -0,0 +1,124 @@
/*
* 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.
*/
switch (Fetchb()) {
case 0xa4: /* SHLD Ed,Gd,Ib */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArd;DSHLD(*eard,*rmrd,Fetchb(),LoadRd,SaveRd);}
else {GetEAa;DSHLD(eaa,*rmrd,Fetchb(),LoadMd,SaveMd);}
break;
}
case 0xac: /* SHRD Ed,Gd,Ib */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArd;DSHRD(*eard,*rmrd,Fetchb(),LoadRd,SaveRd);}
else {GetEAa;DSHRD(eaa,*rmrd,Fetchb(),LoadMd,SaveMd);}
break;
}
case 0xb6: /* MOVZX Gd,Eb */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArb;*rmrd=*earb;}
else {GetEAa;*rmrd=LoadMb(eaa);}
break;
}
case 0xaf: /* IMUL Gd,Ed */
{
GetRMrd;
Bit64s res;
if (rm >= 0xc0 ) {GetEArd;res=(Bit64s)(*rmrd) * (Bit64s)(*eards);}
else {GetEAa;res=(Bit64s)(*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;}
else {flags.cf=true;flags.of=true;}
break;
};
case 0xb7: /* MOVXZ Gd,Ew */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArw;*rmrd=*earw;}
else {GetEAa;*rmrd=LoadMw(eaa);}
break;
}
case 0xba: /* GRP8 Ed,Ib */
{
GetRM;
if (rm >= 0xc0 ) {
GetEArd;
Bit32u mask=1 << (Fetchb() & 31);
flags.cf=(*eard & mask)>0;
switch (rm & 0x38) {
case 0x20: /* BT */
break;
case 0x28: /* BTS */
*eard|=mask;
break;
case 0x30: /* BTR */
*eard&=~mask;
break;
case 0x38: /* BTC */
if (flags.cf) *eard&=~mask;
else *eard|=mask;
break;
}
} else {
GetEAa;Bit32u old=LoadMd(eaa);
Bit32u mask=1 << (Fetchb() & 31);
flags.cf=(old & mask)>0;
switch (rm & 0x38) {
case 0x20: /* BT */
break;
case 0x28: /* BTS */
SaveMd(eaa,old|mask);
break;
case 0x30: /* BTR */
SaveMd(eaa,old & ~mask);
break;
case 0x38: /* BTC */
if (flags.cf) old&=~mask;
else old|=mask;
SaveMd(eaa,old);
break;
}
}
if (flags.type!=t_CF) flags.prev_type=flags.type;
flags.type=t_CF;
break;
}
case 0xbe: /* MOVSX Gd,Eb */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArb;*rmrd=*earbs;}
else {GetEAa;*rmrd=LoadMbs(eaa);}
break;
}
case 0xbf: /* MOVSX Gd,Ew */
{
GetRMrd;
if (rm >= 0xc0 ) {GetEArw;*rmrd=*earws;}
else {GetEAa;*rmrd=LoadMws(eaa);}
break;
}
default:
SUBIP(1);
E_Exit("CPU:Opcode 66:0F:%2X Unhandled",Fetchb());
}

188
src/cpu/core_16/prefix_of.h Normal file
View file

@ -0,0 +1,188 @@
/*
* 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.
*/
switch(Fetchb()) {
case 0x01: /* GRP 7 */
{
GetRM;
switch (rm & 0x38) {
case 0x20: /* SMSW */
/* Let's seriously fake this call */
if (rm>0xc0) {GetEArw;*earw=0;}
else {GetEAa;SaveMw(eaa,0);}
break;
default:
E_Exit("CPU:GRP7:Illegal call %2X",rm);
}
}
break;
case 0x80: /* JO */
JumpSIw(get_OF());break;
case 0x81: /* JNO */
JumpSIw(!get_OF());break;
case 0x82: /* JB */
JumpSIw(get_CF());break;
case 0x83: /* JNB */
JumpSIw(!get_CF());break;
case 0x84: /* JZ */
JumpSIw(get_ZF());break;
case 0x85: /* JNZ */
JumpSIw(!get_ZF()); break;
case 0x86: /* JBE */
JumpSIw(get_CF() || get_ZF());break;
case 0x87: /* JNBE */
JumpSIw(!get_CF() && !get_ZF());break;
case 0x88: /* JS */
JumpSIw(get_SF());break;
case 0x89: /* JNS */
JumpSIw(!get_SF());break;
case 0x8a: /* JP */
JumpSIw(get_PF());break;
case 0x8b: /* JNP */
JumpSIw(!get_PF());break;
case 0x8c: /* JL */
JumpSIw(get_SF() != get_OF());break;
case 0x8d: /* JNL */
JumpSIw(get_SF() == get_OF());break;
case 0x8e: /* JLE */
JumpSIw(get_ZF() || (get_SF() != get_OF()));break;
case 0x8f: /* JNLE */
JumpSIw((get_SF() == get_OF()) && !get_ZF());break;
case 0xa0: /* PUSH FS */
Push_16(Segs[fs].value);break;
case 0xa1: /* POP FS */
SetSegment_16(fs,Pop_16());break;
case 0xa4: /* SHLD Ew,Gw,Ib */
{
GetRMrw;
if (rm >= 0xc0 ) {GetEArw;DSHLW(*earw,*rmrw,Fetchb(),LoadRw,SaveRw);}
else {GetEAa;DSHLW(eaa,*rmrw,Fetchb(),LoadMw,SaveMw);}
break;
}
case 0xa5: /* SHLD Ew,Gw,CL */
{
GetRMrw;
if (rm >= 0xc0 ) {GetEArw;DSHLW(*earw,*rmrw,reg_cl,LoadRw,SaveRw);}
else {GetEAa;DSHLW(eaa,*rmrw,reg_cl,LoadMw,SaveMw);}
break;
}
case 0xa8: /* PUSH GS */
Push_16(Segs[gs].value);break;
case 0xa9: /* POP GS */
SetSegment_16(gs,Pop_16());break;
case 0xac: /* SHRD Ew,Gw,Ib */
{
GetRMrw;
if (rm >= 0xc0 ) {GetEArw;DSHRW(*earw,*rmrw,Fetchb(),LoadRw,SaveRw);}
else {GetEAa;DSHRW(eaa,*rmrw,Fetchb(),LoadMw,SaveMw);}
break;
}
case 0xad: /* SHRD Ew,Gw,CL */
{
GetRMrw;
if (rm >= 0xc0 ) {GetEArw;DSHRW(*earw,*rmrw,reg_cl,LoadRw,SaveRw);}
else {GetEAa;DSHRW(eaa,*rmrw,reg_cl,LoadMw,SaveMw);}
break;
}
case 0xaf: /* IMUL Gw,Ew */
{
GetRMrw;
Bit32s res;
if (rm >= 0xc0 ) {GetEArw;res=(Bit32s)(*rmrw) * (Bit32s)(*earws);}
else {GetEAa;res=(Bit32s)(*rmrw) *(Bit32s)LoadMws(eaa);}
*rmrw=res & 0xFFFF;
flags.type=t_MUL;
if ((res> -32768) && (res<32767)) {flags.cf=false;flags.of=false;}
else {flags.cf=true;flags.of=true;}
break;
}
case 0xb4: /* LFS */
{
GetRMrw;GetEAa;
*rmrw=LoadMw(eaa);SetSegment_16(fs,LoadMw(eaa+2));
break;
}
case 0xb5: /* LGS */
{
GetRMrw;GetEAa;
*rmrw=LoadMw(eaa);SetSegment_16(gs,LoadMw(eaa+2));
break;
}
case 0xb6: /* MOVZX Gw,Eb */
{
GetRMrw;
if (rm >= 0xc0 ) {GetEArb;*rmrw=*earb;}
else {GetEAa;*rmrw=LoadMb(eaa);}
break;
}
case 0xba: /* GRP8 Ew,Ib */
{
GetRM;
if (rm >= 0xc0 ) {
GetEArw;
Bit16u mask=1 << (Fetchb() & 15);
flags.cf=(*earw & mask)>0;
switch (rm & 0x38) {
case 0x20: /* BT */
break;
case 0x28: /* BTS */
*earw|=mask;
break;
case 0x30: /* BTR */
*earw&=~mask;
break;
case 0x38: /* BTC */
if (flags.cf) *earw&=~mask;
else *earw|=mask;
break;
}
} else {
GetEAa;Bit16u old=LoadMw(eaa);
Bit16u mask=1 << (Fetchb() & 15);
flags.cf=(old & mask)>0;
switch (rm & 0x38) {
case 0x20: /* BT */
break;
case 0x28: /* BTS */
SaveMw(eaa,old|mask);
break;
case 0x30: /* BTR */
SaveMw(eaa,old & ~mask);
break;
case 0x38: /* BTC */
if (flags.cf) old&=~mask;
else old|=mask;
SaveMw(eaa,old);
break;
}
}
if (flags.type!=t_CF) flags.prev_type=flags.type;
flags.type=t_CF;
break;
}
case 0xbe: /* MOVSX Gw,Eb */
{
GetRMrw;
if (rm >= 0xc0 ) {GetEArb;*rmrw=*earbs;}
else {GetEAa;*rmrw=LoadMbs(eaa);}
break;
}
default:
SUBIP(1);
E_Exit("CPU:Opcode 0F:%2X Unhandled",Fetchb());
}

20
src/cpu/core_16/start.h Normal file
View file

@ -0,0 +1,20 @@
/*
* 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.
*/
/* Setup the CS:IP and SS:SP Pointers */
LOADIP;

19
src/cpu/core_16/stop.h Normal file
View file

@ -0,0 +1,19 @@
/*
* 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.
*/
SAVEIP;

191
src/cpu/core_16/support.h Normal file
View file

@ -0,0 +1,191 @@
/*
* 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.
*/
EAPoint IPPoint;
#define SUBIP(a) IPPoint-=a
#define SETIP(a) IPPoint=SegBase(cs)+a
#define GETIP (Bit16u)(IPPoint-SegBase(cs))
#define SAVEIP reg_ip=GETIP
#define LOADIP IPPoint=SegBase(cs)+reg_ip
/*
#define ADDIP(a) { \
Bit16u add_ip=(Bit16u)(IPPoint-SegBase(cs)); \
add_ip+=a; \
IPPoint=SegBase(cs)+add_ip; \
}
*/
static INLINE void ADDIP(Bit16u add) {
// Bit16u oldip=(IPPoint-SegBase(cs));
// oldip+=add;
// IPPoint=SegBase(cs)+oldip;
IPPoint=SegBase(cs)+((Bit16u)(((Bit16u)(IPPoint-SegBase(cs)))+(Bit16u)add));
}
static INLINE void ADDIPFAST(Bit16s blah) {
IPPoint+=blah;
}
#define ERRORRETURN(a) { error_ret=a;goto errorreturn; }
static INLINE Bit8u Fetchb() {
Bit8u temp=LoadMb(IPPoint);
IPPoint+=1;
return temp;
}
static INLINE Bit16u Fetchw() {
Bit16u temp=LoadMw(IPPoint);
IPPoint+=2;
return temp;
}
static INLINE Bit32u Fetchd() {
Bit32u temp=LoadMd(IPPoint);
IPPoint+=4;
return temp;
}
static INLINE Bit8s Fetchbs() {
return Fetchb();
}
static INLINE Bit16s Fetchws() {
return Fetchw();
}
static INLINE Bit32s Fetchds() {
return Fetchd();
}
static INLINE void Push_16(Bit16u blah) {
reg_sp-=2;
SaveMw(SegBase(ss)+reg_sp,blah);
};
static INLINE void Push_32(Bit32u blah) {
reg_sp-=4;
SaveMd(SegBase(ss)+reg_sp,blah);
};
static INLINE Bit16u Pop_16() {
Bit16u temp=LoadMw(SegBase(ss)+reg_sp);
reg_sp+=2;
return temp;
};
static INLINE Bit32u Pop_32() {
Bit32u temp=LoadMd(SegBase(ss)+reg_sp);
reg_sp+=4;
return temp;
};
#define stringDI \
EAPoint to; \
to=SegBase(es)+reg_di
#define stringSI \
EAPoint from; \
if (segprefix_on) { \
from=(segprefix_base+reg_si); \
SegPrefixReset; \
} else { \
from=SegBase(ds)+reg_si; \
}
#include "helpers.h"
#include "table_ea.h"
#include "../modrm.h"
#include "instructions.h"
static INLINE void Rep_66(Bit16s direct,EAPoint from,EAPoint to) {
bool again;
do {
again=false;
Bit8u repcode=Fetchb();
switch (repcode) {
case 0x26: /* ES Prefix */
again=true;
from=SegBase(es);
break;
case 0x2e: /* CS Prefix */
again=true;
from=SegBase(cs);
break;
case 0x36: /* SS Prefix */
again=true;
from=SegBase(ss);
break;
case 0x3e: /* DS Prefix */
again=true;
from=SegBase(ds);
break;
case 0xa5: /* REP MOVSD */
for (;reg_cx>0;reg_cx--) {
SaveMd(to+reg_di,LoadMd(from+reg_si));
reg_di+=direct*4;
reg_si+=direct*4;
}
break;
case 0xab: /* REP STOSW */
for (;reg_cx>0;reg_cx--) {
SaveMd(to+reg_di,reg_eax);
reg_di+=direct*4;
}
break;
default:
E_Exit("CPU:Opcode 66:Illegal REP prefix %2X",repcode);
}
} while (again);
}
//flags.io and nt shouldn't be compiled for 386
#define Save_Flagsw(FLAGW) \
{ \
flags.type=t_UNKNOWN; \
flags.cf =(FLAGW & 0x001)>0;flags.pf =(FLAGW & 0x004)>0; \
flags.af =(FLAGW & 0x010)>0;flags.zf =(FLAGW & 0x040)>0; \
flags.sf =(FLAGW & 0x080)>0;flags.tf =(FLAGW & 0x100)>0; \
flags.intf =(FLAGW & 0x200)>0; \
flags.df =(FLAGW & 0x400)>0;flags.of =(FLAGW & 0x800)>0; \
flags.io =(FLAGW >> 12) & 0x03; \
flags.nt =(FLAGW & 0x4000)>0; \
if (flags.intf && PIC_IRQCheck) { \
SAVEIP; \
PIC_runIRQs(); \
LOADIP; \
} \
if (flags.tf) E_Exit("CPU:Trap Flag not supported"); \
}
// if (flags.tf) { \
// cpudecoder=CPU_Real_16_Slow_Decode_Special; \
// return CBRET_NONE; \
// } \

283
src/cpu/core_16/table_ea.h Normal file
View file

@ -0,0 +1,283 @@
/*
* 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.
*/
/* Some variables for EA Loolkup */
typedef EAPoint (*GetEATable[256])(void);
static GetEATable * lookupEATable;
static EAPoint segprefix_base;
static bool segprefix_on=false;
#define SegPrefix(blah) \
segprefix_base=SegBase(blah); \
segprefix_on=true; \
lookupEATable=&GetEA_16_s; \
goto restart; \
#define SegPrefix_66(blah) \
segprefix_base=SegBase(blah); \
segprefix_on=true; \
lookupEATable=&GetEA_16_s; \
goto restart_66; \
#define SegPrefixReset \
segprefix_on=false;lookupEATable=&GetEA_16_n;
/* The MOD/RM Decoder for EA for this decoder's addressing modes */
static EAPoint EA_16_00_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_si); }
static EAPoint EA_16_01_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_di); }
static EAPoint EA_16_02_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+(Bit16s)reg_si); }
static EAPoint EA_16_03_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+(Bit16s)reg_di); }
static EAPoint EA_16_04_n(void) { return SegBase(ds)+(Bit16u)(reg_si); }
static EAPoint EA_16_05_n(void) { return SegBase(ds)+(Bit16u)(reg_di); }
static EAPoint EA_16_06_n(void) { return SegBase(ds)+(Bit16u)(Fetchw());}
static EAPoint EA_16_07_n(void) { return SegBase(ds)+(Bit16u)(reg_bx); }
static EAPoint EA_16_40_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_si+Fetchbs()); }
static EAPoint EA_16_41_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_di+Fetchbs()); }
static EAPoint EA_16_42_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+(Bit16s)reg_si+Fetchbs()); }
static EAPoint EA_16_43_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+(Bit16s)reg_di+Fetchbs()); }
static EAPoint EA_16_44_n(void) { return SegBase(ds)+(Bit16u)(reg_si+Fetchbs()); }
static EAPoint EA_16_45_n(void) { return SegBase(ds)+(Bit16u)(reg_di+Fetchbs()); }
static EAPoint EA_16_46_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+Fetchbs()); }
static EAPoint EA_16_47_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+Fetchbs()); }
static EAPoint EA_16_80_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_si+Fetchws()); }
static EAPoint EA_16_81_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+(Bit16s)reg_di+Fetchws()); }
static EAPoint EA_16_82_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+(Bit16s)reg_si+Fetchws()); }
static EAPoint EA_16_83_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+(Bit16s)reg_di+Fetchws()); }
static EAPoint EA_16_84_n(void) { return SegBase(ds)+(Bit16u)(reg_si+Fetchws()); }
static EAPoint EA_16_85_n(void) { return SegBase(ds)+(Bit16u)(reg_di+Fetchws()); }
static EAPoint EA_16_86_n(void) { return SegBase(ss)+(Bit16u)(reg_bp+Fetchws()); }
static EAPoint EA_16_87_n(void) { return SegBase(ds)+(Bit16u)(reg_bx+Fetchws()); }
static GetEATable GetEA_16_n={
/* 00 */
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
/* 01 */
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
/* 10 */
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
/* 11 These are illegal so make em 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#define prefixed(val) EAPoint ret=segprefix_base+val;SegPrefixReset;return ret;
static EAPoint EA_16_00_s(void) { prefixed((Bit16u)(reg_bx+(Bit16s)reg_si)) }
static EAPoint EA_16_01_s(void) { prefixed((Bit16u)(reg_bx+(Bit16s)reg_di)) }
static EAPoint EA_16_02_s(void) { prefixed((Bit16u)(reg_bp+(Bit16s)reg_si)) }
static EAPoint EA_16_03_s(void) { prefixed((Bit16u)(reg_bp+(Bit16s)reg_di)) }
static EAPoint EA_16_04_s(void) { prefixed((Bit16u)(reg_si)) }
static EAPoint EA_16_05_s(void) { prefixed((Bit16u)(reg_di)) }
static EAPoint EA_16_06_s(void) { prefixed((Bit16u)(Fetchw())) }
static EAPoint EA_16_07_s(void) { prefixed((Bit16u)(reg_bx)) }
static EAPoint EA_16_40_s(void) { prefixed((Bit16u)(reg_bx+(Bit16s)reg_si+Fetchbs())) }
static EAPoint EA_16_41_s(void) { prefixed((Bit16u)(reg_bx+(Bit16s)reg_di+Fetchbs())) }
static EAPoint EA_16_42_s(void) { prefixed((Bit16u)(reg_bp+(Bit16s)reg_si+Fetchbs())) }
static EAPoint EA_16_43_s(void) { prefixed((Bit16u)(reg_bp+(Bit16s)reg_di+Fetchbs())) }
static EAPoint EA_16_44_s(void) { prefixed((Bit16u)(reg_si+Fetchbs())) }
static EAPoint EA_16_45_s(void) { prefixed((Bit16u)(reg_di+Fetchbs())) }
static EAPoint EA_16_46_s(void) { prefixed((Bit16u)(reg_bp+Fetchbs())) }
static EAPoint EA_16_47_s(void) { prefixed((Bit16u)(reg_bx+Fetchbs())) }
static EAPoint EA_16_80_s(void) { prefixed((Bit16u)(reg_bx+(Bit16s)reg_si+Fetchws())) }
static EAPoint EA_16_81_s(void) { prefixed((Bit16u)(reg_bx+(Bit16s)reg_di+Fetchws())) }
static EAPoint EA_16_82_s(void) { prefixed((Bit16u)(reg_bp+(Bit16s)reg_si+Fetchws())) }
static EAPoint EA_16_83_s(void) { prefixed((Bit16u)(reg_bp+(Bit16s)reg_di+Fetchws())) }
static EAPoint EA_16_84_s(void) { prefixed((Bit16u)(reg_si+Fetchws())) }
static EAPoint EA_16_85_s(void) { prefixed((Bit16u)(reg_di+Fetchws())) }
static EAPoint EA_16_86_s(void) { prefixed((Bit16u)(reg_bp+Fetchws())) }
static EAPoint EA_16_87_s(void) { prefixed((Bit16u)(reg_bx+Fetchws())) }
static GetEATable GetEA_16_s={
/* 00 */
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
EA_16_00_s,EA_16_01_s,EA_16_02_s,EA_16_03_s,EA_16_04_s,EA_16_05_s,EA_16_06_s,EA_16_07_s,
/* 01 */
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
EA_16_40_s,EA_16_41_s,EA_16_42_s,EA_16_43_s,EA_16_44_s,EA_16_45_s,EA_16_46_s,EA_16_47_s,
/* 10 */
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
EA_16_80_s,EA_16_81_s,EA_16_82_s,EA_16_83_s,EA_16_84_s,EA_16_85_s,EA_16_86_s,EA_16_87_s,
/* 11 These are illegal so make em 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
INLINE EAPoint Sib(Bitu mode) {
Bit8u sib=Fetchb();
EAPoint base;
switch (sib&7) {
case 0: /* EAX Base */
base=SegBase(ds)+reg_eax;break;
case 1: /* ECX Base */
base=SegBase(ds)+reg_ecx;break;
case 2: /* EDX Base */
base=SegBase(ds)+reg_edx;break;
case 3: /* EBX Base */
base=SegBase(ds)+reg_ebx;break;
case 4: /* ESP Base */
base=SegBase(ds)+reg_esp;break;
case 5: /* #1 Base */
if (!mode) {
base=SegBase(ds)+Fetchd();break;
} else {
base=SegBase(ss)+reg_ebp;break;
}
case 6: /* ESI Base */
base=SegBase(ds)+reg_esi;break;
case 7: /* EDI Base */
base=SegBase(ds)+reg_edi;break;
}
Bitu shift=sib >> 6;
switch ((sib >>3) &7) {
case 0: /* EAX Index */
base+=(Bit32s)reg_eax<<shift;break;
case 1: /* ECX Index */
base+=(Bit32s)reg_ecx<<shift;break;
case 2: /* EDX Index */
base+=(Bit32s)reg_edx<<shift;break;
case 3: /* EBX Index */
base+=(Bit32s)reg_ebx<<shift;break;
case 4: /* None */
break;
case 5: /* EBP Index */
base+=(Bit32s)reg_ebp<<shift;break;
case 6: /* ESI Index */
base+=(Bit32s)reg_esi<<shift;break;
case 7: /* EDI Index */
base+=(Bit32s)reg_edi<<shift;break;
};
return base;
};
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_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_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 GetEATable GetEA_32_n={
/* 00 */
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
/* 01 */
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
/* 10 */
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
/* 11 These are illegal so make em 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

185
src/cpu/cpu.cpp Normal file
View file

@ -0,0 +1,185 @@
/*
* 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 "cpu.h"
#include "memory.h"
#include "debug.h"
#include "keyboard.h"
//Regs regs;
Flag_Info flags;
CPU_Regs cpu_regs;
Segment Segs[6];
Bit32u cpu_cycles;
CPU_Decoder * cpudecoder;
static void CPU_CycleIncrease(void) {
Bit32u old_cycles=cpu_cycles;
cpu_cycles=(Bit32u)(cpu_cycles*1.2);
if (cpu_cycles==old_cycles) cpu_cycles++;
LOG_MSG("CPU:%d cycles",cpu_cycles);
}
static void CPU_CycleDecrease(void) {
cpu_cycles=(Bit32u)(cpu_cycles/1.2);
if (!cpu_cycles) cpu_cycles=1;
LOG_MSG("CPU:%d cycles",cpu_cycles);
}
Bit8u lastint;
void Interrupt(Bit8u num) {
lastint=num;
//DEBUG THINGIE to check fucked ints
switch (num) {
case 0x00:
LOG_WARN("Divide Error");
break;
case 0x06:
break;
case 0x07:
LOG_WARN("Co Processor Exception");
break;
case 0x08:
case 0x09:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x16:
case 0x15:
case 0x1A:
case 0x17:
case 0x1C:
case 0x21:
case 0x2a:
case 0x2f:
case 0x33:
case 0x67:
case 0x74:
break;
case 0xcd:
E_Exit("Call to interrupt 0xCD this is BAD");
case 0x03:
#ifdef C_DEBUG
if (DEBUG_BreakPoint()) return;
#endif
break;
case 0x05:
LOG_MSG("CPU:Out Of Bounds interrupt");
break;
default:
// LOG_WARN("Call to unsupported INT %02X call %02X",num,reg_ah);
break;
};
/* Check for 16-bit or 32-bit and then setup everything for the interrupt to start */
Bit16u pflags;
pflags=
(get_CF() << 0) |
(get_PF() << 2) |
(get_AF() << 4) |
(get_ZF() << 6) |
(get_SF() << 7) |
(flags.tf << 8) |
(flags.intf << 9) |
(flags.df << 10) |
(get_OF() << 11) |
(flags.io << 12) |
(flags.nt <<14);
flags.intf=false;
flags.tf=false;
/* Save everything on a 16-bit stack */
reg_sp-=2;
mem_writew(Segs[ss].phys+reg_sp,pflags);
reg_sp-=2;
mem_writew(Segs[ss].phys+reg_sp,Segs[cs].value);
reg_sp-=2;
mem_writew(Segs[ss].phys+reg_sp,reg_ip);
/* Get the new CS:IP from vector table */
Bit16u newip=mem_readw(num << 2);
Bit16u newcs=mem_readw((num <<2)+2);
SetSegment_16(cs,newcs);
reg_ip=newip;
}
void CPU_Real_16_Slow_Start(void);
void SetCPU16bit()
{
CPU_Real_16_Slow_Start();
}
void SetSegment_16(Bit32u seg,Bit16u val) {
Segs[seg].value=val;
Bit32u off=(val << 4);
Segs[seg].host=memory+off;
Segs[seg].phys=off;
//TODO Maybe use this feature one day :)
// Segs[seg].special=MEMORY_TestSpecial(off);
};
void CPU_Init(void) {
reg_eax=0;
reg_ebx=0;
reg_ecx=0;
reg_edx=0;
reg_edi=0;
reg_esi=0;
reg_ebp=0;
reg_esp=0;
SetSegment_16(cs,0);
SetSegment_16(ds,0);
SetSegment_16(es,0);
SetSegment_16(fs,0);
SetSegment_16(gs,0);
SetSegment_16(ss,0);
reg_eip=0;
flags.type=t_UNKNOWN;
flags.af=0;
flags.cf=0;
flags.cf=0;
flags.sf=0;
flags.zf=0;
flags.intf=true;
flags.nt=0;
flags.io=0;
SetCPU16bit();
cpu_cycles=2000;
KEYBOARD_AddEvent(KBD_f11,CTRL_PRESSED,CPU_CycleDecrease);
KEYBOARD_AddEvent(KBD_f12,CTRL_PRESSED,CPU_CycleIncrease);
reg_al=0;
reg_ah=0;
}

582
src/cpu/flags.cpp Normal file
View file

@ -0,0 +1,582 @@
/*
* 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.
*/
/*
Lazy flag system was designed after the same kind of system used in Bochs.
Probably still some bugs left in here.
*/
#include "dosbox.h"
#include "cpu.h"
#include "pic.h"
/* CF Carry Flag -- Set on high-order bit carry or borrow; cleared
otherwise.
*/
bool get_CF(void) {
switch (flags.type) {
case t_UNKNOWN:
case t_CF:
case t_INCb:
case t_INCw:
case t_INCd:
case t_DECb:
case t_DECw:
case t_DECd:
case t_MUL:
return flags.cf;
break;
case t_ADDb:
return (flags.result.b<flags.var1.b);
case t_ADDw:
return (flags.result.w<flags.var1.w);
case t_ADDd:
return (flags.result.d<flags.var1.d);
case t_ADCb:
return (flags.result.b < flags.var1.b) || (flags.oldcf && (flags.result.b == flags.var1.b));
case t_ADCw:
return (flags.result.w < flags.var1.w) || (flags.oldcf && (flags.result.w == flags.var1.w));
case t_ADCd:
return (flags.result.d < flags.var1.d) || (flags.oldcf && (flags.result.d == flags.var1.d));
case t_SBBb:
return (flags.var1.b < flags.result.b) || (flags.oldcf && (flags.var2.b==0xff));
case t_SBBw:
return (flags.var1.w < flags.result.w) || (flags.oldcf && (flags.var2.w==0xffff));
case t_SBBd:
return (flags.var1.d < flags.result.d) || (flags.oldcf && (flags.var2.d==0xffffffff));
case t_SUBb:
case t_CMPb:
return (flags.var1.b<flags.var2.b);
case t_SUBw:
case t_CMPw:
return (flags.var1.w<flags.var2.w);
case t_SUBd:
case t_CMPd:
return (flags.var1.d<flags.var2.d);
case t_SHLb:
if (flags.var2.b>=8) return false;
else return (flags.var1.b >> (8-flags.var2.b)) & 1;
case t_SHLw:
if (flags.var2.b>=16) return false;
else return (flags.var1.w >> (16-flags.var2.b)) & 1;
case t_SHLd:
return (flags.var1.d >> (32 - flags.var2.b)) & 0x01;
case t_DSHLw: /* Hmm this is not correct for shift higher than 16 */
return (flags.var1.d >> (32 - flags.var2.b)) & 0x01;
case t_DSHLd:
return (flags.var1.d >> (32 - flags.var2.b)) & 0x01;
case t_SHRb:
return (flags.var1.b >> (flags.var2.b - 1)) & 0x01;
case t_SHRw:
return (flags.var1.w >> (flags.var2.b - 1)) & 0x01;
case t_SHRd:
return (flags.var1.d >> (flags.var2.b - 1)) & 0x01;
case t_SARb:
return (flags.var1.b >> (flags.var2.b - 1)) & 0x01;
case t_SARw:
return (flags.var1.w >> (flags.var2.b - 1)) & 0x01;
case t_SARd:
return (flags.var1.d >> (flags.var2.b - 1)) & 0x01;
case t_DSHRw: /* Hmm this is not correct for shift higher than 16 */
return (flags.var1.d >> (flags.var2.b - 1)) & 0x01;
case t_DSHRd:
return (flags.var1.d >> (flags.var2.b - 1)) & 0x01;
case t_NEGb:
return (flags.var1.b!=0);
case t_NEGw:
return (flags.var1.w!=0);
case t_NEGd:
return (flags.var1.d!=0);
case t_ROLb:
return (flags.result.b & 1)>0;
case t_ROLw:
return (flags.result.w & 1)>0;
case t_ROLd:
return (flags.result.d & 1)>0;
case t_RORb:
return (flags.result.b & 0x80)>0;
case t_RORw:
return (flags.result.w & 0x8000)>0;
case t_RORd:
return (flags.result.d & 0x80000000)>0;
case t_RCLb:
return ((flags.var1.b >> (8-flags.var2.b))&1)>0;
case t_RCLw:
return ((flags.var1.w >> (16-flags.var2.b))&1)>0;
case t_RCLd:
return ((flags.var1.d >> (32-flags.var2.b))&1)>0;
case t_RCRb:
return ((flags.var1.b >> (flags.var2.b-1))&1)>0;
case t_RCRw:
return ((flags.var1.w >> (flags.var2.b-1))&1)>0;
case t_RCRd:
return ((flags.var1.d >> (flags.var2.b-1))&1)>0;
case t_ORb:
case t_ORw:
case t_ORd:
case t_ANDb:
case t_ANDw:
case t_ANDd:
case t_XORb:
case t_XORw:
case t_XORd:
case t_TESTb:
case t_TESTw:
case t_TESTd:
case t_DIV:
return false;
default:
E_Exit("get_CF Unknown %d",flags.type);
}
return 0;
}
/* AF Adjust flag -- Set on carry from or borrow to the low order
four bits of AL; cleared otherwise. Used for decimal
arithmetic.
*/
bool get_AF(void) {
Bitu type=flags.type;
again:
switch (type) {
case t_UNKNOWN:
case t_ROLb:
case t_RORb:
case t_RCLb:
case t_RCRb:
case t_ROLw:
case t_RORw:
case t_RCLw:
case t_RCRw:
case t_ROLd:
case t_RORd:
case t_RCLd:
case t_RCRd:
return flags.af;
case t_CF:
type=flags.prev_type;
goto again;
case t_ADDb:
case t_ADCb:
case t_SBBb:
case t_SUBb:
case t_CMPb:
return (((flags.var1.b ^ flags.var2.b) ^ flags.result.b) & 0x10)>0;
case t_ADDw:
case t_ADCw:
case t_SBBw:
case t_SUBw:
case t_CMPw:
return (((flags.var1.w ^ flags.var2.w) ^ flags.result.w) & 0x10)>0;
case t_ADCd:
case t_ADDd:
case t_SBBd:
case t_SUBd:
case t_CMPd:
return (((flags.var1.d ^ flags.var2.d) ^ flags.result.d) & 0x10)>0;
case t_INCb:
return (flags.result.b & 0x0f) == 0;
case t_INCw:
return (flags.result.w & 0x0f) == 0;
case t_INCd:
return (flags.result.d & 0x0f) == 0;
case t_DECb:
return (flags.result.b & 0x0f) == 0x0f;
case t_DECw:
return (flags.result.w & 0x0f) == 0x0f;
case t_DECd:
return (flags.result.d & 0x0f) == 0x0f;
case t_NEGb:
return (flags.var1.b & 0x0f) > 0;
case t_NEGw:
return (flags.var1.w & 0x0f) > 0;
case t_NEGd:
return (flags.var1.d & 0x0f) > 0;
case t_ORb:
case t_ORw:
case t_ORd:
case t_ANDb:
case t_ANDw:
case t_ANDd:
case t_XORb:
case t_XORw:
case t_XORd:
case t_TESTb:
case t_TESTw:
case t_TESTd:
case t_SHLb:
case t_SHLw:
case t_SHLd:
case t_SHRb:
case t_SHRw:
case t_SHRd:
case t_SARb:
case t_SARw:
case t_DSHLw:
case t_DSHLd:
case t_DSHRw:
case t_DSHRd:
case t_DIV:
case t_MUL:
return false; /* undefined */
default:
E_Exit("get_AF Unknown %d",flags.type);
}
return 0;
}
/* ZF Zero Flag -- Set if result is zero; cleared otherwise.
*/
bool get_ZF(void) {
Bitu type=flags.type;
again:
switch (type) {
case t_UNKNOWN:
case t_ROLb:
case t_RORb:
case t_RCLb:
case t_RCRb:
case t_ROLw:
case t_RORw:
case t_RCLw:
case t_RCRw:
case t_ROLd:
case t_RORd:
case t_RCLd:
case t_RCRd:
return flags.zf;
case t_CF:
type=flags.prev_type;
goto again;
case t_ADDb:
case t_ORb:
case t_ADCb:
case t_SBBb:
case t_ANDb:
case t_XORb:
case t_SUBb:
case t_CMPb:
case t_INCb:
case t_DECb:
case t_TESTb:
case t_SHLb:
case t_SHRb:
case t_SARb:
case t_NEGb:
return (flags.result.b==0);
case t_ADDw:
case t_ORw:
case t_ADCw:
case t_SBBw:
case t_ANDw:
case t_XORw:
case t_SUBw:
case t_CMPw:
case t_INCw:
case t_DECw:
case t_TESTw:
case t_SHLw:
case t_SHRw:
case t_SARw:
case t_DSHLw:
case t_DSHRw:
case t_NEGw:
return (flags.result.w==0);
case t_ADDd:
case t_ORd:
case t_ADCd:
case t_SBBd:
case t_ANDd:
case t_XORd:
case t_SUBd:
case t_CMPd:
case t_INCd:
case t_DECd:
case t_TESTd:
case t_SHLd:
case t_SHRd:
case t_SARd:
case t_DSHLd:
case t_DSHRd:
case t_NEGd:
return (flags.result.d==0);
case t_DIV:
case t_MUL:
return false;
default:
E_Exit("get_ZF Unknown %d",flags.type);
}
return false;
}
/* SF Sign Flag -- Set equal to high-order bit of result (0 is
positive, 1 if negative).
*/
bool get_SF(void) {
Bitu type=flags.type;
again:
switch (type) {
case t_UNKNOWN:
case t_ROLb:
case t_RORb:
case t_RCLb:
case t_RCRb:
case t_ROLw:
case t_RORw:
case t_RCLw:
case t_RCRw:
case t_ROLd:
case t_RORd:
case t_RCLd:
case t_RCRd:
return flags.sf;
case t_CF:
type=flags.prev_type;
goto again;
case t_ADDb:
case t_ORb:
case t_ADCb:
case t_SBBb:
case t_ANDb:
case t_XORb:
case t_SUBb:
case t_CMPb:
case t_INCb:
case t_DECb:
case t_TESTb:
case t_SHLb:
case t_SHRb:
case t_SARb:
case t_NEGb:
return (flags.result.b>=0x80);
case t_ADDw:
case t_ORw:
case t_ADCw:
case t_SBBw:
case t_ANDw:
case t_XORw:
case t_SUBw:
case t_CMPw:
case t_INCw:
case t_DECw:
case t_TESTw:
case t_SHLw:
case t_SHRw:
case t_SARw:
case t_DSHLw:
case t_DSHRw:
case t_NEGw:
return (flags.result.w>=0x8000);
case t_ADDd:
case t_ORd:
case t_ADCd:
case t_SBBd:
case t_ANDd:
case t_XORd:
case t_SUBd:
case t_CMPd:
case t_INCd:
case t_DECd:
case t_TESTd:
case t_SHLd:
case t_SHRd:
case t_SARd:
case t_DSHLd:
case t_DSHRd:
case t_NEGd:
return (flags.result.d>=0x80000000);
case t_DIV:
case t_MUL:
return false;
default:
E_Exit("get_SF Unkown %d",flags.type);
}
return false;
}
bool get_OF(void) {
Bit8u var1b7, var2b7, resultb7;
Bit16u var1w15, var2w15, resultw15;
Bit32u var1d31, var2d31, resultd31;
Bitu type=flags.type;
again:
switch (type) {
case t_UNKNOWN:
case t_MUL:
return flags.of;
case t_CF:
type=flags.prev_type;
goto again;
case t_ADDb:
case t_ADCb:
// return (((flags.result.b) ^ (flags.var2.b)) & ((flags.result.b) ^ (flags.var1.b)) & 0x80)>0;
var1b7 = flags.var1.b & 0x80;
var2b7 = flags.var2.b & 0x80;
resultb7 = flags.result.b & 0x80;
return (var1b7 == var2b7) && (resultb7 ^ var2b7);
case t_ADDw:
case t_ADCw:
// return (((flags.result.w) ^ (flags.var2.w)) & ((flags.result.w) ^ (flags.var1.w)) & 0x8000)>0;
var1w15 = flags.var1.w & 0x8000;
var2w15 = flags.var2.w & 0x8000;
resultw15 = flags.result.w & 0x8000;
return (var1w15 == var2w15) && (resultw15 ^ var2w15);
case t_ADDd:
case t_ADCd:
//TODO fix dword Overflow
var1d31 = flags.var1.d & 0x8000;
var2d31 = flags.var2.d & 0x8000;
resultd31 = flags.result.d & 0x8000;
return (var1d31 == var2d31) && (resultd31 ^ var2d31);
case t_SBBb:
case t_SUBb:
case t_CMPb:
// return (((flags.var1.b) ^ (flags.var2.b)) & ((flags.var1.b) ^ (flags.result.b)) & 0x80)>0;
var1b7 = flags.var1.b & 0x80;
var2b7 = flags.var2.b & 0x80;
resultb7 = flags.result.b & 0x80;
return (var1b7 ^ var2b7) && (var1b7 ^ resultb7);
case t_SBBw:
case t_SUBw:
case t_CMPw:
// return (((flags.var1.w) ^ (flags.var2.w)) & ((flags.var1.w) ^ (flags.result.w)) & 0x8000)>0;
var1w15 = flags.var1.w & 0x8000;
var2w15 = flags.var2.w & 0x8000;
resultw15 = flags.result.w & 0x8000;
return (var1w15 ^ var2w15) && (var1w15 ^ resultw15);
case t_SBBd:
case t_SUBd:
case t_CMPd:
var1d31 = flags.var1.d & 0x8000;
var2d31 = flags.var2.d & 0x8000;
resultd31 = flags.result.d & 0x8000;
return (var1d31 ^ var2d31) && (var1d31 ^ resultd31);
case t_INCb:
return (flags.result.b == 0x80);
case t_INCw:
return (flags.result.w == 0x8000);
case t_INCd:
return (flags.result.d == 0x80000000);
case t_DECb:
return (flags.result.b == 0x7f);
case t_DECw:
return (flags.result.w == 0x7fff);
case t_DECd:
return (flags.result.d == 0x7fffffff);
case t_NEGb:
return (flags.var1.b == 0x80);
case t_NEGw:
return (flags.var1.w == 0x8000);
case t_NEGd:
return (flags.var1.d == 0x80000000);
case t_ROLb:
case t_RORb:
case t_RCLb:
case t_RCRb:
case t_SHLb:
if (flags.var2.b==1) return ((flags.var1.b ^ flags.result.b) & 0x80) >0;
break;
case t_ROLw:
case t_RORw:
case t_RCLw:
case t_RCRw:
case t_SHLw:
case t_DSHLw: //TODO This is euhm inccorect i think but let's keep it for now
if (flags.var2.b==1) return ((flags.var1.w ^ flags.result.w) & 0x8000) >0;
break;
case t_ROLd:
case t_RORd:
case t_RCLd:
case t_RCRd:
case t_SHLd:
case t_DSHLd:
if (flags.var2.b==1) return ((flags.var1.d ^ flags.result.d) & 0x80000000) >0;
break;
case t_SHRb:
if (flags.var2.b==1) return (flags.var1.b >= 0x80);
break;
case t_SHRw:
case t_DSHRw: //TODO
if (flags.var2.b==1) return (flags.var1.w >= 0x8000);
break;
case t_SHRd:
case t_DSHRd: //TODO
if (flags.var2.b==1) return (flags.var1.d >= 0x80000000);
break;
case t_SARb:
case t_SARw:
case t_SARd:
case t_ORb:
case t_ORw:
case t_ORd:
case t_ANDb:
case t_ANDw:
case t_ANDd:
case t_XORb:
case t_XORw:
case t_XORd:
case t_TESTb:
case t_TESTw:
case t_TESTd:
case t_DIV:
return false;
default:
E_Exit("get_OF Unkown %d",flags.type);
}
return false;
}
static bool parity_lookup[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
bool get_PF(void) {
switch (flags.type) {
case t_UNKNOWN:
return flags.pf;
default:
return (parity_lookup[flags.result.b]);;
};
return false;
}

210
src/cpu/modrm.cpp Normal file
View file

@ -0,0 +1,210 @@
/*
* 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 "cpu.h"
Bit8u * lookupRMregb[]=
{
&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,
&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,
&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,
&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,
&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,
&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,
&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,
&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,
&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,
&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,
&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,
&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,
&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,
&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,
&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,
&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,
&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,
&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,
&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,
&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,
&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,
&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,
&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,
&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,
&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,&reg_al,
&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,&reg_cl,
&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,&reg_dl,
&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,&reg_bl,
&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,&reg_ah,
&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,&reg_ch,
&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,&reg_dh,
&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh,&reg_bh
};
Bit16u * lookupRMregw[]={
&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,
&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,
&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,
&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,
&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,
&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,
&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,
&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,
&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,
&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,
&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,
&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,
&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,
&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,
&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,
&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,
&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,
&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,
&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,
&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,
&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,
&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,
&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,
&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,
&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,&reg_ax,
&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,&reg_cx,
&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,&reg_dx,
&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,&reg_bx,
&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,&reg_sp,
&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,&reg_bp,
&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,&reg_si,
&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di,&reg_di
};
Bit32u * lookupRMregd[256]={
&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,
&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,
&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,
&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,
&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,
&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,
&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,
&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,
&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,
&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,
&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,
&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,
&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,
&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,
&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,
&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,
&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,
&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,
&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,
&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,
&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,
&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,
&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,
&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,
&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,&reg_eax,
&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,&reg_ecx,
&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,&reg_edx,
&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,&reg_ebx,
&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,&reg_esp,
&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,&reg_ebp,
&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,&reg_esi,
&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi,&reg_edi
};
Bit8u * lookupRMEAregb[256]={
/* 12 lines of 16*0 should give nice errors when used */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh,
&reg_al,&reg_cl,&reg_dl,&reg_bl,&reg_ah,&reg_ch,&reg_dh,&reg_bh
};
Bit16u * lookupRMEAregw[256]={
/* 12 lines of 16*0 should give nice errors when used */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di,
&reg_ax,&reg_cx,&reg_dx,&reg_bx,&reg_sp,&reg_bp,&reg_si,&reg_di
};
Bit32u * lookupRMEAregd[256]={
/* 12 lines of 16*0 should give nice errors when used */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi,
&reg_eax,&reg_ecx,&reg_edx,&reg_ebx,&reg_esp,&reg_ebp,&reg_esi,&reg_edi
};

76
src/cpu/modrm.h Normal file
View file

@ -0,0 +1,76 @@
/*
* 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.
*/
extern Bit8u * lookupRMregb[];
extern Bit16u * lookupRMregw[];
extern Bit32u * lookupRMregd[];
extern Bit8u * lookupRMEAregb[256];
extern Bit16u * lookupRMEAregw[256];
extern Bit32u * lookupRMEAregd[256];
#define GetRM \
Bit8u rm=Fetchb();
#define Getrb \
Bit8u * rmrb; \
rmrb=lookupRMregb[rm];
#define Getrw \
Bit16u * rmrw; \
rmrw=lookupRMregw[rm];
#define Getrd \
Bit32u * rmrd; \
rmrd=lookupRMregd[rm];
#define GetRMrb \
GetRM; \
Getrb;
#define GetRMrw \
GetRM; \
Getrw;
#define GetRMrd \
GetRM; \
Getrd;
#define GetEArb \
union { \
Bit8u * earb; \
Bit8s * earbs; \
}; \
earb=lookupRMEAregb[rm];
#define GetEArw \
union { \
Bit16u * earw; \
Bit16s * earws; \
}; \
earw=lookupRMEAregw[rm];
#define GetEArd \
union { \
Bit32u * eard; \
Bit32s * eards; \
}; \
eard=lookupRMEAregd[rm];

120
src/cpu/slow_16.cpp Normal file
View file

@ -0,0 +1,120 @@
/*
* 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 "mem.h"
#include "cpu.h"
#include "inout.h"
#include "callback.h"
#include "pic.h"
#include "fpu.h"
typedef PhysPt EAPoint;
#define SegBase(seg) Segs[seg].phys
#define LoadMb(off) mem_readb(off)
#define LoadMw(off) mem_readw(off)
#define LoadMd(off) mem_readd(off)
#define LoadMbs(off) (Bit8s)(LoadMb(off))
#define LoadMws(off) (Bit16s)(LoadMw(off))
#define LoadMds(off) (Bit32s)(LoadMd(off))
#define SaveMb(off,val) mem_writeb(off,val)
#define SaveMw(off,val) mem_writew(off,val)
#define SaveMd(off,val) mem_writed(off,val)
/*
typedef HostOff EAPoint;
#define SegBase(seg) Segs[seg].host
#define LoadMb(off) readb(off)
#define LoadMw(off) readw(off)
#define LoadMd(off) readd(off)
#define LoadMbs(off) (Bit8s)(LoadMb(off))
#define LoadMws(off) (Bit16s)(LoadMw(off))
#define LoadMds(off) (Bit32s)(LoadMd(off))
#define SaveMb(off,val) writeb(off,val)
#define SaveMw(off,val) writew(off,val)
#define SaveMd(off,val) writed(off,val)
*/
#define LoadRb(reg) reg
#define LoadRw(reg) reg
#define LoadRd(reg) reg
#define SaveRb(reg,val) reg=val
#define SaveRw(reg,val) reg=val
#define SaveRd(reg,val) reg=val
extern Bitu cycle_count;
#define CPU_386
//TODO Change name
#define FULLFLAGS
#include "core_16/support.h"
static Bitu CPU_Real_16_Slow_Decode_Special(Bitu count);
static Bitu CPU_Real_16_Slow_Decode(Bitu count) {
#include "core_16/start.h"
while (count) {
#ifdef C_DEBUG
cycle_count++;
#endif
count--;
#include "core_16/main.h"
}
#include "core_16/stop.h"
return CBRET_NONE;
}
static Bitu CPU_Real_16_Slow_Decode_Special(Bitu 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--;
}
return CBRET_NONE;
}
void CPU_Real_16_Slow_Start(void) {
lookupEATable=&GetEA_16_n;
segprefix_base=0;
segprefix_on=false;
cpudecoder=&CPU_Real_16_Slow_Decode;
};

5
src/debug/Makefile.am Normal file
View file

@ -0,0 +1,5 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
EXTRA_DIST = debug_win32.cpp
noinst_LIBRARIES = libdebug.a
libdebug_a_SOURCES = debug.cpp debug_gui.cpp debug_disasm.cpp debug_inc.h disasm_tables.h

257
src/debug/debug.cpp Normal file
View file

@ -0,0 +1,257 @@
/*
* 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 <string.h>
#include <list>
#include "dosbox.h"
#ifdef C_DEBUG
#include "debug.h"
#include "cpu.h"
#include "video.h"
#include "pic.h"
#include "keyboard.h"
#include "cpu.h"
#include "callback.h"
#include "inout.h"
#include "mixer.h"
#include "debug_inc.h"
#ifdef WIN32
void WIN32_Console();
#endif
static struct {
Bit32u eax,ebx,ecx,edx,esi,edi,ebp,esp,eip;
} oldregs;
static Segment oldsegs[6];
static Flag_Info oldflags;
DBGBlock dbg;
static char input_line[256];
static Bitu input_count;
Bitu cycle_count;
static bool debugging;
static void SetColor(bool test) {
if (test) {
if (has_colors()) { wattrset(dbg.win_reg,COLOR_PAIR(PAIR_BYELLOW_BLACK));}
} else {
if (has_colors()) { wattrset(dbg.win_reg,0);}
}
}
enum { BKPNT_REALMODE,BKPNT_PHYSICAL };
struct BreakPoint {
PhysPt location;
Bit8u olddata;
Bit16u seg;
Bit16u off_16;
Bit32u off_32;
Bit8u type;
bool enabled;
bool active;
};
static std::list<struct BreakPoint> BPoints;
static void DrawRegisters(void) {
/* Main Registers */
SetColor(reg_eax!=oldregs.eax);oldregs.eax=reg_eax;mvwprintw (dbg.win_reg,0,4,"%08X",reg_eax);
SetColor(reg_ebx!=oldregs.ebx);oldregs.ebx=reg_ebx;mvwprintw (dbg.win_reg,1,4,"%08X",reg_ebx);
SetColor(reg_ecx!=oldregs.ecx);oldregs.ecx=reg_ecx;mvwprintw (dbg.win_reg,2,4,"%08X",reg_ecx);
SetColor(reg_edx!=oldregs.edx);oldregs.edx=reg_edx;mvwprintw (dbg.win_reg,3,4,"%08X",reg_edx);
SetColor(reg_esi!=oldregs.esi);oldregs.esi=reg_esi;mvwprintw (dbg.win_reg,0,18,"%08X",reg_esi);
SetColor(reg_edi!=oldregs.edi);oldregs.edi=reg_edi;mvwprintw (dbg.win_reg,1,18,"%08X",reg_edi);
SetColor(reg_ebp!=oldregs.ebp);oldregs.ebp=reg_ebp;mvwprintw (dbg.win_reg,2,18,"%08X",reg_ebp);
SetColor(reg_esp!=oldregs.esp);oldregs.esp=reg_esp;mvwprintw (dbg.win_reg,3,18,"%08X",reg_esp);
SetColor(reg_eip!=oldregs.eip);oldregs.eip=reg_eip;mvwprintw (dbg.win_reg,1,42,"%08X",reg_eip);
SetColor(Segs[ds].value!=oldsegs[ds].value);oldsegs[ds].value=Segs[ds].value;mvwprintw (dbg.win_reg,0,31,"%04X",Segs[ds].value);
SetColor(Segs[es].value!=oldsegs[es].value);oldsegs[es].value=Segs[es].value;mvwprintw (dbg.win_reg,0,41,"%04X",Segs[es].value);
SetColor(Segs[fs].value!=oldsegs[fs].value);oldsegs[fs].value=Segs[fs].value;mvwprintw (dbg.win_reg,0,51,"%04X",Segs[fs].value);
SetColor(Segs[gs].value!=oldsegs[gs].value);oldsegs[gs].value=Segs[gs].value;mvwprintw (dbg.win_reg,0,61,"%04X",Segs[gs].value);
SetColor(Segs[ss].value!=oldsegs[ss].value);oldsegs[ss].value=Segs[ss].value;mvwprintw (dbg.win_reg,0,71,"%04X",Segs[ss].value);
SetColor(Segs[cs].value!=oldsegs[cs].value);oldsegs[cs].value=Segs[cs].value;mvwprintw (dbg.win_reg,1,31,"%04X",Segs[cs].value);
/*Individual flags*/
flags.cf=get_CF();SetColor(flags.cf!=oldflags.cf);oldflags.cf=flags.cf;mvwprintw (dbg.win_reg,1,53,"%01X",flags.cf);
flags.zf=get_ZF();SetColor(flags.zf!=oldflags.zf);oldflags.zf=flags.zf;mvwprintw (dbg.win_reg,1,56,"%01X",flags.zf);
flags.sf=get_SF();SetColor(flags.sf!=oldflags.sf);oldflags.sf=flags.sf;mvwprintw (dbg.win_reg,1,59,"%01X",flags.sf);
flags.of=get_OF();SetColor(flags.of!=oldflags.of);oldflags.of=flags.of;mvwprintw (dbg.win_reg,1,62,"%01X",flags.of);
flags.af=get_AF();SetColor(flags.af!=oldflags.af);oldflags.af=flags.af;mvwprintw (dbg.win_reg,1,65,"%01X",flags.af);
flags.pf=get_PF();SetColor(flags.pf!=oldflags.pf);oldflags.pf=flags.pf;mvwprintw (dbg.win_reg,1,68,"%01X",flags.pf);
SetColor(flags.df!=oldflags.df);oldflags.df=flags.df;mvwprintw (dbg.win_reg,1,71,"%01X",flags.df);
SetColor(flags.intf!=oldflags.intf);oldflags.intf=flags.intf;mvwprintw (dbg.win_reg,1,74,"%01X",flags.intf);
SetColor(flags.tf!=oldflags.tf);oldflags.tf=flags.tf;mvwprintw (dbg.win_reg,1,77,"%01X",flags.tf);
wattrset(dbg.win_reg,0);
mvwprintw(dbg.win_reg,3,60,"%d ",cycle_count);
wrefresh(dbg.win_reg);
};
static void DrawCode(void) {
PhysPt start=Segs[cs].phys+reg_eip;
char dline[200];Bitu size;Bitu c;
for (Bit32u i=0;i<10;i++) {
size=DasmI386(dline, start, reg_eip, false);
mvwprintw(dbg.win_code,i,0,"%02X:%04X ",Segs[cs].value,(start-Segs[cs].phys));
for (c=0;c<size;c++) wprintw(dbg.win_code,"%02X",mem_readb(start+c));
for (c=20;c>=size*2;c--) waddch(dbg.win_code,' ');
waddstr(dbg.win_code,dline);
for (c=30-strlen(dline);c>0;c--) waddch(dbg.win_code,' ');
start+=size;
}
wrefresh(dbg.win_code);
}
/* This clears all breakpoints by replacing their 0xcc by the original byte */
static void ClearBreakPoints(void) {
// for (Bit32u i=0;i<MAX_BREAKPOINT;i++) {
// if (bpoints[i].active && bpoints[i].enabled) {
// mem_writeb(bpoints[i].location,bpoints[i].olddata);
// }
// }
}
static void SetBreakPoints(void) {
// for (Bit32u i=0;i<MAX_BREAKPOINT;i++) {
// if (bpoints[i].active && bpoints[i].enabled) {
// bpoints[i].olddata=mem_readb(bpoints[i].location);
// mem_writeb(bpoints[i].location,0xcc);
// }
// }
}
static void AddBreakPoint(PhysPt off) {
}
bool DEBUG_BreakPoint(void) {
/* First get the phyiscal address and check for a set breakpoint */
PhysPt where=real_phys(Segs[cs].value,reg_ip-1);
bool found=false;
std::list<BreakPoint>::iterator i;
for(i=BPoints.begin(); i != BPoints.end(); ++i) {
if ((*i).active && (*i).enabled) {
if ((*i).location==where) {
found=true;
break;
}
}
}
if (!found) return false;
ClearBreakPoints();
DEBUG_Enable();
SetBreakPoints();
return false;
}
Bit32u DEBUG_CheckKeys(void) {
int key=getch();
Bit32u ret=0;
if (key>0) {
switch (key) {
case '1':
ret=(*cpudecoder)(100);
break;
case '2':
ret=(*cpudecoder)(500);
break;
case '3':
ret=(*cpudecoder)(1000);
break;
case '4':
ret=(*cpudecoder)(5000);
break;
case '5':
ret=(*cpudecoder)(10000);
break;
case 'q':
ret=(*cpudecoder)(5);
break;
default:
ret=(*cpudecoder)(1);
};
DEBUG_DrawScreen();
}
return ret;
};
Bitu DEBUG_Loop(void) {
//TODO Disable sound
GFX_Events();
PIC_runIRQs();
return DEBUG_CheckKeys();
}
void DEBUG_Enable(void) {
DEBUG_DrawScreen();
debugging=true;
DOSBOX_SetLoop(&DEBUG_Loop);
}
void DEBUG_DrawScreen(void) {
DrawRegisters();
DrawCode();
}
static void DEBUG_RaiseTimerIrq(void) {
PIC_ActivateIRQ(0);
}
void DEBUG_Init(void) {
#ifdef WIN32
WIN32_Console();
#endif
memset((void *)&dbg,0,sizeof(dbg));
debugging=false;
dbg.active_win=3;
input_count=0;
/* Start the Debug Gui */
DBGUI_StartUp();
DEBUG_DrawScreen();
/* Add some keyhandlers */
KEYBOARD_AddEvent(KBD_kpminus,0,DEBUG_Enable);
KEYBOARD_AddEvent(KBD_kpplus,0,DEBUG_RaiseTimerIrq);
/* Clear the breakpoint list */
}
#endif

1112
src/debug/debug_disasm.cpp Normal file

File diff suppressed because it is too large Load diff

130
src/debug/debug_gui.cpp Normal file
View file

@ -0,0 +1,130 @@
/*
* 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"
#ifdef C_DEBUG
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <curses.h>
#include <string.h>
#include "regs.h"
#include "debug.h"
#include "debug_inc.h"
void DEBUG_ShowMsg(char * msg) {
char buf[1024];
strcpy(buf,msg);
strcat(buf,"\n");
waddstr(dbg.win_out,buf);
wprintw(dbg.win_out," %d\n",cycle_count);
wrefresh(dbg.win_out);
}
static void Draw_RegisterLayout(void) {
mvwaddstr(dbg.win_reg,0,0,"EAX=");
mvwaddstr(dbg.win_reg,1,0,"EBX=");
mvwaddstr(dbg.win_reg,2,0,"ECX=");
mvwaddstr(dbg.win_reg,3,0,"EDX=");
mvwaddstr(dbg.win_reg,0,14,"ESI=");
mvwaddstr(dbg.win_reg,1,14,"EDI=");
mvwaddstr(dbg.win_reg,2,14,"EBP=");
mvwaddstr(dbg.win_reg,3,14,"ESP=");
mvwaddstr(dbg.win_reg,0,28,"DS=");
mvwaddstr(dbg.win_reg,0,38,"ES=");
mvwaddstr(dbg.win_reg,0,48,"FS=");
mvwaddstr(dbg.win_reg,0,58,"GS=");
mvwaddstr(dbg.win_reg,0,68,"SS=");
mvwaddstr(dbg.win_reg,1,28,"CS=");
mvwaddstr(dbg.win_reg,1,38,"EIP=");
mvwaddstr(dbg.win_reg,1,52,"C Z S O A P D I T ");
}
static void DrawBars(void) {
if (has_colors()) {
attrset(COLOR_PAIR(PAIR_BLACK_BLUE));
}
/* Show the Register bar */
mvaddstr(dbg.win_reg->_begy-1,0,"---[F1](Register Overview)---");
/* Show the Data Overview bar perhaps with more special stuff in the end */
mvaddstr(dbg.win_data->_begy-1,0,"---[F2](Data Overview)---");
/* Show the Code Overview perhaps with special stuff in bar too */
mvaddstr(dbg.win_code->_begy-1,0,"---[F3](Code Overview)---");
/* Show the Output OverView */
mvaddstr(dbg.win_out->_begy-1,0,"---[F4](OutPut/Input)---");
attrset(0);
}
static void MakeSubWindows(void) {
/* The Std output win should go in bottem */
/* Make all the subwindows */
int outy=1;
/* The Register window */
dbg.win_reg=subwin(dbg.win_main,4,dbg.win_main->_maxx,outy,0);
outy+=5;
/* The Data Window */
dbg.win_data=subwin(dbg.win_main,10,dbg.win_main->_maxx,outy,0);
outy+=11;
/* The Code Window */
dbg.win_code=subwin(dbg.win_main,10,dbg.win_main->_maxx,outy,0);
outy+=11;
/* The output Window */
dbg.win_out=subwin(dbg.win_main,dbg.win_main->_maxy-outy-1,dbg.win_main->_maxx,outy,0);
dbg.input_y=dbg.win_main->_maxy-1;
scrollok(dbg.win_out,TRUE);
DrawBars();
Draw_RegisterLayout();
refresh();
}
static void MakePairs(void) {
init_pair(PAIR_BLACK_BLUE, COLOR_BLACK, COLOR_CYAN);
init_pair(PAIR_BYELLOW_BLACK, COLOR_YELLOW /*| FOREGROUND_INTENSITY */, COLOR_BLACK);
}
void DBGUI_StartUp(void) {
/* Start the main window */
dbg.win_main=initscr();
cbreak(); /* take input chars one at a time, no wait for \n */
noecho(); /* don't echo input */
nodelay(dbg.win_main,true);
keypad(dbg.win_main,true);
cycle_count=0;
MakePairs();
MakeSubWindows();
}
#endif

52
src/debug/debug_inc.h Normal file
View file

@ -0,0 +1,52 @@
/*
* 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.
*/
/* Local Debug Function */
#include <curses.h>
#include "mem.h"
#define PAIR_BLACK_BLUE 1
#define PAIR_BYELLOW_BLACK 2
void DBGUI_StartUp(void);
struct DBGBlock {
WINDOW * win_main; /* The Main Window */
WINDOW * win_reg; /* Register Window */
WINDOW * win_data; /* Data Output window */
WINDOW * win_code; /* Disassembly/Debug point Window */
WINDOW * win_out; /* Text Output Window */
Bit32u active_win; /* Current active window */
Bit32u input_y;
};
struct DASMLine {
Bit32u pc;
char dasm[80];
PhysPt ea;
Bit16u easeg;
Bit32u eaoff;
};
extern DBGBlock dbg;
/* Local Debug Stuff */
Bitu DasmI386(char* buffer, PhysPt pc, Bitu cur_ip, bool bit32);

74
src/debug/debug_win32.cpp Normal file
View file

@ -0,0 +1,74 @@
/*
* 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 <windows.h>
#include <stdio.h>
#include <stdarg.h>
/*
Have to remember where i ripped this code sometime ago.
*/
static void ResizeConsole( HANDLE hConsole, SHORT xSize, SHORT ySize ) {
CONSOLE_SCREEN_BUFFER_INFO csbi; // Hold Current Console Buffer Info
BOOL bSuccess;
SMALL_RECT srWindowRect; // Hold the New Console Size
COORD coordScreen;
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
// Get the Largest Size we can size the Console Window to
coordScreen = GetLargestConsoleWindowSize( hConsole );
// Define the New Console Window Size and Scroll Position
srWindowRect.Right = (SHORT)(min(xSize, coordScreen.X) - 1);
srWindowRect.Bottom = (SHORT)(min(ySize, coordScreen.Y) - 1);
srWindowRect.Left = srWindowRect.Top = (SHORT)0;
// Define the New Console Buffer Size
coordScreen.X = xSize;
coordScreen.Y = ySize;
// If the Current Buffer is Larger than what we want, Resize the
// Console Window First, then the Buffer
if( (DWORD)csbi.dwSize.X * csbi.dwSize.Y > (DWORD) xSize * ySize)
{
bSuccess = SetConsoleWindowInfo( hConsole, TRUE, &srWindowRect );
bSuccess = SetConsoleScreenBufferSize( hConsole, coordScreen );
}
// If the Current Buffer is Smaller than what we want, Resize the
// Buffer First, then the Console Window
if( (DWORD)csbi.dwSize.X * csbi.dwSize.Y < (DWORD) xSize * ySize )
{
bSuccess = SetConsoleScreenBufferSize( hConsole, coordScreen );
bSuccess = SetConsoleWindowInfo( hConsole, TRUE, &srWindowRect );
}
// If the Current Buffer *is* the Size we want, Don't do anything!
return;
}
void WIN32_Console() {
ResizeConsole(GetStdHandle(STD_OUTPUT_HANDLE),80,50);
}

191
src/debug/disasm_tables.h Normal file
View file

@ -0,0 +1,191 @@
/*
* 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.
*/
char * RegTable_16[8]= {"ax","cx","dx","bx","sp","bp","si","di"};
char * RegTable_8[8]= {"al","cl","dl","bl","ah","ch","dh","bh"};
char * SegTable[8]= {"es","cs","ss","ds","fs","gs","iseg","iseg"};
#define MAX_INFO 3
enum {
Eb,Ev,Ew,Ep,
Gb,Gv,
Rb,Rw,Rv,
Ob,Ov,
Sw,
Mp,
Ib,Ibs,Iw,Iv,Ap,
Jb,Jv,
Bd,Bw,
XBnd,Xlea,
/* specials */
b2,p_es,p_ss,p_cs,p_ds,p_fs,p_gs,p_size,p_addr,p_rep,
s_ax,s_cx,s_dx,s_bx,s_sp,s_bp,s_si,s_di,
s_al,s_cl,s_dl,s_bl,s_ah,s_ch,s_dh,s_bh,
s_1,
Cj,
G1,G2,G3b,G3v,G4,G5,
no=0xff
};
enum {
s_jo, s_jno, s_jc, s_jnc, s_je, s_jne, s_jbe, s_jnbe,
s_js, s_jns, s_jp, s_jnp, s_jl, s_jnl, s_jle, s_jnle
};
struct Dentry {
char * start;
Bit8u info[MAX_INFO];
};
static char * G1_Table[8]={"add ","or ","adc ","sbb ","and ","sub ","xor ","cmp "};
static char * G2_Table[8]={"rol ","ror ","rcl ","rcr ","shl ","shr ","sal ","sar "};
static Dentry G3b_Table[8]={
"test ",Eb,Ib,no,
"test ",Eb,Ib,no,
"not ",Eb,no,no,
"neg ",Eb,no,no,
"mul al,",Eb,no,no,
"imul al,",Eb,no,no,
"div ax,",Eb,no,no,
"idiv ax,",Eb,no,no
};
static Dentry G3v_Table[8]={
"test ",Ev,Iv,no,
"test ",Ev,Iv,no,
"not ",Ev,no,no,
"neg ",Ev,no,no,
"mul ax,",Ev,no,no,
"imul ax,",Ev,no,no,
"div dx:ax,",Ev,no,no,
"idiv dx:ax,",Ev,no,no
};
static char * G4_Table[8]={
"inc ",
"dec ",
"illegal",
"illegal",
"illegal",
"illegal",
"illegal",
"illegal"
};
static Dentry G5_Table[8]={
"inc ",Ev,no,no,
"dec ",Ev,no,no,
"call ",Ev,no,no,
"call ",Ep,no,no,
"jmp ",Ev,no,no,
"jmp ",Ep,no,no,
"push ,",Ev,no,no,
"illegal",no,no,no
};
static Dentry DTable[256]={
/* 0 */
"add ",Eb,Gb,no, "add ",Ev,Gv,no, "add ",Gb,Eb,no, "add ",Gv,Ev,no,
"add ",s_al,Ib,no, "add ",s_ax,Iv,no, "push es",no,no,no, "pop es",no,no,no,
"or ",Eb,Gb,no, "or ",Ev,Gv,no, "or ",Gb,Eb,no, "or ",Gv,Ev,no,
"or ",s_al,Ib,no, "or ",s_ax,Iv,no, "push cs",no,no,no, "",b2,no,no,
/* 1 */
"adc ",Eb,Gb,no, "adc ",Ev,Gv,no, "adc ",Gb,Eb,no, "adc ",Gv,Ev,no,
"adc ",s_al,Ib,no, "adc ",s_ax,Iv,no, "push ss",no,no,no, "pop ss",no,no,no,
"sbb ",Eb,Gb,no, "sbb ",Ev,Gv,no, "sbb ",Gb,Eb,no, "sbb ",Gv,Ev,no,
"sbb ",s_al,Ib,no, "sbb ",s_ax,Iv,no, "push ds",no,no,no, "pop ds",no,no,no,
/* 2 */
"and ",Eb,Gb,no, "and ",Ev,Gv,no, "and ",Gb,Eb,no, "and ",Gv,Ev,no,
"and ",s_al,Ib,no, "and ",s_ax,Iv,no, "",p_es,no,no, "daa",no,no,no,
"sub ",Eb,Gb,no, "sub ",Ev,Gv,no, "sub ",Gb,Eb,no, "sub ",Gv,Ev,no,
"sub ",s_al,Ib,no, "sub ",s_ax,Iv,no, "",p_ss,no,no, "das",no,no,no,
/* 3 */
"xor ",Eb,Gb,no, "xor ",Ev,Gv,no, "xor ",Gb,Eb,no, "xor ",Gv,Ev,no,
"xor ",s_al,Ib,no, "xor ",s_ax,Iv,no, "",p_ss,no,no, "aaa",no,no,no,
"cmp ",Eb,Gb,no, "cmp ",Ev,Gv,no, "cmp ",Gb,Eb,no, "cmp ",Gv,Ev,no,
"cmp ",s_al,Ib,no, "cmp ",s_ax,Iv,no, "",p_ds,no,no, "aas",no,no,no,
/* 4 */
"inc ",s_ax,no,no, "inc ",s_cx,no,no, "inc ",s_dx,no,no, "inc ",s_bx,no,no,
"inc ",s_sp,no,no, "inc ",s_bp,no,no, "inc ",s_si,no,no, "inc ",s_di,no,no,
"dec ",s_ax,no,no, "dec ",s_cx,no,no, "dec ",s_dx,no,no, "dec ",s_bx,no,no,
"dec ",s_sp,no,no, "dec ",s_bp,no,no, "dec ",s_si,no,no, "dec ",s_di,no,no,
/* 5 */
"push ",s_ax,no,no, "push ",s_cx,no,no, "push ",s_dx,no,no, "push ",s_bx,no,no,
"push ",s_sp,no,no, "push ",s_bp,no,no, "push ",s_si,no,no, "push ",s_di,no,no,
"pop ",s_ax,no,no, "pop ",s_cx,no,no, "pop ",s_dx,no,no, "pop ",s_bx,no,no,
"pop ",s_sp,no,no, "pop ",s_bp,no,no, "pop ",s_si,no,no, "pop ",s_di,no,no,
/* 6 */
"pusha",Bd,no,no, "popa",Bd,no,no, "bound",XBnd,no,no, "arpl",Ew,Rw,no,
"",p_fs,no,no, "",p_gs,no,no, "",p_size,no,no, "",p_addr,no,no,
"push ",Iv,no,no, "imul ",Gv,Ev,Iv, "push ",Ibs,no,no, "imul ",Gv,Ev,Ib,
"insb",no,no,no, "ins",Bw,no,no, "oustb",no,no,no, "outs",Bw,no,no,
/* 7 */
"jo ",Cj,s_jo,no, "jno ",Cj,s_jno,no, "jc ",Cj,s_jc,no, "jnc ",Cj,s_jnc,no,
"je ",Cj,s_je,no, "jne ",Cj,s_jne,no, "jbe ",Cj,s_jbe,no, "jnbe ",Cj,s_jnbe,no,
"js ",Cj,s_js,no, "jns ",Cj,s_jns,no, "jp ",Cj,s_jp,no, "jnp ",Cj,s_jnp,no,
"jl ",Cj,s_jl,no, "jnl ",Cj,s_jnl,no, "jle ",Cj,s_jle,no, "jnle ",Cj,s_jnle,no,
/* 8 */
"",G1,Eb,Ib, "",G1,Ev,Iv, "",G1,Eb,Ib, "",G1,Ev,Ibs,
"test ",Eb,Gb,no, "test ",Ev,Gv,no, "xchg ",Eb,Gb,no, "xchg ",Ev,Gv,no,
"mov ",Eb,Gb,no, "mov ",Ev,Gv,no, "mov ",Gb,Eb,no, "mov ",Gv,Ev,no,
"mov ",Ew,Sw,no, "lea ",Gv,Xlea,no, "mov ",Sw,Ew,no, "pop ",Ev,no,no,
/* 9 */
"nop",no,no,no, "xchg ",s_ax,s_cx,no,"xchg ",s_ax,s_dx,no,"xchg ",s_ax,s_bx,no,
"xchg ",s_ax,s_sp,no,"xchg ",s_ax,s_bp,no,"xchg ",s_ax,s_si,no,"xchg ",s_ax,s_di,no,
"cbw",no,no,no, "cwd",no,no,no, "call ",Ap,no,no, "fwait",no,no,no,
"pushf",Bd,no,no, "popf",Bd,no,no, "sahf",no,no,no, "lahf",no,no,no,
/* a */
"mov ",s_al,Ob,no, "mov ",s_ax,Ov,no, "mov ",Ob,s_al,no, "mov ",Ov,s_ax,no,
"movsb",no,no,no, "movs",Bw,no,no, "cmpsb",no,no,no, "cmps",Bw,no,no,
"test ",s_al,Ib,no, "test ",s_ax,Iv,no, "stosb",no,no,no, "stos",Bw,no,no,
"lodsb",no,no,no, "lods",Bw,no,no, "scasb",no,no,no, "scas",Bw,no,no,
/* b */
"mov ",s_al,Ib,no, "mov ",s_cl,Ib,no, "mov ",s_dl,Ib,no, "mov ",s_bl,Ib,no,
"mov ",s_ah,Ib,no, "mov ",s_ch,Ib,no, "mov ",s_dh,Ib,no, "mov ",s_bh,Ib,no,
"mov ",s_ax,Iv,no, "mov ",s_cx,Iv,no, "mov ",s_dx,Iv,no, "mov ",s_bx,Iv,no,
"mov ",s_sp,Iv,no, "mov ",s_bp,Iv,no, "mov ",s_si,Iv,no, "mov ",s_di,Iv,no,
/* c */
"",G2,Eb,Ib, "",G2,Ev,Ib, "ret ",Iw,no,no, "ret",no,no,no,
"les ",Gv,Mp,no, "lds ",Gv,Mp,no, "mov ",Eb,Ib,no, "mov ",Ev,Iv,no,
"enter ",Iw,Ib,no, "leave",no,no,no, "retf ",Iw,no,no, "retf",no,no,no,
"int 03",no,no,no, "int ",Ib,no,no, "into",no,no,no, "iret",Bd,no,no,
/* d */
"",G2,Eb,s_1, "",G2,Ev,s_1, "",G2,Eb,s_cl, "",G2,Ev,s_cl,
"aam",no,no,no, "aad",no,no,no, "setalc",no,no,no, "xlat",no,no,no,
"esc 0",Ib,no,no, "esc 1",Ib,no,no, "esc 2",Ib,no,no, "esc 3",Ib,no,no,
"esc 4",Ib,no,no, "esc 5",Ib,no,no, "esc 6",Ib,no,no, "esc 7",Ib,no,no,
/* e */
"loopne ",Jb,no,no, "loope ",Jb,no,no, "loop ",Jb,no,no, "jcxz ",Jb,no,no,
"in ",s_al,Ib,no, "in ",s_ax,Ib,no, "out ",Ib,s_al,no, "out ",Ib,s_ax,no,
"call ",Jv,no,no, "jmp ",Jv,no,no, "jmp",Ap,no,no, "jmp ",Jb,no,no,
"in ",s_al,s_dx,no, "in ",s_ax,s_dx,no, "out ",s_dx,s_al,no,"out ",s_dx,s_ax,no,
/* f */
"lock",no,no,no, "cb ",Iw,no,no, "repne ",p_rep,no,no,"repe ",p_rep,no,no,
"hlt",no,no,no, "cmc",no,no,no, "",G3b,no,no, "",G3v,no,no,
"clc",no,no,no, "stc",no,no,no, "cli",no,no,no, "sti",no,no,no,
"cld",no,no,no, "std",no,no,no, "",G4,Eb,no, "",G5,no,no,
};

7
src/dos/Makefile.am Normal file
View file

@ -0,0 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libdos.a
libdos_a_SOURCES = dos.cpp dos_devices.cpp dos_execute.cpp dos_files.cpp dos_ioctl.cpp dos_memory.cpp \
dos_misc.cpp dos_classes.cpp dos_programs.cpp dos_tables.cpp \
drives.cpp drives.h drive_virtual.cpp drive_local.cpp \
dev_con.h

105
src/dos/dev_con.h Normal file
View file

@ -0,0 +1,105 @@
/*
* 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.
*/
class device_CON : public DOS_Device {
public:
device_CON();
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
Bit8u cache;
};
bool device_CON::Read(Bit8u * data,Bit16u * size) {
Bit16u oldax=reg_ax;
Bit16u count=0;
if ((cache) && (*size)) {
data[count++]=cache;
cache=0;
}
while (*size>count) {
reg_ah=0;
CALLBACK_RunRealInt(0x16);
switch(reg_al) {
case 13:
data[count++]=0x0D;
// if (*size>count) data[count++]=0x0A;
// else cache=0x0A;
*size=count;
reg_ax=oldax;
return true;
default:
data[count++]=reg_al;
break;
case 0:
data[count++]=reg_al;
if (*size>count) data[count++]=reg_ah;
else cache=reg_ah;
break;
}
}
*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) {
//TODO Hack a way to call int 0x10
Bit16u oldax=reg_ax;Bit16u oldbx=reg_bx;
Bit16u count=0;
while (*size>count) {
/*
reg_al=data[count];
reg_ah=0x0e;
reg_bx=0x0007;
CALLBACK_RunRealInt(0x10);
*/
INT10_TeletypeOutput(data[count],7,false,0);
count++;
}
*size=count;
// reg_ax=oldax;reg_bx=oldbx;
return true;
}
bool device_CON::Seek(Bit32u * pos,Bit32u type) {
return false;
}
bool device_CON::Close() {
return false;
}
Bit16u device_CON::GetInformation(void) {
Bit16u head=mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
Bit16u tail=mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
if ((head==tail) && !cache) return 0x80D3; /* No Key Available */
return 0x8093; /* Key Available */
};
device_CON::device_CON() {
name="CON";
cache=0;
}

790
src/dos/dos.cpp Normal file
View file

@ -0,0 +1,790 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "dosbox.h"
#include "bios.h"
#include "mem.h"
#include "callback.h"
#include "regs.h"
#include "dos_inc.h"
DOS_Block dos;
static Bit8u dos_copybuf[0x10000];
static Bitu call_20,call_21,call_theend;
void DOS_SetError(Bit16u code) {
dos.errorcode=code;
};
#define DOSNAMEBUF 256
static Bitu DOS_21Handler(void) {
//TODO KEYBOARD Check for break
char name1[DOSNAMEBUF+1];
char name2[DOSNAMEBUF+1];
switch (reg_ah) {
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_ReadFile(STDIN,&c,&n);
reg_al=c;
DOS_WriteFile(STDOUT,&c,&n);
}
break;
case 0x02: /* Write character to STDOUT */
{
Bit8u c=reg_dl;Bit16u n=1;
DOS_WriteFile(STDOUT,&c,&n);
}
break;
case 0x03: /* Read character from STDAUX */
case 0x04: /* Write Character to STDAUX */
case 0x05: /* Write Character to PRINTER */
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
case 0x06: /* Direct Console Output / Input */
switch (reg_dl) {
case 0xFF: /* Input */
{
//TODO Make this better according to standards
if (!DOS_GetSTDINStatus()) {
CALLBACK_SZF(true);
break;
}
Bit8u c;Bit16u n=1;
DOS_ReadFile(STDIN,&c,&n);
reg_al=c;
CALLBACK_SZF(false);
break;
}
default:
{
Bit8u c=reg_dl;Bit16u n=1;
DOS_WriteFile(STDOUT,&c,&n);
}
break;
};
break;
case 0x07: /* Character Input, without echo */
{
Bit8u c;Bit16u n=1;
DOS_ReadFile (STDIN,&c,&n);
reg_al=c;
break;
};
case 0x08: /* Direct Character Input, without echo */
{
Bit8u c;Bit16u n=1;
DOS_ReadFile (STDIN,&c,&n);
reg_al=c;
break;
};
case 0x09: /* Write string to STDOUT */
{
Bit8u c;Bit16u n=1;
PhysPt buf=real_phys(Segs[ds].value,reg_dx);
while ((c=mem_readb(buf++))!='$') {
DOS_WriteFile(STDOUT,&c,&n);
}
}
break;
case 0x0a: /* Buffered Input */
{
//TODO ADD Break checkin in STDIN but can't care that much for it
PhysPt data=real_phys(Segs[ds].value,reg_dx);
Bit8u free=mem_readb(data);
Bit8u read=0;Bit8u c;Bit16u n=1;
if (!free) break;
while (read<free) {
DOS_ReadFile(STDIN,&c,&n);
DOS_WriteFile(STDOUT,&c,&n);
if (c==13) {
DOS_ReadFile(STDIN,&c,&n);
break;
}
mem_writeb(data+read+2,c);
read++;
};
mem_writeb(data+1,read);
break;
};
case 0x0b: /* Get STDIN Status */
if (DOS_GetSTDINStatus()) reg_al=0xff;
else reg_al=0;
break;
case 0x0c: /* Flush Buffer and read STDIN call */
{
switch (reg_al) {
case 0x1:
case 0x6:
case 0x7:
case 0x8:
case 0xa:
{
Bit8u oldah=reg_ah;
reg_ah=reg_al;
DOS_21Handler();
reg_ah=oldah;
}
break;
default:
LOG_ERROR("DOS:0C:Illegal Flush STDIN Buffer call %d",reg_al);
break;
}
}
break;
//TODO Find out the values for when reg_al!=0
//TODO Hope this doesn't do anything special
case 0x0d: /* Disk Reset */
//Sure let's reset a virtual disk
break;
case 0x0e: /* Select Default Drive */
DOS_SetDefaultDrive(reg_dl);
reg_al=26;
break;
case 0x0f: /* Open File using FCB */
case 0x10: /* Close File using FCB */
case 0x11: /* Find First Matching File using FCB */
case 0x12: /* Find Next Matching File using FCB */
case 0x13: /* Delete File using FCB */
case 0x14: /* Sequential read from FCB */
case 0x15: /* Sequential write to FCB */
case 0x16: /* Create or truncate file using FCB */
case 0x17: /* Rename file using FCB */
case 0x21: /* Read random record from FCB */
case 0x22: /* Write random record to FCB */
case 0x23: /* Get file size for FCB */
case 0x24: /* Set Random Record number for FCB */
case 0x27: /* Random block read from FCB */
case 0x28: /* Random Block read to FCB */
LOG_ERROR("DOS:Unhandled call %02X, FCB Stuff",reg_ah);
reg_al=0xff; /* FCB Calls FAIL */
CALLBACK_SCF(true);
break;
case 0x29: /* Parse filename into FCB */
//TODO Give errors for unsupported functions
{
MEM_StrCopy(real_phys(Segs[ds].value,reg_si),name1,DOSNAMEBUF);
/* only detect the call program use to detect the existence of a harddisk */
if ((strlen((char *)name1)==2) && (name1[1]==':')) {
Bit8u drive=toupper(name1[0])-'A';
if (Drives[drive]) reg_al=0;
else reg_al=0xff;
break;
}
LOG_DEBUG("DOS:29:FCB Parse Filename:%s",name1);
};
reg_al=0xff; /* FCB Calls FAIL */
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;
case 0x1a: /* Set Disk Transfer Area Address */
//TODO find out what a DTA does
dos.dta=RealMake(Segs[ds].value,reg_dx);
break;
case 0x1c: /* Get allocation info for specific drive */
LOG_DEBUG("DOS: Allocation Info call not supported correctly");
SetSegment_16(ds,0xf000);
reg_bx=0;
real_writeb(0xf000,0,0);
reg_al=0x7f;
reg_cx=0x200;
reg_dx=0x1000;
break; /* TODO maybe but hardly think a game needs this */
case 0x1b: /* Get allocation info for default drive */
LOG_DEBUG("DOS: Allocation Info call not supported correctly");
SetSegment_16(ds,0xf000);
reg_bx=0;
real_writeb(0xf000,0,0);
reg_al=0x7f;
reg_cx=0x200;
reg_dx=0x1000;
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 */
case 0x25: /* Set Interrupt Vector */
RealSetVec(reg_al,RealMake(Segs[ds].value,reg_dx));
break;
case 0x26: /* Create new PSP */
DOS_NewPSP(reg_dx);
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;
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;}
dos.date.year=reg_cx;
dos.date.month=reg_dh;
dos.date.day=reg_dl;
reg_al=0;
break;
case 0x2c: /* Get System Time */
//TODO Get time through bios calls date is fixed
{
Bit32u ticks=mem_readd(BIOS_TIMER);
Bit32u seconds=(ticks*10)/182;
reg_ch=(Bit8u)(seconds/3600);
reg_cl=(Bit8u)(seconds % 3600)/60;
reg_dh=(Bit8u)(seconds % 60);
reg_dl=(Bit8u)(ticks % 19)*5;
}
break;
case 0x2d: /* Set System Time */
LOG_DEBUG("DOS:Set System Time not supported");
reg_al=0; /* Noone is changing system time */
break;
case 0x2e: /* Set Verify flag */
dos.verify=(reg_al==1);
break;
case 0x2f: /* Get Disk Transfer Area */
SetSegment_16(es,RealSeg(dos.dta));
reg_bx=RealOff(dos.dta);
break;
case 0x30: /* Get DOS Version */
if (reg_al==0) reg_bh=0xFF; /* Fake Microsoft DOS */
if (reg_al==1) reg_bh=0x10; /* DOS is in HMA */
reg_al=dos.version.major;
reg_ah=dos.version.minor;
break;
case 0x31: /* Terminate and stay resident */
//TODO First get normal files executing
DOS_ResizeMemory(dos.psp,&reg_dx);
if (DOS_Terminate(true)) {
dos.return_code=reg_al;
dos.return_mode=RETURN_TSR;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x33: /* Extended Break Checking */
switch (reg_al) {
case 0:reg_dl=dos.breakcheck;break; /* Get the breakcheck flag */
case 1:dos.breakcheck=(reg_dl>0);break; /* Set the breakcheck flag */
case 2:{bool old=dos.breakcheck;dos.breakcheck=(reg_dl>0);reg_dl=old;}break;
case 5:reg_dl=3;break; /* Always boot from c: :) */
case 6: /* Get true version number */
reg_bl=dos.version.major;
reg_bh=dos.version.minor;
reg_dl=dos.version.revision;
reg_dh=0x10; /* Dos in HMA */
break;
default:
E_Exit("DOS:Illegal 0x33 Call %2X",reg_al);
}
break;
case 0x34: /* Get INDos Flag */
SetSegment_16(es,RealSeg(dos.tables.indosflag));
reg_bx=RealOff(dos.tables.indosflag);
break;
case 0x35: /* Get interrupt vector */
reg_bx=real_readw(0,((Bit16u)reg_al)*4);
SetSegment_16(es,real_readw(0,((Bit16u)reg_al)*4+2));
break;
case 0x36: /* Get Free Disk Space */
{
Bit16u bytes,sectors,clusters,free;
if (DOS_GetFreeDiskSpace(reg_dl,&bytes,&sectors,&clusters,&free)) {
reg_ax=sectors;
reg_bx=free;
reg_cx=bytes;
reg_dx=clusters;
} else {
reg_ax=0xffff;
}
}
break;
case 0x37: /* Get/Set Switch char Get/Set Availdev thing */
//TODO Give errors for these functions to see if anyone actually uses this shit-
switch (reg_al) {
case 0:
reg_al=0;reg_dl=0x2f;break; /* always return '/' like dos 5.0+ */
case 1:
reg_al=0;break;
case 2:
reg_al=0;reg_dl=0x2f;break;
case 3:
reg_al=0;break;
};
LOG_DEBUG("DOS:0x37:Call for not supported switchchar");
break;
case 0x38: /* Set Country Code */
LOG_DEBUG("DOS:Setting country code not supported");
CALLBACK_SCF(true);
break;
if (reg_al==0) { /* Get country specidic information */
} else { /* Set country code */
}
break;
case 0x39: /* MKDIR Create directory */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_MakeDir(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3a: /* RMDIR Remove directory */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_RemoveDir(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3b: /* CHDIR Set current directory */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_ChangeDir(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3c: /* CREATE Create of truncate file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_CreateFile(name1,reg_cx,&reg_ax)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3d: /* OPEN Open existing file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_OpenFile(name1,reg_al,&reg_ax)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3e: /* CLOSE Close file */
if (DOS_CloseFile(reg_bx)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x3f: /* READ Read from file or device */
{
Bit16u toread=reg_cx;
if (DOS_ReadFile(reg_bx,dos_copybuf,&toread)) {
MEM_BlockWrite(real_phys(Segs[ds].value,reg_dx),dos_copybuf,toread);
reg_ax=toread;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
}
case 0x40: /* WRITE Write to file or device */
{
Bit16u towrite=reg_cx;
MEM_BlockRead(real_phys(Segs[ds].value,reg_dx),dos_copybuf,towrite);
if (DOS_WriteFile(reg_bx,dos_copybuf,&towrite)) {
reg_ax=towrite;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
};
case 0x41: /* UNLINK Delete file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_UnlinkFile(name1)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x42: /* LSEEK Set current file position */
{
Bit32u pos=(reg_cx<<16) + reg_dx;
if (DOS_SeekFile(reg_bx,&pos,reg_al)) {
reg_dx=(Bit16u)(pos >> 16);
reg_ax=(Bit16u)(pos & 0xFFFF);
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
}
case 0x43: /* Get/Set file attributes */
//TODO FIX THIS HACK
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
switch (reg_al)
case 0x00: /* Get */
{
if (DOS_GetFileAttr(name1,&reg_cx)) {
CALLBACK_SCF(false);
} else {
CALLBACK_SCF(true);
reg_ax=dos.errorcode;
}
break;
case 0x01: /* Set */
LOG_DEBUG("DOS:Set File Attributes for %s not supported",name1);
CALLBACK_SCF(false);
break;
default:
E_Exit("DOS:0x43:Illegal subfunction %2X",reg_al);
}
break;
case 0x44: /* IOCTL Functions */
if (DOS_IOCTL(reg_al,reg_bx)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x45: /* DUP Duplicate file handle */
if (DOS_DuplicateEntry(reg_bx,&reg_ax)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x46: /* DUP2,FORCEDUP Force duplicate file handle */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x47: /* CWD Get current directory */
//TODO Memory
if (DOS_GetCurrentDir(reg_dl,real_off(Segs[ds].value,reg_si))) {
reg_ax=0x0100;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x48: /* Allocate memory */
{
Bit16u size=reg_bx;Bit16u seg;
if (DOS_AllocateMemory(&seg,&size)) {
reg_ax=seg;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
reg_bx=size;
CALLBACK_SCF(true);
}
break;
}
case 0x49: /* Free memory */
if (DOS_FreeMemory(Segs[es].value)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x4a: /* Resize memory block */
{
Bit16u size=reg_bx;
if (DOS_ResizeMemory(Segs[es].value,&size)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
reg_bx=size;
CALLBACK_SCF(true);
}
break;
}
case 0x4b: /* EXEC Load and/or execute program */
{
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_Execute(name1,(ParamBlock *)real_off(Segs[es].value,reg_bx),reg_al)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
}
break;
//TODO Check for use of execution state AL=5
case 0x4c: /* EXIT Terminate with return code */
{
if (DOS_Terminate(false)) {
dos.return_code=reg_al;
dos.return_mode=RETURN_EXIT;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
}
case 0x4d: /* Get Return code */
reg_al=dos.return_code;
reg_ah=dos.return_mode;
break;
case 0x4e: /* FINDFIRST Find first matching file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_FindFirst(name1,reg_cx)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
};
break;
case 0x4f: /* FINDNEXT Find next matching file */
if (DOS_FindNext()) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
};
break;
case 0x50: /* Set current PSP */
dos.psp=reg_bx;
break;
case 0x51: /* Get current PSP */
reg_bx=dos.psp;
break;
case 0x52: /* Get list of lists */
SetSegment_16(es,0);
reg_bx=0;
LOG_ERROR("Call is made for list of lists not supported let's hope for the best");
break;
//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
case 0x54: /* Get verify flag */
case 0x55: /* Create Child PSP*/
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x56: /* RENAME Rename file */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
MEM_StrCopy(real_phys(Segs[es].value,reg_di),name2,DOSNAMEBUF);
if (DOS_Rename(name1,name2)) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
case 0x57: /* Get/Set File's Date and Time */
reg_cx=0;
reg_dx=0;
LOG_DEBUG("DOS:57:Getting/Setting File Date is faked",reg_ah);
break;
case 0x58: /* Get/Set Memory allocation strategy */
LOG_DEBUG("DOS:58:Not Supported Set//Get memory allocation");
break;
case 0x59: /* Get Extended error information */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x5a: /* Create temporary file */
{
Bit16u handle;
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_CreateTempFile(name1,&handle)) {
reg_ax=handle;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
}
break;
case 0x5b: /* Create new file */
{
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
Bit16u handle;
if (DOS_OpenFile(name1,0,&handle)) {
DOS_CloseFile(handle);
DOS_SetError(DOSERR_ACCESS_DENIED);
reg_ax=dos.errorcode;
CALLBACK_SCF(false);
break;
}
if (DOS_CreateFile(name1,reg_cx,&handle)) {
reg_ax=handle;
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
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);
break;
case 0x60: /* Canonicalize filename or path */
MEM_StrCopy(real_phys(Segs[ds].value,reg_dx),name1,DOSNAMEBUF);
if (DOS_Canonicalize(name1,real_off(Segs[es].value,reg_di))) {
CALLBACK_SCF(false);
} else {
reg_ax=dos.errorcode;
CALLBACK_SCF(true);
}
break;
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;
case 0x65: /* Get extented country information and a lot of other useless shit*/
/* Todo maybe fully support this for now we set it standard for USA */
{
LOG_DEBUG("DOS:65:Extended country information call");
Bit8u * data=real_off(Segs[es].value,reg_di);
switch (reg_al) {
case 1:
real_writeb(Segs[es].value,reg_di,reg_al);
real_writew(Segs[es].value,reg_di+1,4);
real_writew(Segs[es].value,reg_di+3,1);
real_writew(Segs[es].value,reg_di+5,37);
reg_cx=4;
CALLBACK_SCF(false);
break;
default:
E_Exit("DOS:0x65:Unhandled country information call %2X",reg_al);
};
break;
}
case 0x66: /* Get/Set global code page table */
if (reg_al==1) {
LOG_DEBUG("Getting global code page table");
reg_bx=reg_dx=437;
CALLBACK_SCF(false);
break;
}
LOG_ERROR("DOS:Setting code page table is not supported");
break;
case 0x67: /* Set handle countr */
/* Weird call to increase amount of file handles needs to allocate memory if >20 */
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 */
{
Bit8u * temp=real_off(Segs[ds].value,reg_dx);
switch(reg_al) {
case 0x00: /* Get */
LOG_DEBUG("DOS:Get Disk serial number");
CALLBACK_SCF(true);
break;
case 0x01:
LOG_DEBUG("DOS:Set Disk serial number");
default:
E_Exit("DOS:Illegal Get Serial Number call %2X",reg_al);
}
break;
}
case 0x6c: /* Extended Open/Create */
E_Exit("Unhandled Dos 21 call %02X",reg_ah);
break;
case 0x71: /* Unknown probably 4dos detection */
reg_ax=0x7100;
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;
default:
E_Exit("DOS:Unhandled call %02X",reg_ah);
break;
};
return CBRET_NONE;
/* That's it now let's get it working */
};
static Bitu DOS_20Handler(void) {
reg_ax=0x4c00;
DOS_21Handler();
return CBRET_NONE;
}
void DOS_Init(void) {
call_20=CALLBACK_Allocate();
CALLBACK_Setup(call_20,DOS_20Handler,CB_IRET);
RealSetVec(0x20,CALLBACK_RealPointer(call_20));
call_21=CALLBACK_Allocate();
CALLBACK_Setup(call_21,DOS_21Handler,CB_IRET);
RealSetVec(0x21,CALLBACK_RealPointer(call_21));
DOS_SetupFiles(); /* Setup system File tables */
DOS_SetupDevices(); /* Setup dos devices */
DOS_SetupMemory(); /* Setup first MCB */
DOS_SetupTables();
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);
};

181
src/dos/dos_classes.cpp Normal file
View file

@ -0,0 +1,181 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include "dosbox.h"
#include "mem.h"
#include "dos_inc.h"
/*
Work in progress, making classes for handling certain internal memory structures in dos
This should make it somewhat easier for porting to other endian machines and make
dos work a bit easier.
*/
struct sPSP {
Bit8u exit[2]; /* CP/M-like exit poimt */
Bit16u next_seg; /* Segment of first byte beyond memory allocated or program */
Bit8u fill_1; /* single char fill */
/* CPM Stuff dunno what this is*/
//TODO Add some checks for people using this i think
Bit8u far_call; /* far call opcode */
RealPt cpm_entry; /* CPM Service Request address*/
RealPt int_22; /* Terminate Address */
RealPt int_23; /* Break Address */
RealPt int_24; /* Critical Error Address */
Bit16u psp_parent; /* Parent PSP Segment */
Bit8u files[20]; /* File Table - 0xff is unused */
Bit16u environment; /* Segment of evironment table */
RealPt stack; /* SS:SP Save point for int 0x21 calls */
Bit16u max_files; /* Maximum open files */
RealPt file_table; /* Pointer to File Table PSP:0x18 */
RealPt prev_psp; /* Pointer to previous PSP */
RealPt dta; /* Pointer to current Process DTA */
Bit8u fill_2[16]; /* Lot's of unused stuff i can't care aboue */
Bit8u service[3]; /* INT 0x21 Service call int 0x21;retf; */
Bit8u fill_3[45]; /* This has some blocks with FCB info */
CommandTail cmdtail;
};
class DOS_PSP {
public:
DOS_PSP(Bit16u segment);
void MakeNew(Bit16u env,Bit16u memsize);
Bit16u base_seg;
private:
PhysPt off;
};
DOS_PSP::DOS_PSP(Bit16u segment) {
base_seg=segment;
off=Real2Phys(RealMake(segment,0));
};
void DOS_PSP::MakeNew(Bit16u env,Bit16u next_para) {
Bitu i;
for (i=0;i<256;i++) mem_writeb(off+i,0);
/* Standard blocks */
mem_writeb(off+offsetof(sPSP,exit[0]),0xcd);
mem_writeb(off+offsetof(sPSP,exit[1]),0x20);
mem_writeb(off+offsetof(sPSP,service[0]),0xcd);
mem_writeb(off+offsetof(sPSP,service[1]),0x21);
mem_writeb(off+offsetof(sPSP,service[2]),0xcb);
mem_writew(off+offsetof(sPSP,next_seg),next_para);
// mem_writew(off+offsetof(sPSP,psp_parent),dos.psp->base_seg);
/* Setup initial file table */
mem_writed(off+offsetof(sPSP,int_22),RealGetVec(0x22));
mem_writed(off+offsetof(sPSP,int_23),RealGetVec(0x23));
mem_writed(off+offsetof(sPSP,int_24),RealGetVec(0x24));
#if 0
newpsp->mem_size=prevpsp->mem_size;
newpsp->environment=0;
newpsp->int_22.full=real_getvec(0x22);
newpsp->int_23.full=real_getvec(0x23);
newpsp->int_24.full=real_getvec(0x24);
newpsp->psp_parent=dos.psp;
newpsp->prev_psp.full=0xFFFFFFFF;
Bit32u i;
Bit8u * prevfile=real_off(prevpsp->file_table.seg,prevpsp->file_table.off);
for (i=0;i<20;i++) newpsp->files[i]=prevfile[i];
newpsp->max_files=20;
newpsp->file_table.seg=pspseg;
newpsp->file_table.off=offsetof(PSP,files);
/* Save the old DTA in this psp */
newpsp->dta.seg=dos.dta.seg;
newpsp->dta.off=dos.dta.off;
/* Setup the DTA */
dos.dta.seg=pspseg;
dos.dta.off=0x80;
return;
#endif
}
void DOS_FCB::Set_drive(Bit8u a){
mem_writeb(off+offsetof(FCB,drive),a);
}
void DOS_FCB::Set_filename(char * a){
MEM_BlockWrite(off+offsetof(FCB,filename),a,8);
}
void DOS_FCB::Set_ext(char * a) {
MEM_BlockWrite(off+offsetof(FCB,ext),a,3);
}
void DOS_FCB::Set_current_block(Bit16u a){
mem_writew(off+offsetof(FCB,current_block),a);
}
void DOS_FCB::Set_record_size(Bit16u a){
mem_writew(off+offsetof(FCB,record_size),a);
}
void DOS_FCB::Set_filesize(Bit32u a){
mem_writed(off+offsetof(FCB,filesize),a);
}
void DOS_FCB::Set_date(Bit16u a){
mem_writew(off+offsetof(FCB,date),a);
}
void DOS_FCB::Set_time(Bit16u a){
mem_writew(off+offsetof(FCB,time),a);
}
Bit8u DOS_FCB::Get_drive(void){
return mem_readb(off+offsetof(FCB,drive));
}
void DOS_FCB::Get_filename(char * a){
MEM_BlockRead(off+offsetof(FCB,filename),a,8);
}
void DOS_FCB::Get_ext(char * a){
MEM_BlockRead(off+offsetof(FCB,ext),a,3);
}
Bit16u DOS_FCB::Get_current_block(void){
return mem_readw(off+offsetof(FCB,current_block));
}
Bit16u DOS_FCB::Get_record_size(void){
return mem_readw(off+offsetof(FCB,record_size));
}
Bit32u DOS_FCB::Get_filesize(void){
return mem_readd(off+offsetof(FCB,filesize));
}
Bit16u DOS_FCB::Get_date(void){
return mem_readw(off+offsetof(FCB,date));
}
Bit16u DOS_FCB::Get_time(void){
return mem_readw(off+offsetof(FCB,time));
}

77
src/dos/dos_devices.cpp Normal file
View file

@ -0,0 +1,77 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "callback.h"
#include "cpu.h"
#include "mem.h"
#include "bios.h"
#include "dos_inc.h"
#include "support.h"
#define MAX_DEVICES 10
/* Include all the devices */
#include "dev_con.h"
static DOS_Device * devices[MAX_DEVICES];
static Bit32u device_count;
Bit8u DOS_FindDevice(char * name) {
/* loop through devices */
Bit8u index=0;
while (index<device_count) {
if (devices[index]) {
if (strcasecmp(name,devices[index]->name)==0) return index;
}
index++;
}
return 255;
}
void DOS_AddDevice(DOS_Device * adddev) {
//TODO Give the Device a real handler in low memory that responds to calls
if (device_count<MAX_DEVICES) {
devices[device_count]=adddev;
device_count++;
/* Add the device in the main file Table */
Bit8u handle=DOS_FILES;Bit8u i;
for (i=0;i<DOS_FILES;i++) {
if (!Files[i]) {
handle=i;
Files[i]=adddev;
break;
}
}
if (handle==DOS_FILES) E_Exit("DOS:Not enough file handles for device");
adddev->fhandle=handle;
} else {
E_Exit("DOS:Too many devices added");
}
}
void DOS_SetupDevices(void) {
device_count=0;
DOS_Device * newdev;
newdev=new device_CON();
DOS_AddDevice(newdev);
}

439
src/dos/dos_execute.cpp Normal file
View file

@ -0,0 +1,439 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "mem.h"
#include "dos_inc.h"
#include "cpu.h"
#pragma pack(1)
struct EXE_Header {
Bit16u signature; /* EXE Signature MZ or ZM */
Bit16u extrabytes; /* Bytes on the last page */
Bit16u pages; /* Pages in file */
Bit16u relocations; /* Relocations in file */
Bit16u headersize; /* Paragraphs in header */
Bit16u minmemory; /* Minimum amount of memory */
Bit16u maxmemory; /* Maximum amount of memory */
Bit16u initSS;
Bit16u initSP;
Bit16u checksum;
Bit16u initIP;
Bit16u initCS;
Bit16u reloctable;
Bit16u overlay;
};
#pragma pack()
#define MAGIC1 0x5a4d
#define MAGIC2 0x4d5a
#define MAXENV 32768u
#define ENV_KEEPFREE 83 /* keep unallocated by environment variables */
/* The '65' added to nEnvSize does not cover the additional stuff:
+ 2 bytes: number of strings
+ 80 bytes: maximum absolute filename
+ 1 byte: '\0'
-- 1999/04/21 ska */
#define LOADNGO 0
#define LOAD 1
#define OVERLAY 3
bool DOS_Terminate(bool tsr) {
PSP * psp=(PSP *)real_off(dos.psp,0);
if (!tsr) {
/* Free Files owned by process */
for (Bit16u i=0;i<psp->max_files;i++) {
DOS_CloseFile(i);
}
DOS_FreeProcessMemory(dos.psp);
};
dos.psp=psp->psp_parent;
PSP * oldpsp=(PSP *)real_off(dos.psp,0);
/* Restore the DTA */
dos.dta=psp->dta;
/* Restore the old CS:IP from int 22h */
RealPt old22;
old22=RealGetVec(0x22);
SetSegment_16(cs,RealSeg(old22));
reg_ip=RealOff(old22);
/* Restore the SS:SP to the previous one */
SetSegment_16(ss,RealSeg(oldpsp->stack));
reg_sp=RealOff(oldpsp->stack);
/* Restore interrupt 22,23,24 */
RealSetVec(0x22,psp->int_22);
RealSetVec(0x23,psp->int_23);
RealSetVec(0x24,psp->int_24);
return true;
}
static bool MakeEnv(char * name,Bit16u * segment) {
/* If segment to copy environment is 0 copy the caller's environment */
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u * envread,*envwrite;
Bit16u envsize=1;
bool parentenv=true;
if (*segment==0) {
if (!psp->environment) parentenv=false; //environment seg=0
envread=real_off(psp->environment,0);
} else {
if (!*segment) parentenv=false; //environment seg=0
envread=real_off(*segment,0);
}
//TODO Make a good DOS first psp
if (parentenv) {
for (envsize=0; ;envsize++) {
if (envsize>=MAXENV - ENV_KEEPFREE) {
DOS_SetError(DOSERR_ENVIRONMENT_INVALID);
return false;
}
if (readw(envread+envsize)==0) break;
}
envsize += 2; /* account for trailing \0\0 */
}
Bit16u size=long2para(envsize+ENV_KEEPFREE);
if (!DOS_AllocateMemory(segment,&size)) return false;
envwrite=real_off(*segment,0);
if (parentenv) {
bmemcpy(envwrite,envread,envsize);
envwrite+=envsize;
} else {
*envwrite++=0;
}
*((Bit16u *) envwrite)=1;
envwrite+=2;
//TODO put the filename here
return DOS_Canonicalize(name,envwrite);
};
bool DOS_NewPSP(Bit16u pspseg) {
PSP * newpsp=(PSP *)real_off(pspseg,0);
PSP * prevpsp=(PSP *)real_off(dos.psp,0);
memset((void *)newpsp,0,sizeof(PSP));
newpsp->exit[0]=0xcd;newpsp->exit[1]=0x20;
newpsp->service[0]=0xcd;newpsp->service[0]=0x21;newpsp->service[0]=0xcb;
newpsp->mem_size=prevpsp->mem_size;
newpsp->environment=0;
newpsp->int_22=RealGetVec(0x22);
newpsp->int_23=RealGetVec(0x23);
newpsp->int_24=RealGetVec(0x24);
newpsp->psp_parent=dos.psp;
newpsp->prev_psp=0xFFFFFFFF;
Bit32u i;
Bit8u * prevfile=Real2Host(prevpsp->file_table);
for (i=0;i<20;i++) newpsp->files[i]=prevfile[i];
newpsp->max_files=20;
newpsp->file_table=RealMake(pspseg,offsetof(PSP,files));
/* Save the old DTA in this psp */
newpsp->dta=dos.dta;
/* Setup the DTA */
dos.dta=RealMake(pspseg,0x80);
return true;
};
static void SetupPSP(Bit16u pspseg,Bit16u memsize,Bit16u envseg) {
PSP * psp=(PSP *)real_off(pspseg,0);
/* Fix the PSP index of this MCB */
MCB * pspmcb=(MCB *)real_off(pspseg-1,0);
pspmcb->psp_segment=pspseg;
MCB * envmcb=(MCB *)real_off(envseg-1,0);
envmcb->psp_segment=pspseg;
memset((void *)psp,0,sizeof(PSP));
Bit32u i;
psp->exit[0]=0xcd;psp->exit[1]=0x20;
psp->mem_size=memsize+pspseg;
psp->environment=envseg;
psp->int_22=RealGetVec(0x22);
psp->int_23=RealGetVec(0x23);
psp->int_24=RealGetVec(0x24);
psp->service[0]=0xcd;psp->service[0]=0x21;psp->service[0]=0xcb;
psp->psp_parent=dos.psp;
psp->prev_psp=RealMake(dos.psp,0);
for (i=0;i<20;i++) psp->files[i]=0xff;
psp->files[STDIN]=DOS_FindDevice("CON");
psp->files[STDOUT]=DOS_FindDevice("CON");
psp->files[STDERR]=DOS_FindDevice("CON");
psp->files[STDAUX]=DOS_FindDevice("CON");
psp->files[STDNUL]=DOS_FindDevice("CON");
psp->files[STDPRN]=DOS_FindDevice("CON");
psp->max_files=20;
psp->file_table=RealMake(pspseg,offsetof(PSP,files));
/* Save old DTA in psp */
psp->dta=dos.dta;
/* Setup the DTA */
dos.dta=RealMake(pspseg,0x80);
}
static void SetupCMDLine(Bit16u pspseg,ParamBlock * block) {
PSP * psp=(PSP *)real_off(pspseg,0);
if (block->exec.cmdtail) {
memcpy((void *)&psp->cmdtail,(void *)Real2Host(block->exec.cmdtail),128);
} else {
char temp[]="";
psp->cmdtail.count=strlen(temp);
strcpy((char *)&psp->cmdtail.buffer,temp);
psp->cmdtail.buffer[0]=0x0d;
}
}
static bool COM_Load(char * name,ParamBlock * block,Bit8u flag) {
Bit16u fhandle;
Bit16u size;Bit16u readsize;
Bit16u envseg,comseg;
Bit32u pos;
PSP * callpsp=(PSP *)real_off(dos.psp,0);
if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false;
if (flag!=OVERLAY) {
/* Allocate a new Environment */
envseg=block->exec.envseg;
if (!MakeEnv(name,&envseg)) return false;
/* Allocate max memory for COM file and PSP */
size=0xffff;
DOS_AllocateMemory(&comseg,&size);
//TODO Errors check for minimun of 64kb in pages
if (Bit32u(size <<4)<0x1000) {
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
DOS_AllocateMemory(&comseg,&size);
} else {
comseg=block->overlay.loadseg;
}
/* Memory allocated now load the program */
/* Now copy the File into allocated memory */
pos=0;
DOS_SeekFile(fhandle,&pos,0);
readsize=0xffff-256;
if (flag==OVERLAY) {
DOS_ReadFile(fhandle,real_host(comseg,0),&readsize);
} else {
DOS_ReadFile(fhandle,real_host(comseg,256),&readsize);
}
DOS_CloseFile(fhandle);
if (flag==OVERLAY) /* Everything what should be done for Overlays */
return true;
SetupPSP(comseg,size,envseg);
SetupCMDLine(comseg,block);
/* Setup termination Address */
RealSetVec(0x22,RealMake(Segs[cs].value,reg_ip));
/* Everything setup somewhat setup CS:IP and SS:SP */
/* First save the SS:SP of program that called execute */
callpsp->stack=RealMake(Segs[ss].value,reg_sp);
/* Clear out first Stack entry to point to int 20h at psp:0 */
real_writew(comseg,0xfffe,0);
dos.psp=comseg;
switch (flag) {
case LOADNGO:
SetSegment_16(cs,comseg);
SetSegment_16(ss,comseg);
SetSegment_16(ds,comseg);
SetSegment_16(es,comseg);
flags.intf=true;
reg_ip=0x100;
reg_sp=0xFFFE;
reg_ax=0;
reg_bx=reg_cx=reg_dx=reg_si=reg_di=reg_bp=0;
return true;
case LOAD:
block->exec.initsssp=RealMake(comseg,0xfffe);
block->exec.initcsip=RealMake(comseg,0x100);
return true;
}
return false;
}
static bool EXE_Load(char * name,ParamBlock * block,Bit8u flag) {
EXE_Header header;
Bit16u fhandle;Bit32u i;
Bit16u size,minsize,maxsize,freesize;Bit16u readsize;
Bit16u envseg,pspseg,exeseg;
Bit32u imagesize,headersize;
PSP * callpsp=(PSP *)real_off(dos.psp,0);
if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false;
if (flag!=OVERLAY) {
/* Allocate a new Environment */
envseg=block->exec.envseg;
if (!MakeEnv(name,&envseg)) return false;
};
/* First Read the EXE Header */
readsize=sizeof(EXE_Header);
DOS_ReadFile(fhandle,(Bit8u*)&header,&readsize);
/* Calculate the size of the image to load */
headersize=header.headersize*16;
imagesize=header.pages*512-headersize;
if (flag!=OVERLAY) {
minsize=long2para(imagesize+(header.minmemory<<4)+256);
if (header.maxmemory!=0) maxsize=long2para(imagesize+(header.maxmemory<<4)+256);
else maxsize=0xffff;
freesize=0xffff;
/* Check for enough free memory */
DOS_AllocateMemory(&exeseg,&freesize);
if (minsize>freesize) {
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
if (maxsize>freesize) {
size=freesize;
} else size=maxsize;
if ((header.minmemory|header.maxmemory)==0) {
size=freesize;
E_Exit("Special case exe header max and min=0");
}
if (!DOS_AllocateMemory(&pspseg,&size)) {
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
DOS_FreeMemory(envseg);
return false;
}
SetupPSP(pspseg,size,envseg);
SetupCMDLine(pspseg,block);
exeseg=pspseg+16;
} else {
/* For OVERLAY */
exeseg=block->overlay.loadseg;
}
/* Load the image in 32k blocks */
DOS_SeekFile(fhandle,&headersize,0);
Bit8u * imageoff=real_off(exeseg,0);
//TODO File size checking and remove size
// Remove psp size
// imagesize=256;
// Maybe remove final page and add last bytes on page
if (header.extrabytes) {
imagesize-=512;
imagesize+=header.extrabytes;
};
while (imagesize>0x7FFF) {
readsize=0x8000;
DOS_ReadFile(fhandle,imageoff,&readsize);
if (readsize!=0x8000) {
E_Exit("Illegal header");
}
imageoff+=0x8000;
imagesize-=0x8000;
}
if (imagesize>0) {
readsize=(Bit16u) imagesize;
DOS_ReadFile(fhandle,imageoff,&readsize);
}
headersize=header.reloctable;
DOS_SeekFile(fhandle,&headersize,0);
RealPt reloc;
for (i=0;i<header.relocations;i++) {
readsize=4;
DOS_ReadFile(fhandle,(Bit8u *)&reloc,&readsize);
PhysPt address=Real2Phys(RealMake(RealSeg(reloc)+exeseg,RealOff(reloc)));
Bit16u change=mem_readw(address);
if (flag==OVERLAY) {
change+=block->overlay.relocation;
} else {
change+=exeseg;
};
mem_writew(address,change);
};
DOS_CloseFile(fhandle);
if (flag==OVERLAY) return true;
/* Setup termination Address */
RealSetVec(0x22,RealMake(Segs[cs].value,reg_ip));
/* Start up the actual EXE if we need to */
//TODO check for load and return
callpsp->stack=RealMake(Segs[ss].value,reg_sp);
dos.psp=pspseg;
SetSegment_16(cs,exeseg+header.initCS);
SetSegment_16(ss,exeseg+header.initSS);
SetSegment_16(ds,pspseg);
SetSegment_16(es,pspseg);
reg_ip=header.initIP;
reg_sp=header.initSP;
reg_ax=0;
reg_bx=reg_cx=reg_dx=reg_si=reg_di=reg_bp=0;
flags.intf=true;
return true;
};
bool DOS_Execute(char * name,ParamBlock * block,Bit8u flags) {
EXE_Header head;
Bit16u fhandle;
Bit16u size;
bool iscom=false;
if (!DOS_OpenFile(name,OPEN_READ,&fhandle)) return false;
size=sizeof(EXE_Header);
if (!DOS_ReadFile(fhandle,(Bit8u *)&head,&size)) {
DOS_CloseFile(fhandle);
return false;
}
if (!DOS_CloseFile(fhandle)) return false;
if (size<sizeof(EXE_Header)) iscom=true;
if ((head.signature!=MAGIC1) && (head.signature!=MAGIC2)) iscom=true;
if (iscom) {
return COM_Load(name,block,flags);
} else {
return EXE_Load(name,block,flags);
}
}

614
src/dos/dos_files.cpp Normal file
View file

@ -0,0 +1,614 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include "dosbox.h"
#include "mem.h"
#include "cpu.h"
#include "dos_inc.h"
#include "drives.h"
#define DOS_FILESTART 4
DOS_File * Files[DOS_FILES];
DOS_Drive * Drives[DOS_DRIVES];
static Bit8u CurrentDrive=2; //Init on C:
Bit8u DOS_GetDefaultDrive(void) {
return CurrentDrive;
}
void DOS_SetDefaultDrive(Bit8u drive) {
CurrentDrive=drive;
}
bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) {
//TODO Hope this is ok :)
char upname[DOS_PATHLENGTH];
Bit32u r=0;Bit32u w=0;Bit32u namestart=0;
bool hasdrive=false;
*drive=CurrentDrive;
char tempdir[DOS_NAMELENGTH];
//TODO Maybe check for illegal characters
while (name[r]!=0 && (r<DOS_PATHLENGTH)) {
Bit8u c=name[r++];
if ((c>='a') && (c<='z')) {upname[w++]=c-32;continue;}
if ((c>='A') && (c<='Z')) {upname[w++]=c;continue;}
if ((c>='0') && (c<='9')) {upname[w++]=c;continue;}
switch (c) {
case ':':
if (hasdrive) { DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; }
else hasdrive=true;
if ((upname[0]>='A') && (upname[0]<='Z')) {
*drive=upname[0]-'A';
w=0;
} else {
DOS_SetError(DOSERR_PATH_NOT_FOUND);return false;
}
break;
case '/':
upname[w++]='\\';
break;
case ' ':
break;
case '\\': case '$': case '#': case '@': case '(': case ')':
case '!': case '%': case '{': case '}': case '`': case '~':
case '_': case '-': case '.': case '*': case '?': case '&':
upname[w++]=c;
break;
default:
DOS_SetError(DOSERR_PATH_NOT_FOUND);return false;
break;
}
}
upname[w]=0;
/* This should get us an upcase filename and no incorrect chars */
/* Now parse the new file name to make the final filename */
if ((*drive>=26)) {
DOS_SetError(DOSERR_INVALID_DRIVE);return false;
};
if (!Drives[*drive]) {
DOS_SetError(DOSERR_INVALID_DRIVE);return false;
};
if (upname[0]!='\\') strcpy(fullname,Drives[*drive]->curdir);
else fullname[0]=0;
Bit32u lastdir=0;Bit32u t=0;
while (fullname[t]!=0) {
if ((fullname[t]=='\\') && (fullname[t+1]!=0))lastdir=t;
t++;
};
r=0;w=0;
tempdir[0]=0;
bool stop=false;
while (!stop) {
if (upname[r]==0) stop=true;
if ((upname[r]=='\\') || (upname[r]==0)){
tempdir[w]=0;
if (tempdir[0]==0) { w=0;r++;continue;}
if (strcmp(tempdir,".")==0) {
tempdir[0]=0;
w=0;r++;
continue;
}
if (strcmp(tempdir,"..")==0) {
fullname[lastdir]=0;
Bit32u t=0;lastdir=0;
while (fullname[t]!=0) {
if ((fullname[t]=='\\') && (fullname[t+1]!=0))lastdir=t;
t++;
}
tempdir[0]=0;
w=0;r++;
continue;
}
lastdir=strlen(fullname);
//TODO Maybe another check for correct type because of .... stuff
if (lastdir!=0) strcat(fullname,"\\");
strcat(fullname,tempdir);
tempdir[0]=0;
w=0;r++;
continue;
}
tempdir[w++]=upname[r++];
}
return true;
}
bool DOS_GetCurrentDir(Bit8u drive,Bit8u * buffer) {
if (drive==0) drive=DOS_GetDefaultDrive();
else drive--;
if ((drive>DOS_DRIVES) || (!Drives[drive])) {
DOS_SetError(DOSERR_INVALID_DRIVE);
return false;
}
strcpy((char *) buffer,Drives[drive]->curdir);
return true;
}
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;
} else {
DOS_SetError(DOSERR_PATH_NOT_FOUND);
}
return false;
}
bool DOS_MakeDir(char * dir) {
Bit8u drive;char fulldir[DOS_PATHLENGTH];
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
return Drives[drive]->MakeDir(fulldir);
}
bool DOS_RemoveDir(char * dir) {
Bit8u drive;char fulldir[DOS_PATHLENGTH];
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
return Drives[drive]->RemoveDir(fulldir);
}
bool DOS_Rename(char * oldname,char * newname) {
Bit8u driveold;char fullold[DOS_PATHLENGTH];
Bit8u drivenew;char fullnew[DOS_PATHLENGTH];
if (!DOS_MakeName(oldname,fullold,&driveold)) return false;
if (!DOS_MakeName(newname,fullnew,&drivenew)) return false;
//TODO Test for different drives maybe
if (Drives[drivenew]->Rename(fullold,fullnew)) return true;
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
};
bool DOS_FindFirst(char * search,Bit16u attr) {
Bit8u drive;char fullsearch[DOS_PATHLENGTH];
if (!DOS_MakeName(search,fullsearch,&drive)) return false;
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
dtablock->sattr=attr | DOS_ATTR_ARCHIVE;
dtablock->sdrive=drive;
return Drives[drive]->FindFirst(fullsearch,dtablock);
};
bool DOS_FindNext(void) {
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
return Drives[dtablock->sdrive]->FindNext(dtablock);
};
bool DOS_ReadFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
//TODO maybe another code :)
/*
if (!(Files[handle]->flags & OPEN_READ)) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
}
*/
Bit16u toread=*amount;
bool ret=Files[handle]->Read(data,&toread);
*amount=toread;
return ret;
};
bool DOS_WriteFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
//TODO maybe another code :)
/*
if (!(Files[handle]->flags & OPEN_WRITE)) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
}
*/
Bit16u towrite=*amount;
bool ret=Files[handle]->Write(data,&towrite);
*amount=towrite;
return ret;
};
bool DOS_SeekFile(Bit16u entry,Bit32u * pos,Bit32u type) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
return Files[handle]->Seek(pos,type);
};
bool DOS_CloseFile(Bit16u entry) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
//TODO Figure this out with devices :)
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u * table=Real2Host(psp->file_table);
table[entry]=0xFF;
/* Devices won't allow themselves to be closed or killed */
if (Files[handle]->Close()) {
delete Files[handle];
Files[handle]=0;
}
return true;
}
bool DOS_CreateFile(char * name,Bit16u attributes,Bit16u * entry) {
char fullname[DOS_PATHLENGTH];Bit8u drive;
PSP * psp=(PSP *)real_off(dos.psp,0);
if (!DOS_MakeName(name,fullname,&drive)) return false;
/* Check for a free file handle */
Bit8u handle=DOS_FILES;Bit8u i;
for (i=0;i<DOS_FILES;i++) {
if (!Files[i]) {
handle=i;
break;
}
}
if (handle==DOS_FILES) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
/* We have a position in the main table now find one in the psp table */
Bit8u * table=Real2Host(psp->file_table);
*entry=0xff;
for (i=0;i<psp->max_files;i++) {
if (table[i]==0xFF) {
*entry=i;
break;
}
}
if (*entry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
bool foundit=Drives[drive]->FileCreate(&Files[handle],fullname,attributes);
if (foundit) {
table[*entry]=handle;
return true;
} else {
return false;
}
}
bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) {
/* First check for devices */
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u handle=DOS_FindDevice((char *)name);
bool device=false;char fullname[DOS_PATHLENGTH];Bit8u drive;Bit8u i;
if (handle!=255) {
device=true;
} else {
/* First check if the name is correct */
if (!DOS_MakeName(name,fullname,&drive)) return false;
/* Check for a free file handle */
for (i=0;i<DOS_FILES;i++) {
if (!Files[i]) {
handle=i;
break;
}
}
if (handle==255) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
}
/* We have a position in the main table now find one in the psp table */
Bit8u * table=Real2Host(psp->file_table);
*entry=0xff;
for (i=0;i<psp->max_files;i++) {
if (table[i]==0xFF) {
*entry=i;
break;
}
}
if (*entry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
bool exists=false;
if (!device) exists=Drives[drive]->FileOpen(&Files[handle],fullname,flags);
if (exists || device ) {
table[*entry]=handle;
return true;
} else {
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
}
}
bool DOS_UnlinkFile(char * name) {
char fullname[DOS_PATHLENGTH];Bit8u drive;
if (!DOS_MakeName(name,fullname,&drive)) return false;
return Drives[drive]->FileUnlink(fullname);
}
bool DOS_GetFileAttr(char * name,Bit16u * attr) {
char fullname[DOS_PATHLENGTH];Bit8u drive;
if (!DOS_MakeName(name,fullname,&drive)) return false;
if (Drives[drive]->GetFileAttr(fullname,attr)) {
return true;
} else {
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
}
}
bool DOS_Canonicalize(char * name,Bit8u * big) {
//TODO Add Better support for devices and shit but will it be needed i doubt it :)
Bit8u drive;
char fullname[DOS_PATHLENGTH];
if (!DOS_MakeName(name,fullname,&drive)) return false;
big[0]=drive+'A';
big[1]=':';
big[2]='\\';
strcpy((char *)&big[3],fullname);
return true;
};
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) {
if (drive==0) drive=DOS_GetDefaultDrive();
else drive--;
if ((drive>DOS_DRIVES) || (!Drives[drive])) {
DOS_SetError(DOSERR_INVALID_DRIVE);
return false;
}
return Drives[drive]->FreeSpace(bytes,sectors,clusters,free);
}
bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry) {
Bit8u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
PSP * psp=(PSP *)real_off(dos.psp,0);
Bit8u * table=Real2Host(psp->file_table);
*newentry=0xff;
for (Bit16u i=0;i<psp->max_files;i++) {
if (table[i]==0xFF) {
*newentry=i;
break;
}
}
if (*newentry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
}
table[*newentry]=handle;
return true;
};
bool DOS_CreateTempFile(char * name,Bit16u * entry) {
/* First add random crap to the end of the name and try to open */
/* Todo maybe check for euhm existence of the path name */
char * tempname;
tempname=name+strlen(name);
do {
Bit32u i;
for (i=0;i<8;i++) {
tempname[i]=(rand()%26)+'A';
}
tempname[8]='.';
for (i=9;i<12;i++) {
tempname[i]=(rand()%26)+'A';
}
tempname[13]=0;
} while (!DOS_CreateFile(name,0,entry));
return true;
}
#if 0
void FCB_MakeName (DOS_FCB* fcb, char* outname, Bit8u* outdrive){
char naam[15];
Bit8u drive=fcb->Get_drive();
if(drive!=0){
naam[0]=(drive-1)+'A';
naam[1]=':';
naam[2]='\0';}
else{
naam[0]='\0';
};
char temp[9];
fcb->Get_filename(temp);
temp[9]='.';
strncat(naam,temp,9);
char ext[3];
fcb->Get_ext(ext);
if(drive!=0) {
strncat(&naam[11],ext,3);
naam[14]='\0';
}else{
strncat(&naam[9],ext,3);
naam[12]='\0';
};
DOS_MakeName(naam,outname, outdrive);
return;
}
bool DOS_FCBOpen(Bit16u seg,Bit16u offset) {
DOS_FCB fcb(seg,offset);
Bit8u drive;
char fullname[DOS_PATHLENGTH];
FCB_MakeName (&fcb, fullname, &drive);
if(DOS_FileExists(fullname)==false) return false;
struct stat stat_block;
stat(fullname, &stat_block);
fcb.Set_filesize((Bit32u)stat_block.st_size);
Bit16u constant =0;
fcb.Set_current_block(constant);
constant=0x80;
fcb.Set_record_size(constant);
struct tm *time;
time=localtime(&stat_block.st_mtime);
constant=(time->tm_hour<<11)+(time->tm_min<<5)+(time->tm_sec/2); /* standard way. */
fcb->Set_time(constant);
constant=((time->tm_year-80)<<9)+((time->tm_mon+1)<<5)+(time->tm_mday);
fcb->Set_date(constant);
fcb->Set_drive(drive +1);
return true;
}
bool FCB_Close(void)
{ return true;}
bool FCB_FindFirst(Bit16u seg,Bit16u offset)
{FCB* fcb = new FCB(seg,offset);
Bit8u drive;
Bitu i;
char fullname[DOS_PATHLENGTH];
FCB_MakeName (fcb, fullname, &drive);
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
if(Drives[drive]->FindFirst(fullname,dtablock)==false) return false;
char naam[8];
char ext[3];
char * point=strrchr(dtablock->name,'.');
if(point==NULL|| *(point+1)=='\0') {
ext[0]=' ';
ext[1]=' ';
ext[2]=' ';
}else
{strcpy(ext,point+1);
Bitu i;
i=strlen(point+1);
while(i!=3) ext[i-1]=' ';
}
if(point!=NULL) *point='\0';
strcpy (naam,dtablock->name);
i=strlen(dtablock->name);
while(i!=8) naam[i-1]=' ';
FCB* fcbout= new FCB((PhysPt)Real2Host(dos.dta));
fcbout->Set_drive(drive +1);
fcbout->Set_filename(naam);
fcbout->Set_ext(ext);
return true;
}
bool FCB_FindNext(Bit16u seg,Bit16u offset)
{FCB* fcb = new FCB(seg,offset);
Bit8u drive;
Bitu i;
char fullname[DOS_PATHLENGTH];
FCB_MakeName (fcb, fullname, &drive);
DTA_FindBlock * dtablock=(DTA_FindBlock *)Real2Host(dos.dta);
if(Drives[dtablock->sdrive]->FindNext(dtablock)==false) return false;
char naam[8];
char ext[3];
char * point=strrchr(dtablock->name,'.');
if(point==NULL|| *(point+1)=='\0') {
ext[0]=' ';
ext[1]=' ';
ext[2]=' ';
}else
{strcpy(ext,point+1);
Bitu i;
i=strlen(point+1);
while(i!=3) ext[i-1]=' ';
}
if(point!=NULL) *point='\0';
strcpy (naam,dtablock->name);
i=strlen(dtablock->name);
while(i!=8) naam[i-1]=' ';
FCB* fcbout= new FCB((PhysPt)Real2Host(dos.dta));
fcbout->Set_drive(drive +1);
fcbout->Set_filename(naam);
fcbout->Set_ext(ext);
return true;
}
#endif
bool DOS_FileExists(char * name) {
Bit16u handle;
if (DOS_OpenFile(name,0,&handle)) {
DOS_CloseFile(handle);
return true;
}
return false;
}
bool DOS_SetDrive(Bit8u drive) {
if (Drives[drive]) {
DOS_SetDefaultDrive(drive);
return true;
} else {
return false;
}
};
void DOS_SetupFiles (void) {
/* Setup the File Handles */
Bit32u i;
for (i=0;i<DOS_FILES;i++) {
Files[i]=0;
}
/* Setup the Virtual Disk System */
for (i=0;i<DOS_DRIVES;i++) {
Drives[i]=0;
}
Drives[25]=new Virtual_Drive();
}

60
src/dos/dos_ioctl.cpp Normal file
View file

@ -0,0 +1,60 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "callback.h"
#include "mem.h"
#include "cpu.h"
#include "dos_inc.h"
#define MAX_DEVICE 20
static DOS_File * dos_devices[MAX_DEVICE];
bool DOS_IOCTL(Bit8u call,Bit16u entry) {
Bit32u handle=RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
if (!Files[handle]) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
};
switch(reg_al) {
case 0x00: /* Get Device Information */
reg_dx=Files[handle]->GetInformation();
return true;
case 0x07: /* Get Output Status */
LOG_DEBUG("DOS:IOCTL:07:Fakes output status is ready for handle %d",handle);
reg_al=0xff;
return true;
default:
LOG_ERROR("DOS:IOCTL Call %2X Handle %2X unhandled",reg_al,handle);
return false;
};
return false;
};
bool DOS_GetSTDINStatus(void) {
Bit32u handle=RealHandle(STDIN);
if (Files[handle]->GetInformation() & 64) return false;
return true;
};

162
src/dos/dos_memory.cpp Normal file
View file

@ -0,0 +1,162 @@
/*
* 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 "mem.h"
#include "dos_inc.h"
#define MEM_START 0x60 //First Segment that DOS can use
//#define MEM_START 4000 //First Segment that DOS can use
static void DOS_CompressMemory(void) {
MCB * pmcb;MCB * pmcbnext;
Bit16u mcb_segment;
mcb_segment=dos.firstMCB;
pmcb=(MCB *)real_off(mcb_segment,0);
while (pmcb->type!=0x5a) {
pmcbnext=pmcbnext=(MCB *)real_off(mcb_segment+pmcb->size+1,0);
if ((pmcb->psp_segment==0) && (pmcbnext->psp_segment==0)) {
pmcb->size+=pmcbnext->size+1;
pmcb->type=pmcbnext->type;
} else {
mcb_segment+=pmcb->size+1;
pmcb=(MCB *)real_off(mcb_segment,0);
}
}
}
void DOS_FreeProcessMemory(Bit16u pspseg) {
MCB * pmcb;
Bit16u mcb_segment=dos.firstMCB;
pmcb=(MCB *)real_off(mcb_segment,0);
while (true) {
if (pmcb->psp_segment==pspseg) {
pmcb->psp_segment=MCB_FREE;
}
mcb_segment+=pmcb->size+1;
if (pmcb->type==0x5a) break;
pmcb=(MCB *)real_off(mcb_segment,0);
}
DOS_CompressMemory();
};
bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) {
MCB * pmcb;MCB * pmcbnext;
Bit16u bigsize=0;Bit16u mcb_segment;
bool stop=false;mcb_segment=dos.firstMCB;
DOS_CompressMemory();
while(!stop) {
pmcb=(MCB *)real_off(mcb_segment,0);
if (pmcb->psp_segment==0) {
/* Check for enough free memory in current block */
if (pmcb->size<(*blocks)) {
if (bigsize<pmcb->size) {
bigsize=pmcb->size;
}
} else if (pmcb->size==*blocks) {
pmcb->psp_segment=dos.psp;
*segment=mcb_segment+1;
return true;
} else {
/* If so allocate it */
pmcbnext=(MCB *)real_off(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;
}
}
/* Onward to the next MCB if there is one */
if (pmcb->type==0x5a) {
*blocks=bigsize;
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
return false;
}
mcb_segment+=pmcb->size+1;
}
return false;
};
bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks) {
DOS_CompressMemory();
MCB * pmcb,* pmcbnext,* pmcbnew;
pmcb=(MCB *)real_off(segment-1,0);
pmcbnext=(MCB *)real_off(segment+pmcb->size,0);
Bit16u total=pmcb->size;
if (pmcb->type!=0x5a) {
if (pmcbnext->psp_segment==MCB_FREE) {
total+=pmcbnext->size+1;
}
};
if (*blocks<total) {
if (pmcb->type!=0x5a) {
pmcb->type=pmcbnext->type;
}
pmcb->size=*blocks;
pmcbnew=(MCB *)real_off(segment+*blocks,0);
pmcbnew->size=total-*blocks-1;
pmcbnew->type=pmcb->type;
pmcbnew->psp_segment=MCB_FREE;
pmcb->type=0x4D;
return true;
}
if (*blocks==total) {
if (pmcb->type!=0x5a) {
pmcb->type=pmcbnext->type;
}
pmcb->size=*blocks;
return true;
}
*blocks=total;
DOS_SetError(DOSERR_INSUFFICIENT_MEMORY);
return false;
};
bool DOS_FreeMemory(Bit16u segment) {
//TODO Check if allowed to free this segment
MCB * pmcb;
pmcb=(MCB *)real_off(segment-1,0);
pmcb->psp_segment=MCB_FREE;
DOS_CompressMemory();
return true;
}
void DOS_SetupMemory(void) {
//TODO Maybe allocate some memory for dos transfer buffers
//Although i could use bios regions for that for max free low memory
MCB * mcb=(MCB *) real_off(MEM_START,0);
mcb->psp_segment=MCB_FREE; //Free
mcb->size=0x9FFE - MEM_START;
mcb->type=0x5a; //Last Block
dos.firstMCB=MEM_START;
}

69
src/dos/dos_misc.cpp Normal file
View file

@ -0,0 +1,69 @@
/*
* 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 "callback.h"
#include "mem.h"
#include "regs.h"
#include "dos_inc.h"
static Bitu call_int2f,call_int2a;
struct MultiplexBlock {
MultiplexHandler * handler;
MultiplexBlock * next;
};
static MultiplexBlock * first_multiplex;
void DOS_AddMultiplexHandler(MultiplexHandler * handler) {
MultiplexBlock * new_multiplex=new(MultiplexBlock);
new_multiplex->next=first_multiplex;
new_multiplex->handler=handler;
first_multiplex=new_multiplex;
}
static Bitu INT2F_Handler(void) {
MultiplexBlock * loop_multiplex=first_multiplex;
while (loop_multiplex) {
if ((*loop_multiplex->handler)()) return CBRET_NONE;
loop_multiplex=loop_multiplex->next;
}
LOG_WARN("DOS:Multiplex Unhandled call %4X",reg_ax);
return CBRET_NONE;
};
static Bitu INT2A_Handler(void) {
return CBRET_NONE;
};
void DOS_SetupMisc(void) {
/* Setup the dos multiplex interrupt */
first_multiplex=0;
call_int2f=CALLBACK_Allocate();
CALLBACK_Setup(call_int2f,&INT2F_Handler,CB_IRET);
RealSetVec(0x2f,CALLBACK_RealPointer(call_int2f));
/* Setup the dos network interrupt */
call_int2a=CALLBACK_Allocate();
CALLBACK_Setup(call_int2a,&INT2A_Handler,CB_IRET);
RealSetVec(0x2A<<2,CALLBACK_RealPointer(call_int2a));
};

210
src/dos/dos_programs.cpp Normal file
View file

@ -0,0 +1,210 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "programs.h"
#include "support.h"
#include "drives.h"
#include "cross.h"
class MOUNT : public Program {
public:
MOUNT(PROGRAM_Info * program_info);
void Run(void);
};
MOUNT::MOUNT(PROGRAM_Info * info):Program(info) {
}
void MOUNT::Run(void) {
/* Parse the command line */
/* if the command line is empty show current mounts */
if (!*prog_info->cmd_line) {
WriteOut("Current mounted drives are\n");
for (int d=0;d<DOS_DRIVES;d++) {
if (Drives[d]) {
WriteOut("Drive %c is mounted as %s\n",d+'A',Drives[d]->GetInfo());
}
}
return;
}
char drive;
drive=toupper(*prog_info->cmd_line);
char * dir=strchr(prog_info->cmd_line,' ');
if (dir) {
if (!*dir) dir=0;
else dir=trim(dir);
};
if (!isalpha(drive) || !dir) {
WriteOut("Usage MOUNT Drive-Letter Local-Directory\nSo a MOUNT c c:\\windows mounts windows directory as the c: drive in DOSBox\n");
return;
};
struct stat test;
if (stat(dir,&test)) {
WriteOut("Directory %s Doesn't exist",dir);
return;
}
/* Not a switch so a normal directory/file */
if (!(test.st_mode & S_IFDIR)) {
WriteOut("%s isn't a directory",dir);
return;
}
if (Drives[drive-'A']) {
WriteOut("Drive %c already mounted with %s\n",drive,Drives[drive-'A']->GetInfo());
return;
}
char fulldir[DOS_PATHLENGTH];
strcpy(fulldir,dir);
static char theend[2]={CROSS_FILESPLIT,0};
char * last=strrchr(fulldir,CROSS_FILESPLIT);
if (!last || *(++last)) strcat(fulldir,theend);
Drives[drive-'A']=new localDrive(fulldir);
WriteOut("Mounting drive %c as %s\n",drive,fulldir);
}
static void MOUNT_ProgramStart(PROGRAM_Info * info) {
MOUNT * tempmount=new MOUNT(info);
tempmount->Run();
delete tempmount;
}
class MEM : public Program {
public:
MEM(PROGRAM_Info * program_info);
void Run(void);
};
MEM::MEM(PROGRAM_Info * info):Program(info) {
}
void MEM::Run(void) {
}
static void MEM_ProgramStart(PROGRAM_Info * info) {
MEM mem(info);
mem.Run();
}
#if !defined (WIN32) /* Unix */
class UPCASE : public Program {
public:
UPCASE(PROGRAM_Info * program_info);
void Run(void);
void upcasedir(char * directory);
};
UPCASE::UPCASE(PROGRAM_Info * info):Program(info) {
}
void UPCASE::upcasedir(char * directory) {
DIR * sdir;
char fullname[512];
char newname[512];
struct dirent *tempdata;
struct stat finfo;
if(!(sdir=opendir(directory))) {
WriteOut("Failed to open directory %s\n",directory);
return;
}
WriteOut("Scanning directory %s\n",fullname);
while (tempdata=readdir(sdir)) {
if (strcmp(tempdata->d_name,".")==0) continue;
if (strcmp(tempdata->d_name,"..")==0) continue;
strcpy(fullname,directory);
strcat(fullname,"/");
strcat(fullname,tempdata->d_name);
strcpy(newname,directory);
strcat(newname,"/");
upcase(tempdata->d_name);
strcat(newname,tempdata->d_name);
WriteOut("Renaming %s to %s\n",fullname,newname);
rename(fullname,newname);
stat(fullname,&finfo);
if(S_ISDIR(finfo.st_mode)) {
upcasedir(fullname);
}
}
closedir(sdir);
}
void UPCASE::Run(void) {
/* First check if the directory exists */
struct stat info;
WriteOut("UPCASE 0.1 Directory case convertor.\n");
if (!strlen(prog_info->cmd_line)) {
WriteOut("Usage UPCASE [local directory]\n");
WriteOut("This tool will convert all files and subdirectories in a directory.\n");
WriteOut("Be VERY sure this directory contains only dos related material.\n");
WriteOut("Otherwise you might horribly screw up your filesystem.\n");
return;
}
if (stat(prog_info->cmd_line,&info)) {
WriteOut("%s doesn't exist\n",prog_info->cmd_line);
return;
}
if(!S_ISDIR(info.st_mode)) {
WriteOut("%s isn't a directory\n",prog_info->cmd_line);
return;
}
WriteOut("Converting the wrong directories can be very harmfull, please be carefull.\n");
WriteOut("Are you really really sure you want to convert %s to upcase?Y/N\n",prog_info->cmd_line);
Bit8u key;Bit16u n=1;
DOS_ReadFile(STDIN,&key,&n);
if (toupper(key)=='Y') {
upcasedir(prog_info->cmd_line);
} else {
WriteOut("Okay better not do it.\n");
}
}
static void UPCASE_ProgramStart(PROGRAM_Info * info) {
UPCASE * tempUPCASE=new UPCASE(info);
tempUPCASE->Run();
delete tempUPCASE;
}
#endif
void DOS_SetupPrograms(void) {
PROGRAMS_MakeFile("MOUNT.COM",MOUNT_ProgramStart);
// PROGRAMS_MakeFile("MEM.COM",MEM_ProgramStart); /*next release */
#if !defined (WIN32) /* Unix */
PROGRAMS_MakeFile("UPCASE.COM",UPCASE_ProgramStart);
#endif
}

54
src/dos/dos_tables.cpp Normal file
View file

@ -0,0 +1,54 @@
/*
* 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 "mem.h"
#include "dos_inc.h"
#pragma pack(1)
struct DOS_TableCase {
Bit16u size;
Bit8u chars[256];
};
#pragma pack()
RealPt DOS_TableUpCase;
RealPt DOS_TableLowCase;
static Bit16u dos_memseg=0xd000;
Bit16u DOS_GetMemory(Bit16u pages) {
if (pages+dos_memseg>=0xe000) {
E_Exit("DOS:Not enough memory for internal tables");
}
Bit16u page=dos_memseg;
dos_memseg+=pages;
return page;
}
void DOS_SetupTables(void) {
dos.tables.indosflag=RealMake(DOS_GetMemory(1),0);
mem_writeb(Real2Phys(dos.tables.indosflag),0);
};

277
src/dos/drive_local.cpp Normal file
View file

@ -0,0 +1,277 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "dosbox.h"
#include "dos_system.h"
#include "drives.h"
#include "support.h"
#include "cross.h"
class localFile : public DOS_File {
public:
localFile(FILE * handle,Bit16u devinfo);
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
FILE * fhandle;
Bit16u info;
};
bool localDrive:: FileCreate(DOS_File * * file,char * name,Bit16u attributes) {
//TODO Maybe care for attributes but not likely
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
FILE * hand=fopen(newname,"wb+");
if (!hand) return false;
/* Make the 16 bit device information */
*file=new localFile(hand,0x202);
return true;
};
bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
char * type;
switch (flags) {
case OPEN_READ:type="rb";break;
case OPEN_WRITE:type="rb+";break;
case OPEN_READWRITE:type="rb+";break;
default:
//TODO FIX IT
type="rb+";
// return false;
};
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
FILE * hand=fopen(newname,type);
Bit32u err=errno;
if (!hand) return false;
*file=new localFile(hand,0x202);
return true;
};
bool localDrive::FileUnlink(char * name) {
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
if (!unlink(newname)) return true;
return false;
};
bool localDrive::FindFirst(char * search,DTA_FindBlock * dta) {
//TODO Find some way for lowcase and highcase drives oneday
char name[512];
strcpy(name,basedir);
strcat(name,search);
CROSS_FILENAME(name);
char * last=strrchr(name, CROSS_FILESPLIT);
*last=0;
last++;
/* Check the wildcard string for an extension */
strcpy(wild_name,last);
wild_ext=strrchr(wild_name,'.');
if (wild_ext) {
*wild_ext++=0;
}
strcpy(directory,name);
/* make sure / is last sign */
if (pdir) closedir(pdir);
if(directory[(strlen(directory)-1)]!=CROSS_FILESPLIT) strcat(directory, "/");
if((pdir=opendir(directory))==NULL) return false;
return FindNext(dta);
}
bool localDrive::FindNext(DTA_FindBlock * dta) {
Bit8u tempattr=0;
struct dirent *tempdata;
struct stat stat_block;
char werkbuffer[512];
if(pdir==NULL){
return false;
};
start:
if((tempdata=readdir(pdir))==NULL) {
closedir(pdir);
pdir=NULL;
return false;
}
strcpy(werkbuffer,tempdata->d_name);
if (wild_ext) {
char * ext=strrchr(werkbuffer,'.');
if (!ext) ext="*";
else *ext++=0;
if(!wildcmp(wild_ext,ext)) goto start;
}
if(!wildcmp(wild_name,werkbuffer)) goto start;
werkbuffer[0]='\0';
strcpy(werkbuffer,directory);
strcat(werkbuffer,tempdata->d_name);
if(stat(werkbuffer,&stat_block)!=0){
/*nu is er iets fout!*/ exit(1);
}
if(S_ISDIR(stat_block.st_mode)) tempattr=DOS_ATTR_DIRECTORY;
else tempattr=DOS_ATTR_ARCHIVE;
if(!(dta->sattr & tempattr)) goto start;
/*file is oke so filldtablok */
if(strlen(tempdata->d_name)<=DOS_NAMELENGTH) strcpy(dta->name,upcase(tempdata->d_name));
dta->attr=tempattr;
dta->size=(Bit32u) stat_block.st_size;
struct tm *time;
time=localtime(&stat_block.st_mtime);
dta->time=(time->tm_hour<<11)+(time->tm_min<<5)+(time->tm_sec/2); /* standard way. */
dta->date=((time->tm_year-80)<<9)+((time->tm_mon+1)<<5)+(time->tm_mday);
return true;
}
bool localDrive::GetFileAttr(char * name,Bit16u * attr) {
char newname[512];
strcpy(newname,basedir);
strcat(newname,name);
CROSS_FILENAME(newname);
FILE * hand=fopen(newname,"rb");
if (hand) {
fclose(hand);
*attr=DOS_ATTR_ARCHIVE;
return true;
}
*attr=0;
return false;
};
bool localDrive::MakeDir(char * dir) {
char newdir[512];
strcpy(newdir,basedir);
strcat(newdir,dir);
CROSS_FILENAME(newdir);
#if defined (WIN32) /* MS Visual C++ */
int temp=mkdir(newdir);
#else
int temp=mkdir(newdir,0);
#endif
return (temp==0);
}
bool localDrive::RemoveDir(char * dir) {
char newdir[512];
strcpy(newdir,basedir);
strcat(newdir,dir);
int temp=rmdir(newdir);
return (temp==0);
}
bool localDrive::TestDir(char * dir) {
char newdir[512];
strcpy(newdir,basedir);
strcat(newdir,dir);
int temp=access(newdir,F_OK);
return (temp==0);
}
bool localDrive::Rename(char * oldname,char * newname) {
char newold[512];
strcpy(newold,basedir);
strcat(newold,oldname);
CROSS_FILENAME(newold);
char newnew[512];
strcpy(newnew,basedir);
strcat(newnew,newnew);
CROSS_FILENAME(newname);
int temp=rename(newold,newnew);
return (temp==0);
};
bool localDrive::FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) {
/* Always report 100 mb free should be enough */
/* Total size is always 1 gb */
*bytes=512;
*sectors=127;
*clusters=16513;
*free=1700;
return true;
};
localDrive::localDrive(char * startdir) {
strcpy(basedir,startdir);
sprintf(info,"local directory %s",startdir);
pdir=NULL;
}
bool localFile::Read(Bit8u * data,Bit16u * size) {
*size=fread(data,1,*size,fhandle);
return true;
};
bool localFile::Write(Bit8u * data,Bit16u * size) {
*size=fwrite(data,1,*size,fhandle);
return true;
}
bool localFile::Seek(Bit32u * pos,Bit32u type) {
int seektype;
switch (type) {
case DOS_SEEK_SET:seektype=SEEK_SET;break;
case DOS_SEEK_CUR:seektype=SEEK_CUR;break;
case DOS_SEEK_END:seektype=SEEK_END;break;
default:
//TODO Give some doserrorcode;
return false;//ERROR
}
fpos_t temppos;
int ret=fseek(fhandle,*pos,seektype);
fgetpos(fhandle,&temppos);
//TODO Hope we don't encouter files with 64 bits size
Bit32u * fake_pos=(Bit32u*)&temppos;
*pos=*fake_pos;
return true;
}
bool localFile::Close() {
fclose(fhandle);
return true;
}
Bit16u localFile::GetInformation(void) {
return info;
}
localFile::localFile(FILE * handle,Bit16u devinfo) {
fhandle=handle;
info=devinfo;
}

205
src/dos/drive_virtual.cpp Normal file
View file

@ -0,0 +1,205 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dosbox.h"
#include "dos_system.h"
#include "drives.h"
#include "support.h"
struct VFILE_Block {
char * name;
Bit8u * data;
Bit32u size;
VFILE_Block * next;
};
static VFILE_Block * first_file;
void VFILE_Register(char * name,Bit8u * data,Bit32u size) {
VFILE_Block * new_file=new VFILE_Block;
new_file->name=name;
new_file->data=data;
new_file->size=size;
new_file->next=first_file;
first_file=new_file;
}
class Virtual_File : public DOS_File {
public:
Virtual_File(Bit8u * in_data,Bit32u in_size);
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
Bit32u file_size;
Bit32u file_pos;
Bit8u * file_data;
};
Virtual_File::Virtual_File(Bit8u * in_data,Bit32u in_size) {
file_size=in_size;
file_data=in_data;
file_pos=0;
}
bool Virtual_File::Read(Bit8u * data,Bit16u * size) {
Bit32u left=file_size-file_pos;
if (left<=*size) {
memcpy(data,&file_data[file_pos],left);
*size=(Bit16u)left;
} else {
memcpy(data,&file_data[file_pos],*size);
}
file_pos+=*size;
return true;
};
bool Virtual_File::Write(Bit8u * data,Bit16u * size){
/* Not really writeable */
return false;
};
bool Virtual_File::Seek(Bit32u * new_pos,Bit32u type){
switch (type) {
case DOS_SEEK_SET:
if (*new_pos<=file_size) file_pos=*new_pos;
else return false;
break;
case DOS_SEEK_CUR:
if ((*new_pos+file_pos)<=file_size) file_pos=*new_pos+file_pos;
else return false;
break;
case DOS_SEEK_END:
if (*new_pos<=file_size) file_pos=file_size-*new_pos;
else return false;
break;
}
*new_pos=file_pos;
return true;
};
bool Virtual_File::Close(){
return true;
};
Bit16u Virtual_File::GetInformation(void) {
return 0;
}
Virtual_Drive::Virtual_Drive() {
strcpy(info,"Internal Virtual Drive");
search_file=0;
}
bool Virtual_Drive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
/* Scan through the internal list of files */
VFILE_Block * cur_file=first_file;
while (cur_file) {
if (strcasecmp(name,cur_file->name)==0) {
/* We have a match */
*file=new Virtual_File(cur_file->data,cur_file->size);
return true;
}
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::FileCreate(DOS_File * * file,char * name,Bit16u attributes) {
return false;
}
bool Virtual_Drive::FileUnlink(char * name) {
return false;
}
bool Virtual_Drive::RemoveDir(char * dir) {
return false;
}
bool Virtual_Drive::MakeDir(char * dir) {
return false;
}
bool Virtual_Drive::TestDir(char * dir) {
return false;
}
static void FillDTABlock(DTA_FindBlock * dta,VFILE_Block * fill_file) {
strcpy(dta->name,fill_file->name);
dta->size=fill_file->size;
dta->attr=DOS_ATTR_ARCHIVE;
dta->time=2;
dta->date=6;
}
bool Virtual_Drive::FindFirst(char * search,DTA_FindBlock * dta) {
search_file=first_file;
strcpy(search_string,search);
while (search_file) {
if (wildcmp(search_string,search_file->name)) {
FillDTABlock(dta,search_file);
search_file=search_file->next;
return true;
}
search_file=search_file->next;
}
return false;
}
bool Virtual_Drive::FindNext(DTA_FindBlock * dta) {
while (search_file) {
if (wildcmp(search_string,search_file->name)) {
FillDTABlock(dta,search_file);
search_file=search_file->next;
return true;
}
search_file=search_file->next;
}
return false;
}
bool Virtual_Drive::GetFileAttr(char * name,Bit16u * attr) {
return false;
}
bool Virtual_Drive::Rename(char * oldname,char * newname) {
return false;
}
bool Virtual_Drive::FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free) {
/* Always report 100 mb free should be enough */
/* Total size is always 1 gb */
*bytes=512;
*sectors=127;
*clusters=16513;
*free=00;
return true;
}

31
src/dos/drives.cpp Normal file
View file

@ -0,0 +1,31 @@
/*
* 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 "dos_system.h"
#include "drives.h"
DOS_Drive::DOS_Drive() {
curdir[0]=0;
info[0]=0;
}
char * DOS_Drive::GetInfo(void) {
return info;
}

71
src/dos/drives.h Normal file
View file

@ -0,0 +1,71 @@
/*
* 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.
*/
#ifndef _DRIVES_H__
#define _DRIVES_H__
#include <sys/types.h>
#include <dirent.h>
class localDrive : public DOS_Drive {
public:
localDrive(char * startdir);
bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
bool FileUnlink(char * name);
bool RemoveDir(char * dir);
bool MakeDir(char * dir);
bool TestDir(char * dir);
bool FindFirst(char * search,DTA_FindBlock * dta);
bool FindNext(DTA_FindBlock * dta);
bool GetFileAttr(char * name,Bit16u * attr);
bool Rename(char * oldname,char * newname);
bool FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free);
private:
bool FillDTABlock(DTA_FindBlock * dta);
char basedir[512];
char directory[512];
char wild_name[15];
char * wild_ext;
DIR *pdir;
};
struct VFILE_Block;
class Virtual_Drive: public DOS_Drive {
public:
Virtual_Drive();
bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
bool FileUnlink(char * name);
bool RemoveDir(char * dir);
bool MakeDir(char * dir);
bool TestDir(char * dir);
bool FindFirst(char * search,DTA_FindBlock * dta);
bool FindNext(DTA_FindBlock * dta);
bool GetFileAttr(char * name,Bit16u * attr);
bool Rename(char * oldname,char * newname);
bool FreeSpace(Bit16u * bytes,Bit16u * sectors,Bit16u * clusters,Bit16u * free);
private:
VFILE_Block * search_file;
char search_string[255];
};
#endif

297
src/dosbox.cpp Normal file
View file

@ -0,0 +1,297 @@
/*
* 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 <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "dosbox.h"
#include "debug.h"
#include "cpu.h"
#include "video.h"
#include "pic.h"
#include "cpu.h"
#include "callback.h"
#include "inout.h"
#include "mixer.h"
#include "timer.h"
#include "dos_inc.h"
#include "setup.h"
#include "cross.h"
#include "programs.h"
char dosbox_basedir[CROSS_LEN];
#if 0
int main(int argc, char* argv[]) {
/* Strip out the dosbox startup directory */
/* Handle the command line for new stuff to add to autoexec.bat */
int argl=1;
if (argc>1) {
if (*argv[1]!='-') {
struct stat test;
if (stat(argv[1],&test)) {
E_Exit("%s Doesn't exist",argv[1]);
}
/* Not a switch so a normal directory/file */
if (test.st_mode & S_IFDIR) {
SHELL_AddAutoexec("MOUNT C %s",argv[1]);
SHELL_AddAutoexec("C:");
} else {
char * name=strrchr(argv[1],CROSS_FILESPLIT);
if (!name) E_Exit("This is weird %s",argv[1]);
*name++=0;
if (access(argv[1],F_OK)) E_Exit("Illegal Directory %s",argv[1]);
SHELL_AddAutoexec("MOUNT C %s",argv[1]);
SHELL_AddAutoexec("C:");
SHELL_AddAutoexec(name);
}
argl++;
}
}
bool sw_c=false;
while (argl<argc) {
if (*argv[argl]=='-') {
sw_c=false;
if (strcmp(argv[argl],"-c")==0) sw_c=true;
else E_Exit("Illegal switch %s",argv[argl]);
argl++;
continue;
}
SHELL_AddAutoexec(argv[argl]);
if (sw_c) {
}
argl++;
}
SysShutDown();
SDL_Quit();
return 0;
}
#endif
//The whole load of startups for all the subfunctions
void MSG_Init(void);
void MEM_Init(void);
void VGA_Init(void);
void CALLBACK_Init();
void DOS_Init();
void RENDER_Init(void);
void CPU_Init();
void FPU_Init();
void IO_Init(void);
void DMA_Init(void);
void MIXER_Init(void);
void HARDWARE_Init(void);
void KEYBOARD_Init(void); //TODO This should setup INT 16 too but ok ;)
void JOYSTICK_Init(void);
void MOUSE_Init(void);
void SBLASTER_Init(void);
void ADLIB_Init(void);
void PCSPEAKER_Init(void);
void TANDY_Init(void);
void CMS_Init(void);
void PIC_Init(void);
void TIMER_Init(void);
void BIOS_Init(void);
void DEBUG_Init(void);
void PLUGIN_Init(void);
/* Dos Internal mostly */
void EMS_Init(void);
void XMS_Init(void);
void PROGRAMS_Init(void);
void SHELL_Init(void);
void CALLBACK_ShutDown(void);
void PIC_ShutDown(void);
void KEYBOARD_ShutDown(void);
void CPU_ShutDown(void);
void VGA_ShutDown(void);
void BIOS_ShutDown(void);
void MEMORY_ShutDown(void);
Bit32u LastTicks;
static LoopHandler * loop;
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);
}
TIMER_CheckPIT();
GFX_Events();
PIC_runIRQs();
return (*cpudecoder)(cpu_cycles);
};
static Bitu Speed_Loop(void) {
Bit32u new_ticks;
new_ticks=GetTicks();
Bitu ret=0;
Bitu cycles=1;
if (new_ticks>LastTicks) {
Bit32u ticks=new_ticks-LastTicks;
if (ticks>20) ticks=20;
// if (ticks>3) LOG_DEBUG("Ticks %d",ticks);
LastTicks=new_ticks;
TIMER_AddTicks(ticks);
cycles+=cpu_cycles*ticks;
}
TIMER_CheckPIT();
GFX_Events();
PIC_runIRQs();
return (*cpudecoder)(cycles);
}
void DOSBOX_SetLoop(LoopHandler * handler) {
loop=handler;
}
void DOSBOX_RunMachine(void){
Bitu ret;
do {
ret=(*loop)();
} while (!ret);
}
static void InitSystems(void) {
MSG_Init();
MEM_Init();
IO_Init();
CALLBACK_Init();
PROGRAMS_Init();
HARDWARE_Init();
TIMER_Init();
CPU_Init();
FPU_Init();
MIXER_Init();
#ifdef C_DEBUG
DEBUG_Init();
#endif
//Start up individual hardware
DMA_Init();
PIC_Init();
VGA_Init();
KEYBOARD_Init();
MOUSE_Init();
JOYSTICK_Init();
SBLASTER_Init();
TANDY_Init();
PCSPEAKER_Init();
ADLIB_Init();
CMS_Init();
PLUGIN_Init();
/* Most of teh interrupt handlers */
BIOS_Init();
DOS_Init();
EMS_Init(); //Needs dos first
XMS_Init(); //Needs dos first
/* Setup the normal system loop */
LastTicks=GetTicks();
DOSBOX_SetLoop(&Normal_Loop);
// DOSBOX_SetLoop(&Speed_Loop);
}
void DOSBOX_Init(int argc, char* argv[]) {
/* Find the base directory */
strcpy(dosbox_basedir,argv[0]);
char * last=strrchr(dosbox_basedir,CROSS_FILESPLIT); //if windowsversion fails:
if (!last) E_Exit("Can't find basedir %s", argv[0]);
*++last=0;
/* Parse the command line with a setup function */
int argl=1;
if (argc>1) {
if (*argv[1]!='-') {
struct stat test;
if (stat(argv[1],&test)) {
E_Exit("%s Doesn't exist",argv[1]);
}
/* Not a switch so a normal directory/file */
if (test.st_mode & S_IFDIR) {
SHELL_AddAutoexec("MOUNT C %s",argv[1]);
SHELL_AddAutoexec("C:");
} else {
char * name=strrchr(argv[1],CROSS_FILESPLIT);
if (!name) E_Exit("This is weird %s",argv[1]);
*name++=0;
if (access(argv[1],F_OK)) E_Exit("Illegal Directory %s",argv[1]);
SHELL_AddAutoexec("MOUNT C %s",argv[1]);
SHELL_AddAutoexec("C:");
SHELL_AddAutoexec(name);
}
argl++;
}
}
bool sw_c=false;
while (argl<argc) {
if (*argv[argl]=='-') {
sw_c=false;
if (strcmp(argv[argl],"-c")==0) sw_c=true;
else E_Exit("Illegal switch %s",argv[argl]);
argl++;
continue;
}
SHELL_AddAutoexec(argv[argl]);
if (sw_c) {
}
argl++;
}
InitSystems();
}
void DOSBOX_StartUp(void) {
SHELL_AddAutoexec("SET PATH=Z:\\");
SHELL_AddAutoexec("SET COMSPEC=Z:\\COMMAND.COM");
SHELL_Init();
};

75
src/dosbox.lang Normal file
View file

@ -0,0 +1,75 @@
:SHELL_CMD_HELP
supported commands are:
.
:SHELL_ILLEGAL_SWITCH
Illegal switch: %s
.
:SHELL_CMD_ECHO_ON
ECHO is on
.
:SHELL_CMD_ECHO_OFF
ECHO is off
.
:SHELL_CMD_CHDIR_ERROR
Unable to change to: %s
.
:SHELL_CMD_MKDIR_ERROR
Unable to make: %s
.
:SHELL_CMD_RMDIR_ERROR
Unable to remove: %s
.
:SHELL_SYNTAXERROR
The syntax of the command is incorrect
.
:SHELL_CMD_SET_NOT_SET
Environment variable %s not defined
.
:SHELL_CMD_SET_OUT_OF_SPACE
Not enough environment space left
.
:SHELL_CMD_IF_EXIST_MISSING_FILENAME
IF EXIST: Missing filename
.
:SHELL_CMD_IF_ERRORLEVEL_MISSING_NUMBER
IF ERRORLEVEL: Missing number
.
:SHELL_CMD_IF_ERRORLEVEL_INVALID_NUMBER
IF ERRORLEVEL: Invalid number
.
:SHELL_CMD_GOTO_MISSING_LABEL
No label supplied to GOTO command
.
:SHELL_CMD_GOTO_LABEL_NOT_FOUND
Label %s not found
.
:SHELL_CMD_FILE_NOT_FOUND
File %s not found
.
:SHELL_CMD_DIR_INTRO
Directory of %s
.
:SHELL_CMD_DIR_PATH_ERROR
Illegal Path
.
:SHELL_CMD_DIR_BYTES_USED
%16d File(s) %16s Bytes
.
:SHELL_CMD_DIR_BYTES_FREE
%16d Dir(s) %16s Bytes free
.
:SHELL_STARTUP
DOSBox Shell v0.35
For Help and supported commands type: HELP
For information about the hardware setup manager type: HWSET /?
HAVE FUN!
The DOSBox Team
.
:SHELL_EXECUTE_DRIVE_NOT_FOUND
Drive %c does not exist!
.
:SHELL_EXECUTE_ILLEGAL_COMMAND
Illegal command
.

4
src/fpu/Makefile.am Normal file
View file

@ -0,0 +1,4 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libfpu.a
libfpu_a_SOURCES = fpu.cpp fpu_load.h

62
src/fpu/fpu.cpp Normal file
View file

@ -0,0 +1,62 @@
/*
* 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 <math.h>
#include <float.h>
#include "mem.h"
#include "dosbox.h"
typedef PhysPt EAPoint;
#define LoadMb(off) mem_readb(off)
#define LoadMw(off) mem_readw(off)
#define LoadMd(off) mem_readd(off)
#define LoadMbs(off) (Bit8s)(LoadMb(off))
#define LoadMws(off) (Bit16s)(LoadMw(off))
#define LoadMds(off) (Bit32s)(LoadMd(off))
#define SaveMb(off,val) mem_writeb(off,val)
#define SaveMw(off,val) mem_writew(off,val)
#define SaveMd(off,val) mem_writed(off,val)
typedef long double FPUREG;
#include "fpu_load.h"
void FPU_ESC0_EA(Bitu rm,PhysPt addr) {
}
void FPU_ESC0_Normal(Bitu rm) {
}
void FPU_Init(void) {
}

21
src/fpu/fpu_load.h Normal file
View file

@ -0,0 +1,21 @@
/*
* 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.
*/
INLINE FPUREG Load_Short(EAPoint addr) {
return (Bit16s)mem_readw(addr);
}

5
src/gui/Makefile.am Normal file
View file

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

160
src/gui/render.cpp Normal file
View file

@ -0,0 +1,160 @@
/*
* 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 "video.h"
#include "render.h"
#define MAX_RES 2048
struct PalData {
struct {
Bit8u red;
Bit8u green;
Bit8u blue;
Bit8u unused;
} rgb[256];
Bitu first;
Bitu last;
};
static struct {
struct {
Bitu width;
Bitu height;
Bitu bpp;
Bitu pitch;
float ratio;
} src;
Bitu flags;
RENDER_Handler * handler;
Bitu stretch_x[MAX_RES];
Bitu stretch_y[MAX_RES];
PalData pal;
bool remake;
bool enlarge;
} render;
/* 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]);
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++) {
render.stretch_x[i]=c>> 16;
c=(c&0xffff)+a;
}
c=0;a=(render.src.height<<16)/gfx_info.height;
for (i=0;i<gfx_info.height;i++) {
render.stretch_y[i]=(c>> 16)*render.src.pitch;
c=(c&0xffff)+a;
}
}
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);
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;
render.pal.rgb[entry].blue=blue;
if (render.pal.first>entry) render.pal.first=entry;
if (render.pal.last<entry) render.pal.last=entry;
}
static void RENDER_Resize(Bitu * width,Bitu * height) {
/* Calculate the new size the window should be */
if (!*width && !*height) {
/* Special command to reset any resizing for fullscreen */
*width=render.src.width;
*height=render.src.height;
} else {
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();
render.src.width=width;
render.src.height=height;
render.src.bpp=bpp;
render.src.ratio=ratio;
render.src.pitch=pitch;
render.handler=handler;
switch (bpp) {
case 8:
GFX_Resize(width,height,bpp,&RENDER_Resize);
GFX_SetDrawHandler(RENDER_Draw);
break;
default:
E_Exit("RENDER:Illegal bpp %d",bpp);
};
/* Setup the internal render structures to correctly render this screen */
MakeTables();
GFX_Start();
}
void RENDER_Init(void) {
render.pal.first=256;
render.pal.last=0;
render.enlarge=false;
}

513
src/gui/sdlmain.cpp Normal file
View file

@ -0,0 +1,513 @@
/*
* 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 <string.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>
#include "dosbox.h"
#include "video.h"
#include "keyboard.h"
#include "mouse.h"
#include "joystick.h"
#include "pic.h"
#include "timer.h"
//#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;
bool mouse_grabbed;
bool full_screen;
SDL_Thread * thread;
SDL_mutex * mutex;
SDL_Surface * surface;
SDL_Joystick * joy;
SDL_Color pal[256];
};
static SDL_Block sdl;
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) {
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);
} else {
sdl.surface=SDL_SetVideoMode(sdl.width,sdl.height,sdl.bpp,SDL_SWSURFACE|SDL_RESIZABLE);
}
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();
}
void GFX_Resize(Bitu width,Bitu height,Bitu bpp,GFX_ResizeHandler * resize) {
GFX_Stop();
sdl.width=width;
sdl.height=height;
sdl.bpp=bpp;
sdl.resize=resize;
ResetScreen();
GFX_Start();
}
static void CaptureMouse() {
sdl.mouse_grabbed=!sdl.mouse_grabbed;
if (sdl.mouse_grabbed) {
SDL_WM_GrabInput(SDL_GRAB_ON);
SDL_ShowCursor(SDL_DISABLE);
} else {
SDL_WM_GrabInput(SDL_GRAB_OFF);
SDL_ShowCursor(SDL_ENABLE);
}
}
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);
}
}
ResetScreen();
GFX_Start();
}
static void GFX_Redraw() {
#ifdef C_THREADED
if (SDL_mutexP(sdl.mutex)) {
E_Exit("Can't Lock Mutex");
};
#endif
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);
};
#ifdef C_THREADED
if (SDL_mutexV(sdl.mutex)) {
E_Exit("Can't Release Mutex");
}
#endif
}
static int SDLGFX_Thread(void * data) {
do {
GFX_Redraw();
SDL_Delay(1000/70);
} while (true);
return 1;
}
void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) {
/* I should probably not change the GFX_PalEntry :) */
#ifdef 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");
}
} else {
if (!SDL_SetPalette(sdl.surface,SDL_LOGPAL,(SDL_Color *)entries,start,count)) {
E_Exit("SDL:Can't set palette");
}
}
/* Copy palette entries into some internal back up table */
#ifdef 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;
}
void GFX_Stop() {
#ifdef C_THREADED
SDL_mutexP(sdl.mutex);
#endif
sdl.active=false;
#ifdef C_THREADED
SDL_mutexV(sdl.mutex);
#endif
}
void GFX_Start() {
sdl.active=true;
}
void GFX_StartUp() {
sdl.active=false;
sdl.full_screen=false;
sdl.draw=0;
#ifdef C_THREADED
sdl.mutex=SDL_CreateMutex();
sdl.thread = SDL_CreateThread(&SDLGFX_Thread,0);
#else
TIMER_RegisterMicroHandler(GFX_Redraw,1000000/70);
#endif
GFX_Resize(640,400,8,0);
SDL_EnableKeyRepeat(250,30);
/* Get some Keybinds */
KEYBOARD_AddEvent(KBD_f9,CTRL_PRESSED,SwitchFullScreen);
KEYBOARD_AddEvent(KBD_f10,CTRL_PRESSED,CaptureMouse);
KEYBOARD_AddEvent(KBD_enter,ALT_PRESSED,SwitchFullScreen);
}
void GFX_ShutDown() {
if (sdl.full_screen) SwitchFullScreen();
if (sdl.mouse_grabbed) CaptureMouse();
GFX_Stop();
}
static void HandleKey(SDL_KeyboardEvent * key) {
Bit32u code;
switch (key->keysym.sym) {
case SDLK_1:code=KBD_1;break;
case SDLK_2:code=KBD_2;break;
case SDLK_3:code=KBD_3;break;
case SDLK_4:code=KBD_4;break;
case SDLK_5:code=KBD_5;break;
case SDLK_6:code=KBD_6;break;
case SDLK_7:code=KBD_7;break;
case SDLK_8:code=KBD_8;break;
case SDLK_9:code=KBD_9;break;
case SDLK_0:code=KBD_0;break;
case SDLK_q:code=KBD_q;break;
case SDLK_w:code=KBD_w;break;
case SDLK_e:code=KBD_e;break;
case SDLK_r:code=KBD_r;break;
case SDLK_t:code=KBD_t;break;
case SDLK_y:code=KBD_y;break;
case SDLK_u:code=KBD_u;break;
case SDLK_i:code=KBD_i;break;
case SDLK_o:code=KBD_o;break;
case SDLK_p:code=KBD_p;break;
case SDLK_a:code=KBD_a;break;
case SDLK_s:code=KBD_s;break;
case SDLK_d:code=KBD_d;break;
case SDLK_f:code=KBD_f;break;
case SDLK_g:code=KBD_g;break;
case SDLK_h:code=KBD_h;break;
case SDLK_j:code=KBD_j;break;
case SDLK_k:code=KBD_k;break;
case SDLK_l:code=KBD_l;break;
case SDLK_z:code=KBD_z;break;
case SDLK_x:code=KBD_x;break;
case SDLK_c:code=KBD_c;break;
case SDLK_v:code=KBD_v;break;
case SDLK_b:code=KBD_b;break;
case SDLK_n:code=KBD_n;break;
case SDLK_m:code=KBD_m;break;
case SDLK_F1:code=KBD_f1;break;
case SDLK_F2:code=KBD_f2;break;
case SDLK_F3:code=KBD_f3;break;
case SDLK_F4:code=KBD_f4;break;
case SDLK_F5:code=KBD_f5;break;
case SDLK_F6:code=KBD_f6;break;
case SDLK_F7:code=KBD_f7;break;
case SDLK_F8:code=KBD_f8;break;
case SDLK_F9:code=KBD_f9;break;
case SDLK_F10:code=KBD_f10;break;
case SDLK_F11:code=KBD_f11;break;
case SDLK_F12:code=KBD_f12;break;
// KBD_esc,KBD_tab,KBD_backspace,KBD_enter,KBD_space,
case SDLK_ESCAPE:code=KBD_esc;break;
case SDLK_TAB:code=KBD_tab;break;
case SDLK_BACKSPACE:code=KBD_backspace;break;
case SDLK_RETURN:code=KBD_enter;break;
case SDLK_SPACE:code=KBD_space;break;
case SDLK_LALT:code=KBD_leftalt;break;
case SDLK_RALT:code=KBD_rightalt;break;
case SDLK_LCTRL:code=KBD_leftctrl;break;
case SDLK_RCTRL:code=KBD_rightctrl;break;
case SDLK_LSHIFT:code=KBD_leftshift;break;
case SDLK_RSHIFT:code=KBD_rightshift;break;
case SDLK_CAPSLOCK:code=KBD_capslock;break;
case SDLK_SCROLLOCK:code=KBD_scrolllock;break;
case SDLK_NUMLOCK:code=KBD_numlock;break;
case SDLK_BACKQUOTE:code=KBD_grave;break;
case SDLK_MINUS:code=KBD_minus;break;
case SDLK_EQUALS:code=KBD_equals;break;
case SDLK_BACKSLASH:code=KBD_backslash;break;
case SDLK_LEFTBRACKET:code=KBD_leftbracket;break;
case SDLK_RIGHTBRACKET:code=KBD_rightbracket;break;
case SDLK_SEMICOLON:code=KBD_semicolon;break;
case SDLK_QUOTE:code=KBD_quote;break;
case SDLK_PERIOD:code=KBD_period;break;
case SDLK_COMMA:code=KBD_comma;break;
case SDLK_SLASH:code=KBD_slash;break;
case SDLK_INSERT:code=KBD_insert;break;
case SDLK_HOME:code=KBD_home;break;
case SDLK_PAGEUP:code=KBD_pageup;break;
case SDLK_DELETE:code=KBD_delete;break;
case SDLK_END:code=KBD_end;break;
case SDLK_PAGEDOWN:code=KBD_pagedown;break;
case SDLK_LEFT:code=KBD_left;break;
case SDLK_UP:code=KBD_up;break;
case SDLK_DOWN:code=KBD_down;break;
case SDLK_RIGHT:code=KBD_right;break;
case SDLK_KP1:code=KBD_kp1;break;
case SDLK_KP2:code=KBD_kp2;break;
case SDLK_KP3:code=KBD_kp3;break;
case SDLK_KP4:code=KBD_kp4;break;
case SDLK_KP5:code=KBD_kp5;break;
case SDLK_KP6:code=KBD_kp6;break;
case SDLK_KP7:code=KBD_kp7;break;
case SDLK_KP8:code=KBD_kp8;break;
case SDLK_KP9:code=KBD_kp9;break;
case SDLK_KP0:code=KBD_kp0;break;
case SDLK_KP_DIVIDE:code=KBD_kpslash;break;
case SDLK_KP_MULTIPLY:code=KBD_kpmultiply;break;
case SDLK_KP_MINUS:code=KBD_kpminus;break;
case SDLK_KP_PLUS:code=KBD_kpplus;break;
case SDLK_KP_ENTER:code=KBD_kpenter;break;
case SDLK_KP_PERIOD:code=KBD_kpperiod;break;
// case SDLK_:code=key_;break;
/* Special Keys */
default:
//TODO maybe give warning for keypress unknown
return;
}
KEYBOARD_AddKey(code,(key->state==SDL_PRESSED));
}
static void HandleMouseMotion(SDL_MouseMotionEvent * motion) {
if (!sdl.mouse_grabbed) {
Mouse_CursorSet((float)motion->x/(float)sdl.width,(float)motion->y/(float)sdl.height);
} else {
Mouse_CursorMoved((float)motion->xrel/(float)sdl.width,(float)motion->yrel/(float)sdl.height);
}
}
static void HandleMouseButton(SDL_MouseButtonEvent * button) {
switch (button->state) {
case SDL_PRESSED:
switch (button->button) {
case SDL_BUTTON_LEFT:
Mouse_ButtonPressed(0);
break;
case SDL_BUTTON_RIGHT:
Mouse_ButtonPressed(1);
break;
case SDL_BUTTON_MIDDLE:
Mouse_ButtonPressed(2);
break;
}
break;
case SDL_RELEASED:
switch (button->button) {
case SDL_BUTTON_LEFT:
Mouse_ButtonReleased(0);
break;
case SDL_BUTTON_RIGHT:
Mouse_ButtonReleased(1);
break;
case SDL_BUTTON_MIDDLE:
Mouse_ButtonReleased(2);
break;
}
break;
}
}
static void HandleJoystickAxis(SDL_JoyAxisEvent * jaxis) {
switch (jaxis->axis) {
case 0:
JOYSTICK_Move_X(0,(float)(jaxis->value/32768.0));
break;
case 1:
JOYSTICK_Move_Y(0,(float)(jaxis->value/32768.0));
break;
}
}
static void HandleJoystickButton(SDL_JoyButtonEvent * jbutton) {
bool state;
state=jbutton->type==SDL_JOYBUTTONDOWN;
if (jbutton->button<2) {
JOYSTICK_Button(0,jbutton->button,state);
}
}
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() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
case SDL_KEYUP:
HandleKey(&event.key);
break;
case SDL_MOUSEMOTION:
HandleMouseMotion(&event.motion);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
HandleMouseButton(&event.button);
break;
case SDL_JOYAXISMOTION:
HandleJoystickAxis(&event.jaxis);
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
HandleJoystickButton(&event.jbutton);
break;
case SDL_VIDEORESIZE:
HandleVideoResize(&event.resize);
break;
case SDL_QUIT:
E_Exit("Closed the SDL Window");
break;
}
}
}
#if 0
void E_Exit(char * format,...) {
char buf[1024];
va_list msg;
strcpy(buf,"EXIT:");
va_start(msg,format);
vsprintf(buf+strlen(buf),format,msg);
va_end(msg);
waddstr(dbg.win_out,buf);
wprintw(dbg.win_out," %d\n",cycle_count);
wrefresh(dbg.win_out);
throw ((Bitu)1);
}
#endif
void GFX_ShowMsg(char * msg) {
char buf[1024];
strcpy(buf,msg);
strcat(buf,"\n");
printf(buf);
};
int main(int argc, char* argv[]) {
try {
if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER
#ifndef DISABLE_JOYSTICK
|SDL_INIT_JOYSTICK
#endif
) < 0 ) {
E_Exit("Can't init SDL");
}
GFX_StartUp();
/* Init all the dosbox subsystems */
DOSBOX_Init(argc,argv);
/* Start the systems that SDL should provide */
#ifndef DISABLE_JOYSTICK
if (SDL_NumJoysticks()>0) {
SDL_JoystickEventState(SDL_ENABLE);
sdl.joy=SDL_JoystickOpen(0);
LOG_MSG("Using joystick %s with %d axes and %d buttons",SDL_JoystickName(0),SDL_JoystickNumAxes(sdl.joy),SDL_JoystickNumButtons(sdl.joy));
JOYSTICK_Enable(0,true);
#endif
}
/* Start dosbox up */
DOSBOX_StartUp();
}
catch (Bitu e) {
LOG_MSG("Exit to error %d",e);
}
GFX_Stop();
return 0;
};

11
src/hardware/Makefile.am Normal file
View file

@ -0,0 +1,11 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
EXTRA_DIST = fmopl.c fmopl.h
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

224
src/hardware/adlib.cpp Normal file
View file

@ -0,0 +1,224 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include <math.h>
#include "dosbox.h"
#include "inout.h"
#include "mixer.h"
#include "timer.h"
#include "hardware.h"
/*
Thanks to vdmsound for nice simple way to implement this
*/
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"
}
struct OPLTimer_t {
bool isEnabled;
bool isMasked;
bool isOverflowed;
Bit32u count;
Bit32u 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
static MIXER_Channel * adlib_chan;
static void ADLIB_CallBack(Bit8u *stream, Bit32u len) {
/* Check for size to update and check for 1 ms updates to the opl registers */
/* Calculate teh machine ms we are at now */
/* update 1 ms of data */
MAME::YM3812UpdateOne(myopl,(MAME::INT16 *)stream,len);
}
static Bit8u read_p388(Bit32u port) {
Bit8u ret=0;
Bit32u new_ticks=GetTicks();
if (timer1.isEnabled) {
if ((new_ticks-timer1.base)>timer1.count) {
timer1.isOverflowed=true;
timer1.base=new_ticks;
}
if (timer1.isOverflowed || !timer1.isMasked) {
ret|=0xc0;
}
}
if (timer2.isEnabled) {
if ((new_ticks-timer2.base)>timer2.count) {
timer2.isOverflowed=true;
timer2.base=new_ticks;
}
if (timer2.isOverflowed || !timer2.isMasked) {
ret|=0xA0;
}
}
return ret;
}
static void write_p388(Bit32u port,Bit8u val) {
regsel=val;
}
static void write_p389(Bit32u port,Bit8u val) {
switch (regsel) {
case 0x02: /* Timer 1 */
timer1.count=(val*80/1000);
return;
case 0x03: /* Timer 2 */
timer2.count=(val*320/1000);
return;
case 0x04: /* IRQ clear / mask and Timer enable */
if (val&0x80) {
timer1.isOverflowed=false;
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();
}
return;
default: /* Normal OPL call queue it */
MAME::OPLWriteReg(myopl,regsel,val);
}
}
static HWBlock hw_adlib;
static bool adlib_enabled;
static void ADLIB_Enable(bool enable) {
if (enable) {
adlib_enabled=true;
MIXER_Enable(adlib_chan,true);
IO_RegisterWriteHandler(0x388,write_p388,"ADLIB Register select");
IO_RegisterWriteHandler(0x389,write_p389,"ADLIB Data Write");
IO_RegisterReadHandler(0x388,read_p388,"ADLIB Status");
IO_RegisterWriteHandler(0x220,write_p388,"ADLIB Register select");
IO_RegisterWriteHandler(0x221,write_p389,"ADLIB Data Write");
IO_RegisterReadHandler(0x220,read_p388,"ADLIB Status");
} else {
adlib_enabled=false;
MIXER_Enable(adlib_chan,false);
IO_FreeWriteHandler(0x220);
IO_FreeWriteHandler(0x221);
IO_FreeReadHandler(0x220);
IO_FreeWriteHandler(0x388);
IO_FreeWriteHandler(0x389);
IO_FreeReadHandler(0x388);
}
}
static void ADLIB_InputHandler(char * line) {
bool s_off=ScanCMDBool(line,"OFF");
bool s_on=ScanCMDBool(line,"ON");
char * rem=ScanCMDRemain(line);
if (rem) {
sprintf(line,"Illegal Switch");
return;
}
if (s_on && s_off) {
sprintf(line,"Can't use /ON and /OFF at the same time");
return;
}
if (s_on) {
ADLIB_Enable(true);
sprintf(line,"Adlib has been enabled");
return;
}
if (s_off) {
ADLIB_Enable(false);
sprintf(line,"Adlib has been disabled");
return;
}
return;
}
static void ADLIB_OutputHandler (char * towrite) {
if(adlib_enabled) {
sprintf(towrite,"IO %X",0x388);
} else {
sprintf(towrite,"Disabled");
}
};
void ADLIB_Init(void) {
timer1.isMasked=true;
timer1.base=0;
timer1.count=0;
timer1.isEnabled=false;
timer1.isOverflowed=false;
timer2.isMasked=true;
timer2.base=0;
timer2.count=0;
timer2.isEnabled=false;
timer2.isOverflowed=false;
#define ADLIB_FREQ 22050
myopl=MAME::OPLCreate(0,OPL_INTERNAL_FREQ,ADLIB_FREQ);
adlib_chan=MIXER_AddChannel(ADLIB_CallBack,ADLIB_FREQ,"ADLIB");
MIXER_SetMode(adlib_chan,MIXER_16MONO);
hw_adlib.dev_name="ADLIB";
hw_adlib.full_name="Adlib FM Synthesizer";
hw_adlib.next=0;
hw_adlib.help="/ON Enables Adlib\n/OFF Disables Adlib\n";
hw_adlib.get_input=ADLIB_InputHandler;
hw_adlib.show_status=ADLIB_OutputHandler;
HW_Register(&hw_adlib);
ADLIB_Enable(true);
};

225
src/hardware/dma.cpp Normal file
View file

@ -0,0 +1,225 @@
/*
* 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.
*/
/*
Based the port handling from the bochs dma code.
*/
/*
Still need to implement reads from dma ports :)
Perhaps sometime also implement dma writes.
DMA transfer that get setup with a size 0 are also done wrong should be 0x10000 probably.
*/
#include <string.h>
#include "dosbox.h"
#include "mem.h"
#include "inout.h"
#include "dma.h"
#ifdef DEBUG_DMA
#define DMA_DEBUG LOG_DEBUG
#else
#define DMA_DEBUG
#endif
#define DMA_MODE_DEMAND 0
#define DMA_MODE_SINGLE 1
#define DMA_MODE_BLOCK 2
#define DMA_MODE_CASCADE 3
struct DMA_CHANNEL {
struct {
Bit8u mode_type;
Bit8u address_decrement;
Bit8u autoinit_enable;
Bit8u transfer_type;
} mode;
Bit16u base_address;
Bit16u base_count;
Bit16u current_address;
Bit32u current_count;
Bit8u page;
bool masked;
HostPt host_address;
bool addr_changed;
};
struct DMA_CONTROLLER {
bool flipflop;
Bit8u status_reg;
Bit8u command_reg;
DMA_CHANNEL chan[4];
};
static DMA_CONTROLLER dma[2];
static void write_dma(Bit32u port,Bit8u val) {
/* only use first dma for now */
DMA_CONTROLLER * cont=&dma[0];
DMA_CHANNEL * chan=&cont->chan[port>>1];
switch (port) {
case 0x00:case 0x02:case 0x04:case 0x06:
if (cont->flipflop) {
chan->base_address=val;
} else {
chan->base_address|=(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;
} else {
chan->base_count|=(val<<8);
}
cont->flipflop=!cont->flipflop;
chan->addr_changed=true;
break;
case 0x08: /* Command Register */
if (val != 4) LOG_WARN("DMA1:Illegal command %2X",val);
cont->command_reg=val;
break;
case 0x09: /* Request Register */
if (val&4) {
/* Set Request bit */
} else {
Bitu channel = val & 0x03;
cont->status_reg &= ~(1 << (channel+4));
}
break;
case 0x0a: /* single mask bit register */
chan->masked=(val & 4)>0;
break;
case 0x0b: /* mode register */
chan->mode.mode_type = (val >> 6) & 0x03;
chan->mode.address_decrement = (val >> 5) & 0x01;
chan->mode.autoinit_enable = (val >> 4) & 0x01;
chan->mode.transfer_type = (val >> 2) & 0x03;
if (chan->mode.address_decrement) {
LOG_WARN("DMA:Address Decrease not supported yet");
}
break;
case 0x0c: /* Clear Flip/Flip */
cont->flipflop=true;
break;
};
};
static Bit8u channelindex[7] = {2, 3, 1, 0, 0, 0, 0};
void write_dma_page(Bit32u port,Bit8u val) {
switch (port) {
case 0x81: /* dma0 page register, channel 2 */
case 0x82: /* dma0 page register, channel 3 */
case 0x83: /* dma0 page register, channel 1 */
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;
}
}
void DMA_8_Read(Bit32u dmachan,Bit8u * buffer,Bit16u count) {
DMA_CHANNEL * chan=&dma[0].chan[dmachan];
/* DMA always does autoinit should work under normal situations */
if (chan->addr_changed) {
/* Calculate the new starting position for dma read*/
chan->addr_changed=false;
chan->host_address=memory+(chan->page << 16)+chan->base_address;
chan->current_count=chan->base_count+1;
chan->current_address=chan->base_address;
DMA_DEBUG("DMA:Transfer from %d size %d",(chan->page << 16)+chan->base_address,chan->current_count);
}
if (!count) return;
if (chan->current_count>=count) {
memcpy(buffer,chan->host_address,count);
chan->host_address+=count;
chan->current_address+=count;
chan->current_count-=count;
return;
} else {
/* Copy remaining piece of first buffer */
memcpy(buffer,chan->host_address,chan->current_count);
buffer+=chan->current_count;
count-=(Bit16u)chan->current_count;
/* Autoinit reset the dma channel */
chan->host_address=memory+(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 */
memcpy(buffer,chan->host_address,count);
chan->host_address+=count;
chan->current_address+=count;
chan->current_count-=count;
return;
}
};
void DMA_8_Write(Bit32u dmachan,Bit8u * buffer,Bit16u count) {
if (dma[0].chan[dmachan].addr_changed) {
/* Calculate the new starting position for dma read*/
dma[0].chan[dmachan].addr_changed=false;
dma[0].chan[dmachan].host_address=memory+(dma[0].chan[dmachan].page << 16)+dma[0].chan[dmachan].base_address;
dma[0].chan[dmachan].current_count=dma[0].chan[dmachan].base_count;
dma[0].chan[dmachan].current_count=dma[0].chan[dmachan].current_count;
}
if (dma[0].chan[dmachan].current_count>=count) {
memcpy(dma[0].chan[dmachan].host_address,buffer,count);
dma[0].chan[dmachan].host_address+=count;
dma[0].chan[dmachan].current_address+=count;
dma[0].chan[dmachan].current_count-=count;
return;
} else {
}
return;
};
void DMA_16_Read(Bit32u dmachan,Bit8u * buffer,Bit16u count) {
}
void DMA_16_Write(Bit32u dmachan,Bit8u * buffer,Bit16u count) {
}
void DMA_Init(void) {
for (Bit32u i=0;i<0x10;i++) {
IO_RegisterWriteHandler(i,write_dma,"DMA1");
}
IO_RegisterWriteHandler(0x81,write_dma_page,"DMA Pages");
IO_RegisterWriteHandler(0x82,write_dma_page,"DMA Pages");
IO_RegisterWriteHandler(0x83,write_dma_page,"DMA Pages");
IO_RegisterWriteHandler(0x87,write_dma_page,"DMA Pages");
}

9730
src/hardware/ega-switch.h Normal file

File diff suppressed because it is too large Load diff

1878
src/hardware/fmopl.c Normal file

File diff suppressed because it is too large Load diff

191
src/hardware/fmopl.h Normal file
View file

@ -0,0 +1,191 @@
#ifndef __FMOPL_H_
#define __FMOPL_H_
/* --- select emulation chips --- */
#define BUILD_YM3812 (HAS_YM3812)
#define BUILD_YM3526 (HAS_YM3526)
#define BUILD_Y8950 (HAS_Y8950)
/* --- system optimize --- */
/* select bit size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16
/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if (OPL_SAMPLE_BITS==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_SAMPLE_BITS==8)
typedef unsigned char 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 */
/* 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] */
/* Phase Generator */
UINT32 Cnt; /* frequency count */
UINT32 Incr; /* frequency step */
/* 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 */
UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
/* LFO */
UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
/* waveform select */
unsigned int *wavetable;
}OPL_SLOT;
/* ---------- 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 */
/* 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) */
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;
/* 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 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);
/* YM3626/YM3812 local section */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
#endif

2562
src/hardware/font-switch.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,256 @@
/*
* 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 <math.h>
#include "dosbox.h"
#include "inout.h"
#include "mixer.h"
#include "mem.h"
#include "hardware.h"
#define CMS_RATE 22050
#define CMS_VOLUME 6000
#define FREQ_SHIFT 16
#define SIN_ENT 1024
#define SIN_MAX (SIN_ENT << FREQ_SHIFT)
#ifndef PI
#define PI 3.14159265358979323846
#endif
struct CMS {
struct {
Bit32u freq_pos;
Bit32u freq_add;
Bit16s * vol_left;
Bit16s * vol_right;
Bit8u octave;
Bit8u freq;
} chan[6];
struct {
Bit32u freq_pos;
Bit32u freq_add;
Bit32u random_val;
} noise[2];
Bit8u voice_enabled;
Bit8u noise_enabled;
Bit8u reg;
};
static Bit32u freq_table[256][8];
static Bit32u noise_freq[3];
static Bit16s vol_table[16];
static Bit16s sin_table[16][SIN_ENT];
static MIXER_Channel * cms_chan;
static CMS cms_block[2];
static void write_cms(Bit32u port,Bit8u val) {
Bit32u sel=(port>>1)&1;
CMS * cms=&cms_block[sel];
switch (port & 1) {
case 1: /* Register Select */
cms->reg=val;
break;
case 0: /* Write Register */
switch (cms->reg) {
case 0x00: case 0x01: case 0x02: /* Volume Select */
case 0x03: case 0x04: case 0x05:
cms->chan[cms->reg].vol_left=sin_table[val & 0xf];
cms->chan[cms->reg].vol_right=sin_table[(val>>4) & 0xf];
break;
case 0x08: case 0x09: case 0x0a: /* Frequency Select */
case 0x0b: case 0x0c: case 0x0d:
{
Bit8u chan=cms->reg-0x08;
cms->chan[chan].freq=val;
/* Get a new entry in the freq table */
cms->chan[chan].freq_add=freq_table[cms->chan[chan].freq][cms->chan[chan].octave];
break;
}
case 0x10: case 0x11: case 0x12: /* Octave Select */
{
Bit8u chan=(cms->reg-0x10)*2;
cms->chan[chan].octave=val&7;
cms->chan[chan].freq_add=freq_table[cms->chan[chan].freq][cms->chan[chan].octave];
chan++;
cms->chan[chan].octave=(val>>4)&7;
cms->chan[chan].freq_add=freq_table[cms->chan[chan].freq][cms->chan[chan].octave];
}
break;
case 0x14: /* Frequency enable */
cms->voice_enabled=val;
//TODO Check for enabling of speaker maybe
break;
case 0x15: /* Noise Enable */
cms->noise_enabled=val;
//TODO Check for enabling of speaker maybe
break;
case 0x16: /* Noise generator setup */
cms->noise[0].freq_add=noise_freq[val & 3];
cms->noise[1].freq_add=noise_freq[(val>>4) & 3];
break;
default:
LOG_ERROR("CMS %d:Illegal register %X2 Selected for write",sel,cms->reg);
break;
};
break;
}
};
static void CMS_CallBack(Bit8u * stream,Bit32u len) {
/* Generate the CMS wave */
/* Generate 12 channels of sound data this could be nice */
for (Bit32u l=0;l<len;l++) {
register Bit32s left,right;
left=right=0;
for (int c=0;c<2;c++) {
CMS * cms=&cms_block[c];
Bit8u use_voice=1;
for (int chan=0;chan<6;chan++) {
if (cms->noise_enabled & use_voice) {
} else if (cms->voice_enabled & use_voice) {
int pos=cms->chan[chan].freq_pos>>FREQ_SHIFT;
left+=cms->chan[chan].vol_left[pos];
right+=cms->chan[chan].vol_right[pos];
cms->chan[chan].freq_pos+=cms->chan[chan].freq_add;
if (cms->chan[chan].freq_pos>=SIN_MAX)
cms->chan[chan].freq_pos-=SIN_MAX;
}
use_voice<<=1;
}
}
if (left>MAX_AUDIO) *(Bit16s *)stream=MAX_AUDIO;
else if (left<MIN_AUDIO) *(Bit16s *)stream=MIN_AUDIO;
else *(Bit16s *)stream=(Bit16s)left;
stream+=2;
if (right>MAX_AUDIO) *(Bit16s *)stream=MAX_AUDIO;
else if (right<MIN_AUDIO) *(Bit16s *)stream=MIN_AUDIO;
else *(Bit16s *)stream=(Bit16s)right;
stream+=2;
}
}
static HWBlock hw_cms;
static bool cms_enabled;
static void CMS_Enable(bool enable) {
if (enable) {
cms_enabled=true;
MIXER_Enable(cms_chan,true);
IO_RegisterWriteHandler(0x220,write_cms,"CMS");
IO_RegisterWriteHandler(0x221,write_cms,"CMS");
IO_RegisterWriteHandler(0x222,write_cms,"CMS");
IO_RegisterWriteHandler(0x223,write_cms,"CMS");
} else {
cms_enabled=false;
MIXER_Enable(cms_chan,false);
IO_FreeWriteHandler(0x220);
IO_FreeWriteHandler(0x221);
IO_FreeWriteHandler(0x222);
IO_FreeWriteHandler(0x223);
}
}
static void CMS_InputHandler(char * line) {
bool s_off=ScanCMDBool(line,"OFF");
bool s_on=ScanCMDBool(line,"ON");
char * rem=ScanCMDRemain(line);
if (rem) {
sprintf(line,"Illegal Switch");
return;
}
if (s_on && s_off) {
sprintf(line,"Can't use /ON and /OFF at the same time");
return;
}
if (s_on) {
CMS_Enable(true);
sprintf(line,"Creative Music System has been enabled");
return;
}
if (s_off) {
CMS_Enable(false);
sprintf(line,"Creative Music System has been disabled");
return;
}
return;
}
static void CMS_OutputHandler (char * towrite) {
if(cms_enabled) {
sprintf(towrite,"IO %X",0x220);
} else {
sprintf(towrite,"Disabled");
}
};
void CMS_Init(void) {
Bits i;
/* Register the Mixer CallBack */
cms_chan=MIXER_AddChannel(CMS_CallBack,CMS_RATE,"CMS");
MIXER_SetMode(cms_chan,MIXER_16STEREO);
MIXER_Enable(cms_chan,false);
/* Register with the hardware setup tool */
hw_cms.dev_name="CMS";
hw_cms.full_name="Creative Music System";
hw_cms.next=0;
hw_cms.help="/ON Enables CMS\n/OFF Disables CMS\n";
hw_cms.get_input=CMS_InputHandler;
hw_cms.show_status=CMS_OutputHandler;
HW_Register(&hw_cms);
CMS_Enable(false);
/* Make the frequency/octave table */
double log_start=log10(27.34375);
double log_add=(log10(54.609375)-log10(27.34375))/256;
for (i=0;i<256;i++) {
double freq=pow(10,log_start);
for (int k=0;k<8;k++) {
freq_table[i][k]=(Bit32u)((double)SIN_MAX/(CMS_RATE/freq));
freq*=2;
}
log_start+=log_add;
}
// noise_freq[0]=(Bit32u)(FREQ_MAX/((float)CMS_RATE/(float)28000));
// noise_freq[1]=(Bit32u)(FREQ_MAX/((float)CMS_RATE/(float)14000));
// noise_freq[2]=(Bit32u)(FREQ_MAX/((float)CMS_RATE/(float)6800));
for (int s=0;s<SIN_ENT;s++) {
double out=sin( (2*PI/SIN_ENT)*s)*CMS_VOLUME;
for (i=15;i>=0;i--) {
sin_table[i][s]=(Bit16s)out;
// out /= (float)1.258925412; /* = 10 ^ (2/20) = 2dB */
out /= 1.1;
}
}
}

117
src/hardware/hardware.cpp Normal file
View file

@ -0,0 +1,117 @@
/*
* 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.
*/
/*
This could do with a serious revision :)
*/
#include <string.h>
#include "dosbox.h"
#include "programs.h"
#include "hardware.h"
static HWBlock * firsthw=0;
class HWSET : public Program {
public:
HWSET(PROGRAM_Info * program_info);
void Run(void);
};
HWSET::HWSET(PROGRAM_Info * info):Program(info) {
}
void HW_Register(HWBlock * block) {
block->next=firsthw;
firsthw=block;
}
void HWSET::Run(void) {
/* Hopefull enough space */
char buf[1024];
HWBlock * loopblock;
if (!*prog_info->cmd_line) {
/* No command line given give overview of hardware */
loopblock=firsthw;
WriteOut("ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿");
WriteOut("³Device ³Full Name ³Status ³");
WriteOut("ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´");
while (loopblock) {
if (loopblock->show_status) {
loopblock->show_status(buf);
} else {
strcpy(buf,"No Status Handler");
}
WriteOut("³%-8s³%-25s³%-43s³",loopblock->dev_name,loopblock->full_name,buf);
loopblock=loopblock->next;
}
WriteOut("ÀÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");
WriteOut("If you want to setup specific hardware use \"HWSET Device\" for information.\n");
return;
}
/* Command line given */
if (strcmp(prog_info->cmd_line,"/?")==0) {
WriteOut("Hardware setup tool for DOSBox.\n");
WriteOut("This program can be used to change the settings of internal hardware.\n\n"
"HWSET [device] [switches]\n\n"
"Using an empty command line gives you a list of hardware.\n"
"You can get list of switches for a device with HWSET device.\n"
);
return;
}
char * rest=strchr(prog_info->cmd_line,' ');
if (rest) *rest++=0;
loopblock=firsthw;
while (loopblock) {
if (strcasecmp(loopblock->dev_name,prog_info->cmd_line)==0) goto founddev;
loopblock=loopblock->next;
}
WriteOut("Device %s not found\n",prog_info->cmd_line);
return;
founddev:
/* Check for rest of line */
if (rest) {
strcpy(buf,rest);
loopblock->get_input(buf);
WriteOut(buf);
} else {
WriteOut("Command overview for %s\n%s",loopblock->full_name,loopblock->help);
}
return;
}
static void HWSET_ProgramStart(PROGRAM_Info * info) {
HWSET * tempHWSET=new HWSET(info);
tempHWSET->Run();
delete tempHWSET;
}
void HARDWARE_Init(void) {
PROGRAMS_MakeFile("HWSET.COM",HWSET_ProgramStart);
};

View file

@ -0,0 +1,91 @@
/*
* 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 "inout.h"
IO_ReadBlock IO_ReadTable[IO_MAX];
IO_WriteBlock IO_WriteTable[IO_MAX];
void IO_Write(Bitu num,Bit8u val) {
if (num<IO_MAX) IO_WriteTable[num].handler(num,val);
else LOG_ERROR("IO:Out or range write %X2 to port %4X",val,num);
}
Bit8u IO_Read(Bitu num) {
if (num<IO_MAX) return IO_ReadTable[num].handler(num);
else LOG_ERROR("IO:Out or range read from port %4X",num);
return 0xff;
}
static Bit8u IO_ReadBlocked(Bit32u port) {
return 0xff;
}
static void IO_WriteBlocked(Bit32u port,Bit8u val) {
}
static Bit8u IO_ReadDefault(Bit32u port) {
LOG_WARN("Reading from undefined port %04X",port);
IO_RegisterReadHandler(port,&IO_ReadBlocked,"Blocked Read");
return 0xff;
}
void IO_WriteDefault(Bit32u port,Bit8u val) {
LOG_WARN("Writing %02X to undefined port %04X",val,port);
IO_RegisterWriteHandler(port,&IO_WriteBlocked,"Blocked Write");
}
void IO_RegisterReadHandler(Bit32u port,IO_ReadHandler * handler,char * name) {
if (port<IO_MAX) {
IO_ReadTable[port].handler=handler;
IO_ReadTable[port].name=name;
}
}
void IO_RegisterWriteHandler(Bit32u port,IO_WriteHandler * handler,char * name) {
if (port<IO_MAX) {
IO_WriteTable[port].handler=handler;
IO_WriteTable[port].name=name;
}
}
void IO_FreeReadHandler(Bit32u port) {
if (port<IO_MAX) {
IO_RegisterReadHandler(port,&IO_ReadDefault,"Default Read");
}
}
void IO_FreeWriteHandler(Bit32u port) {
if (port<IO_MAX) {
IO_RegisterWriteHandler(port,&IO_WriteDefault,"Default Write");
}
}
void IO_Init(void) {
for (Bitu i=0;i<IO_MAX;i++) {
IO_RegisterReadHandler(i,&IO_ReadDefault,"Default Read");
IO_RegisterWriteHandler(i,&IO_WriteDefault,"Default Write");
}
}

101
src/hardware/joystick.cpp Normal file
View file

@ -0,0 +1,101 @@
/*
* 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 "inout.h"
#define RANGE 64
struct JoyStick {
bool enabled;
float xpos,ypos;
Bitu xcount,ycount;
bool button[2];
};
static JoyStick stick[2];
static Bit8u read_p201(Bit32u port) {
/** Format of the byte to be returned:
** | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
** +-------------------------------+
** | | | | | | | |
** Joystick B, Button 2 ---+ | | | | | | +--- Joystick A, X Axis
** Joystick B, Button 1 -------+ | | | | +------- Joystick A, Y Axis
** Joystick A, Button 2 -----------+ | | +----------- Joystick B, X Axis
** Joystick A, Button 1 ---------------+ +--------------- Joystick B, Y Axis
**/
Bit8u ret=0xff;
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[1].enabled) {
if (stick[1].xcount) stick[0].xcount--; else ret&=~4;
if (stick[1].ycount) stick[0].ycount--; else ret&=~8;
if (stick[1].button[0]) ret&=64;
if (stick[1].button[1]) ret&=128;
}
return ret;
}
static void write_p201(Bit32u port,Bit8u val) {
if (stick[0].enabled) {
stick[0].xcount=(Bitu)(stick[0].xpos*RANGE+RANGE*2);
stick[0].ycount=(Bitu)(stick[0].ypos*RANGE+RANGE*2);
}
if (stick[1].enabled) {
stick[1].xcount=(Bitu)(stick[1].xpos*RANGE+RANGE*2);
stick[1].ycount=(Bitu)(stick[1].ypos*RANGE+RANGE*2);
}
}
void JOYSTICK_Enable(Bitu which,bool enabled) {
if (which<2) stick[which].enabled=enabled;
}
void JOYSTICK_Button(Bitu which,Bitu num,bool pressed) {
if ((which<2) && (num<2)) stick[which].button[num]=pressed;
}
void JOYSTICK_Move_X(Bitu which,float x) {
if (which<2) {
stick[which].xpos=x;
}
}
void JOYSTICK_Move_Y(Bitu which,float y) {
if (which<2) {
stick[which].ypos=y;
}
}
void JOYSTICK_Init(void) {
IO_RegisterReadHandler(0x201,read_p201,"JOYSTICK");
IO_RegisterWriteHandler(0x201,write_p201,"JOYSTICK");
stick[0].enabled=false;
stick[1].enabled=false;
}

260
src/hardware/keyboard.cpp Normal file
View file

@ -0,0 +1,260 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "keyboard.h"
#include "inout.h"
#include "pic.h"
#include "mixer.h"
#define KEYBUFSIZE 32
struct KeyEvent {
Bitu type;
Bitu state;
KEYBOARD_EventHandler * handler;
KeyEvent * next;
};
static Bitu shift_state=0;
static Bit8u cur_scancode;
static Bit8u kbuf[KEYBUFSIZE];
static Bitu kbuf_pos;
static Bitu kbuf_used;
static Bit8u port_61_data;
//TODO Are these initialized at 0 at startup? Hope so :)
static KeyEvent * event_handlers[KBD_LAST];
static Bit8u read_p60(Bit32u port) {
if (kbuf_used>0) {
cur_scancode=kbuf[kbuf_pos];
};
return cur_scancode;
}
static void write_p60(Bit32u port,Bit8u val) {
//TODO Work this out ;)
LOG_DEBUG("Port 60 write with val %d",val);
}
static Bit8u read_p61(Bit32u port) {
return port_61_data;
};
static void write_p61(Bit32u port,Bit8u val) {
//TODO Enable spreaker through here :)
if ((val&128)) { /* Keyboard acknowledge */
kbuf_used--;
kbuf_pos++;
if (kbuf_pos>=KEYBUFSIZE) kbuf_pos=0;
if (kbuf_used>0) PIC_ActivateIRQ(1);
}
port_61_data=val;
if ((val & 3)==3) {
PCSPEAKER_Enable(true);
} else {
PCSPEAKER_Enable(false);
}
}
void KEYBOARD_AddCode(Bit8u code) {
//Now Raise the keyboard IRQ
//If the buffer is full just drop the scancode :)
if (kbuf_used<KEYBUFSIZE) {
Bit32u start=kbuf_used+kbuf_pos;
kbuf_used++;
if (start>=KEYBUFSIZE) start-=KEYBUFSIZE;
kbuf[start]=code;
}
PIC_ActivateIRQ(1);
}
void KEYBOARD_AddEvent(Bitu keytype,Bitu state,KEYBOARD_EventHandler * handler) {
KeyEvent * newevent=new KeyEvent;
/* Add the event in the correct key structure */
if (keytype>=KBD_LAST) {
LOG_ERROR("KEYBOARD:Illegal key %d for handler",keytype);
}
newevent->next=event_handlers[keytype];
event_handlers[keytype]=newevent;
newevent->type=keytype;
newevent->state=state;
newevent->handler=handler;
};
void KEYBOARD_AddKey(Bitu keytype,bool pressed) {
bool extend=false;
Bit8u ret=0;
switch (keytype) {
case KBD_esc:ret=1;break;
case KBD_1:ret=2;break;
case KBD_2:ret=3;break;
case KBD_3:ret=4;break;
case KBD_4:ret=5;break;
case KBD_5:ret=6;break;
case KBD_6:ret=7;break;
case KBD_7:ret=8;break;
case KBD_8:ret=9;break;
case KBD_9:ret=10;break;
case KBD_0:ret=11;break;
case KBD_minus:ret=12;break;
case KBD_equals:ret=13;break;
case KBD_backspace:ret=14;break;
case KBD_tab:ret=15;break;
case KBD_q:ret=16;break;
case KBD_w:ret=17;break;
case KBD_e:ret=18;break;
case KBD_r:ret=19;break;
case KBD_t:ret=20;break;
case KBD_y:ret=21;break;
case KBD_u:ret=22;break;
case KBD_i:ret=23;break;
case KBD_o:ret=24;break;
case KBD_p:ret=25;break;
case KBD_leftbracket:ret=26;break;
case KBD_rightbracket:ret=27;break;
case KBD_enter:ret=28;break;
case KBD_leftctrl:ret=29;
shift_state=(shift_state&~CTRL_PRESSED)|(pressed ? CTRL_PRESSED:0);
break;
case KBD_a:ret=30;break;
case KBD_s:ret=31;break;
case KBD_d:ret=32;break;
case KBD_f:ret=33;break;
case KBD_g:ret=34;break;
case KBD_h:ret=35;break;
case KBD_j:ret=36;break;
case KBD_k:ret=37;break;
case KBD_l:ret=38;break;
case KBD_semicolon:ret=39;break;
case KBD_quote:ret=40;break;
case KBD_grave:ret=41;break;
case KBD_leftshift:ret=42;
shift_state=(shift_state&~SHIFT_PRESSED)|(pressed ? SHIFT_PRESSED:0);
break;
case KBD_backslash:ret=43;break;
case KBD_z:ret=44;break;
case KBD_x:ret=45;break;
case KBD_c:ret=46;break;
case KBD_v:ret=47;break;
case KBD_b:ret=48;break;
case KBD_n:ret=49;break;
case KBD_m:ret=50;break;
case KBD_comma:ret=51;break;
case KBD_period:ret=52;break;
case KBD_slash:ret=53;break;
case KBD_rightshift:ret=54;break;
case KBD_kpmultiply:ret=55;break;
case KBD_leftalt:ret=56;
shift_state=(shift_state&~ALT_PRESSED)|(pressed ? ALT_PRESSED:0);
break;
case KBD_space:ret=57;break;
case KBD_capslock:ret=58;break;
case KBD_f1:ret=59;break;
case KBD_f2:ret=60;break;
case KBD_f3:ret=61;break;
case KBD_f4:ret=62;break;
case KBD_f5:ret=63;break;
case KBD_f6:ret=64;break;
case KBD_f7:ret=65;break;
case KBD_f8:ret=66;break;
case KBD_f9:ret=67;break;
case KBD_f10:ret=68;break;
case KBD_numlock:ret=69;break;
case KBD_scrolllock:ret=70;break;
case KBD_kp7:ret=71;break;
case KBD_kp8:ret=72;break;
case KBD_kp9:ret=73;break;
case KBD_kpminus:ret=74;break;
case KBD_kp4:ret=75;break;
case KBD_kp5:ret=76;break;
case KBD_kp6:ret=77;break;
case KBD_kpplus:ret=78;break;
case KBD_kp1:ret=79;break;
case KBD_kp2:ret=80;break;
case KBD_kp3:ret=81;break;
case KBD_kp0:ret=82;break;
case KBD_kpperiod:ret=83;break;
case KBD_f11:ret=87;break;
case KBD_f12:ret=88;break;
//The Extended keys
case KBD_kpenter:extend=true;ret=28;break;
case KBD_rightctrl:extend=true;ret=29;break;
case KBD_kpslash:extend=true;ret=53;break;
case KBD_rightalt:extend=true;ret=56;break;
case KBD_home:extend=true;ret=71;break;
case KBD_up:extend=true;ret=72;break;
case KBD_pageup:extend=true;ret=73;break;
case KBD_left:extend=true;ret=75;break;
case KBD_right:extend=true;ret=77;break;
case KBD_end:extend=true;ret=79;break;
case KBD_down:extend=true;ret=80;break;
case KBD_pagedown:extend=true;ret=81;break;
case KBD_insert:extend=true;ret=82;break;
case KBD_delete:extend=true;ret=83;break;
default:
E_Exit("Unsopperted key press");
break;
};
/* check for active key events */
KeyEvent * checkevent=event_handlers[keytype];
while (checkevent) {
if ((shift_state & checkevent->state)==checkevent->state) {
if (checkevent->type==keytype && pressed) {
(*checkevent->handler)();
return;
}
if (checkevent->type==keytype) return;
}
checkevent=checkevent->next;
}
if (extend) KEYBOARD_AddCode(224);
if (!pressed) ret+=128;
KEYBOARD_AddCode(ret);
};
void KEYBOARD_Init(void) {
kbuf_used=0;kbuf_pos=0;
IO_RegisterWriteHandler(0x60,write_p60,"Keyboard");
IO_RegisterReadHandler(0x60,read_p60,"Keyboard");
IO_RegisterWriteHandler(0x61,write_p61,"Keyboard");
IO_RegisterReadHandler(0x61,read_p61,"Keyboard");
port_61_data=1; /* Speaker control through PIT and speaker disabled */
// memset(&event_handlers,0,sizeof(event_handlers));
};

299
src/hardware/memory.cpp Normal file
View file

@ -0,0 +1,299 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "dosbox.h"
#include "mem.h"
#define MEM_MAXSIZE 16 /* The Size of memory used to get size of page table */
#define memsize 8 /* 8 mb of memory */
#define EMM_HANDLECOUNT 250
EMM_Handle EMM_Handles[EMM_HANDLECOUNT];
PageEntry * PageEntries[MEM_MAXSIZE*1024*16]; /* Number of pages */
Bit8u * memory=0;
bool MEMORY_TestSpecial(PhysPt off) {
return (PageEntries[off >> 12]>0);
}
void MEMORY_SetupHandler(Bit32u page,Bit32u pages,PageEntry * entry) {
for (Bit32u i=page;i<page+pages;i++) {
PageEntries[i]=entry;
}
}
void MEMORY_ResetHandler(Bit32u page,Bit32u pages) {
for (Bit32u i=page;i<page+pages;i++) {
PageEntries[i]=0;
}
};
void MEM_BlockRead(PhysPt off,void * data,Bitu size) {
Bitu c;
Bit8u * idata=(Bit8u *)data;
for (c=1;c<=(size>>2);c++) {
writed(idata,mem_readd(off));
idata+=4;off+=4;
}
for (c=1;c<=(size&3);c++) {
writeb(idata,mem_readb(off));
idata+=1;off+=1;
}
}
void MEM_BlockWrite(PhysPt off,void * data,Bitu size) {
Bitu c;
Bit8u * idata=(Bit8u *)data;
for (c=1;c<=(size>>2);c++) {
mem_writed(off,readd(idata));
idata+=4;off+=4;
}
for (c=1;c<=(size&3);c++) {
mem_writeb(off,readb(idata));
idata+=1;off+=1;
}
}
void MEM_BlockCopy(PhysPt dest,PhysPt src,Bitu size) {
Bitu c;
for (c=1;c<=(size>>2);c++) {
mem_writed(dest,mem_readd(src));
dest+=4;src+=4;
}
for (c=1;c<=(size&3);c++) {
mem_writeb(dest,mem_readb(src));
dest+=1;src+=1;
}
};
void MEM_StrCopy(PhysPt off,char * data,Bitu size) {
Bit8u c;
while ((c=mem_readb(off)) && size) {
*data=c;
off++;data++;size--;
}
*data='\0';
}
/* TODO Maybe check for page boundaries but that would be wasting lot's of time */
void mem_writeb(PhysPt off,Bit8u val) {
PageEntry * entry=PageEntries[off >> 12];
if (!entry) { writeb(memory+off,val);return; }
switch (entry->type) {
case MEMORY_RELOCATE:
writeb(entry->relocate+(off-entry->base),val);
break;
case MEMORY_HANDLER:
entry->handler.write(off-entry->base,val);
break;
default:
E_Exit("Write to Illegal Memory Address %4x",off);
}
}
void mem_writew(PhysPt off,Bit16u val) {
PageEntry * entry=PageEntries[off >> 12];
if (!entry) { writew(memory+off,val);return; }
switch (entry->type) {
case MEMORY_RELOCATE:
writew(entry->relocate+(off-entry->base),val);
break;
case MEMORY_HANDLER:
entry->handler.write(off-entry->base,(val & 0xFF));
entry->handler.write(off-entry->base+1,(val >> 8));
break;
default:
E_Exit("Write to Illegal Memory Address %4x",off);
}
}
void mem_writed(PhysPt off,Bit32u val) {
PageEntry * entry=PageEntries[off >> 12];
if (!entry) { writed(memory+off,val);return; }
switch (entry->type) {
case MEMORY_RELOCATE:
writed(entry->relocate+(off-entry->base),val);
break;
case MEMORY_HANDLER:
entry->handler.write(off-entry->base, (Bit8u)(val & 0xFF));
entry->handler.write(off-entry->base+1,(Bit8u)(val >> 8) & 0xFF);
entry->handler.write(off-entry->base+2,(Bit8u)(val >> 16) & 0xFF);
entry->handler.write(off-entry->base+3,(Bit8u)(val >> 24) & 0xFF);
break;
default:
E_Exit("Write to Illegal Memory Address %4x",off);
}
}
Bit8u mem_readb(PhysPt off) {
PageEntry * entry=PageEntries[off >> 12];
if (!entry) { return readb(memory+off);}
switch (entry->type) {
case MEMORY_RELOCATE:
return readb(entry->relocate+(off-entry->base));
case MEMORY_HANDLER:
return entry->handler.read(off-entry->base);
break;
default:
E_Exit("Read from Illegal Memory Address %4x",off);
}
return 0; /* Keep compiler happy */
}
Bit16u mem_readw(PhysPt off) {
PageEntry * entry=PageEntries[off >> 12];
if (!entry) { return readw(memory+off);}
switch (entry->type) {
case MEMORY_RELOCATE:
return readw(entry->relocate+(off-entry->base));
case MEMORY_HANDLER:
return entry->handler.read(off-entry->base) |
(entry->handler.read(off-entry->base+1) << 8);
break;
default:
E_Exit("Read from Illegal Memory Address %4x",off);
}
return 0; /* Keep compiler happy */
}
Bit32u mem_readd(PhysPt off) {
PageEntry * entry=PageEntries[off >> 12];
if (!entry) { return readd(memory+off);}
switch (entry->type) {
case MEMORY_RELOCATE:
return readd(entry->relocate+(off-entry->base));
case MEMORY_HANDLER:
return entry->handler.read(off-entry->base) |
(entry->handler.read(off-entry->base+1) << 8) |
(entry->handler.read(off-entry->base+2) << 16)|
(entry->handler.read(off-entry->base+3) << 24);
break;
default:
E_Exit("Read from Illegal Memory Address %4x",off);
}
return 0; /* Keep compiler happy */
}
/* The EMM Allocation Part */
/* If this returns 0 we got and error since 0 is always taken */
static Bit16u EMM_GetFreeHandle(void) {
Bit16u i=0;
while (i<EMM_HANDLECOUNT) {
if (!EMM_Handles[i].active) return i;
i++;
}
E_Exit("MEMORY:Out of EMM Memory handles");
return 0;
}
void EMM_GetFree(Bit16u * maxblock,Bit16u * total) {
Bit32u index=0;
*maxblock=0;*total=0;
while (EMM_Handles[index].active) {
if (EMM_Handles[index].free) {
if(EMM_Handles[index].size>*maxblock) *maxblock=EMM_Handles[index].size;
*total+=EMM_Handles[index].size;
}
if (EMM_Handles[index].next) index=EMM_Handles[index].next;
else break;
}
}
void EMM_Allocate(Bit16u size,Bit16u * handle) {
Bit16u index=0;*handle=0;
while (EMM_Handles[index].active) {
if (EMM_Handles[index].free) {
/* Use entire block */
if(EMM_Handles[index].size==size) {
EMM_Handles[index].free=false;
*handle=index;
break;
}
/* Split up block */
if(EMM_Handles[index].size>size) {
Bit16u newindex=EMM_GetFreeHandle();
EMM_Handles[newindex].active=true;
EMM_Handles[newindex].phys_base=EMM_Handles[newindex].phys_base+size*4096;
EMM_Handles[newindex].size=EMM_Handles[index].size-size;
EMM_Handles[newindex].free=true;
EMM_Handles[newindex].next=EMM_Handles[index].next;
EMM_Handles[index].next=newindex;
EMM_Handles[index].free=false;
EMM_Handles[index].size=size;
*handle=index;
break;
}
}
if (EMM_Handles[index].next) index=EMM_Handles[index].next;
else break;
}
}
void EMM_Free(Bit16u handle) {
if (!EMM_Handles[handle].active) E_Exit("EMM:Tried to free illegal handle");
EMM_Handles[handle].free=true;
//TODO join memory blocks
}
PageEntry HMA_PageEntry;
void MEM_Init(void) {
memset((void *)&PageEntries,0,sizeof(PageEntries));
memory=(Bit8u *)malloc(memsize*1024*1024);
if (!memory) {
E_Exit("Can't allocate memory for memory");
}
/* Setup the HMA to wrap */
HMA_PageEntry.type=MEMORY_RELOCATE;;
HMA_PageEntry.base=1024*1024;
HMA_PageEntry.relocate=memory;
Bitu i;
for (i=0;i<16;i++) {
PageEntries[i+256]=&HMA_PageEntry;
}
/* Setup the EMM Structures */
for (i=0;i<EMM_HANDLECOUNT;i++) {
EMM_Handles[i].active=false;
EMM_Handles[i].size=0;
}
/* Setup the first handle with free and max memory */
EMM_Handles[0].active=true;
EMM_Handles[0].free=false;
EMM_Handles[0].phys_base=0x110000;
EMM_Handles[0].next=1;
if (memsize>1) {
EMM_Handles[1].size=(memsize-1)*256-16;
} else {
EMM_Handles[0].size=0;;
}
EMM_Handles[1].active=true;
EMM_Handles[1].free=true;
EMM_Handles[1].phys_base=0x110000;
};

254
src/hardware/mixer.cpp Normal file
View file

@ -0,0 +1,254 @@
/*
* 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.
*/
/*
Remove the sdl code from here and have it handeld in the sdlmain.
That should call the mixer start from there or something.
*/
#include <string.h>
#include <SDL/SDL.h>
#include "dosbox.h"
#include "mixer.h"
#include "timer.h"
#define MIXER_MAXCHAN 8
#define MIXER_BLOCKSIZE 1024
#define MIXER_BUFSIZE MIXER_BLOCKSIZE*8
#define MIXER_SSIZE 4
#define MIXER_SHIFT 16
#define MIXER_REMAIN ((1<<MIXER_SHIFT)-1)
#define MIXER_FREQ 22050
struct MIXER_Channel {
Bit8u volume;
Bit8u mode;
Bit32u freq;
char * name;
MIXER_MixHandler handler;
Bit32u sample_add;
Bit32u sample_remain;
Bit16s sample_data[2];
bool playing;
MIXER_Channel * next;
};
static MIXER_Channel * first_channel;
static union {
Bit16s temp_m16[MIXER_BUFSIZE][1];
Bit16s temp_s16[MIXER_BUFSIZE][2];
Bit8u temp_m8[MIXER_BUFSIZE][1];
Bit8u temp_s8[MIXER_BUFSIZE][2];
};
static Bit16s mix_bufout[MIXER_BUFSIZE][2];
static Bit16s mix_buftemp[MIXER_BUFSIZE][2];
static Bit32s mix_bufextra;
static Bit32u mix_writepos;
static Bit32u mix_readpos;
static Bit32u mix_ticks;
static Bit32u mix_add;
static Bit32u mix_remain;
MIXER_Channel * MIXER_AddChannel(MIXER_MixHandler handler,Bit32u freq,char * name) {
//TODO Find a free channel
MIXER_Channel * chan=new MIXER_Channel;
if (!chan) return 0;
chan->playing=false;
chan->volume=255;
chan->mode=MIXER_16STEREO;
chan->handler=handler;
chan->name=name;
chan->sample_add=(freq<<MIXER_SHIFT)/MIXER_FREQ;
chan->next=first_channel;
first_channel=chan;
return chan;
};
void MIXER_SetFreq(MIXER_Channel * chan,Bit32u freq) {
if (chan) {
chan->freq=freq;
/* Calculate the new addition value */
chan->sample_add=(freq<<MIXER_SHIFT)/MIXER_FREQ;
}
}
void MIXER_SetMode(MIXER_Channel * chan,Bit8u mode) {
if (chan) chan->mode=mode;
};
void MIXER_SetVolume(MIXER_Channel * chan,Bit8u vol) {
if (chan) chan->volume=vol;
}
void MIXER_Enable(MIXER_Channel * chan,bool enable) {
if (chan) chan->playing=enable;
}
/* Mix a certain amount of new samples */
static void MIXER_MixData(Bit32u samples) {
/* This Should mix the channels */
if (!samples) return;
if (samples>MIXER_BUFSIZE) samples=MIXER_BUFSIZE;
/* 16-bit stereo is 4 bytes per sample */
memset((void *)&mix_buftemp,0,samples*MIXER_SSIZE);
MIXER_Channel * chan=first_channel;
while (chan) {
if (chan->playing) {
Bit32u chan_samples=samples*chan->sample_add;
Bit32u real_samples=chan_samples>>MIXER_SHIFT;
if (chan_samples & MIXER_REMAIN) real_samples++;
(chan->handler)((Bit8u*)&temp_m8,real_samples);
switch (chan->mode) {
case MIXER_8MONO:
/* Mix a 8 bit mono stream into the final 16 bit stereo output stream */
{
/* Mix the data with output buffer */
Bit32s newsample;Bit32u sample_read=0;Bit32u sample_add=chan->sample_add;
for (Bit32u mix=0;mix<samples;mix++) {
Bit32u pos=sample_read >> MIXER_SHIFT;
sample_read+=sample_add;
newsample=mix_buftemp[mix][0]+((Bit8s)(temp_m8[pos][0]^0x80) << 8);
if (newsample>MAX_AUDIO) mix_buftemp[mix][0]=MAX_AUDIO;
else if (newsample<MIN_AUDIO) mix_buftemp[mix][0]=MIN_AUDIO;
else mix_buftemp[mix][0]=(Bit16s)newsample;
newsample=mix_buftemp[mix][1]+((Bit8s)(temp_m8[pos][0]^0x80) << 8);
if (newsample>MAX_AUDIO) mix_buftemp[mix][1]=MAX_AUDIO;
else if (newsample<MIN_AUDIO) mix_buftemp[mix][1]=MIN_AUDIO;
else mix_buftemp[mix][1]=(Bit16s)newsample;
}
break;
}
case MIXER_16MONO:
/* Mix a 16 bit mono stream into the final 16 bit stereo output stream */
{
Bit32s newsample;Bit32u sample_read=0;Bit32u sample_add=chan->sample_add;
for (Bit32u mix=0;mix<samples;mix++) {
Bit32u pos=sample_read >> MIXER_SHIFT;
sample_read+=sample_add;
newsample=mix_buftemp[mix][0]+temp_m16[pos][0];
if (newsample>MAX_AUDIO) mix_buftemp[mix][0]=MAX_AUDIO;
else if (newsample<MIN_AUDIO) mix_buftemp[mix][0]=MIN_AUDIO;
else mix_buftemp[mix][0]=(Bit16s)newsample;
newsample=mix_buftemp[mix][1]+temp_m16[pos][0];
if (newsample>MAX_AUDIO) mix_buftemp[mix][1]=MAX_AUDIO;
else if (newsample<MIN_AUDIO) mix_buftemp[mix][1]=MIN_AUDIO;
else mix_buftemp[mix][1]=(Bit16s)newsample;
}
break;
}
case MIXER_16STEREO:
/* Mix a 16 bit stereo stream into the final 16 bit stereo output stream */
{
Bit32s newsample;Bit32u sample_read=0;Bit32u sample_add=chan->sample_add;
for (Bit32u mix=0;mix<samples;mix++) {
Bit32u pos=sample_read >> MIXER_SHIFT;
sample_read+=sample_add;
newsample=mix_buftemp[mix][0]+temp_s16[pos][0];
if (newsample>MAX_AUDIO) mix_buftemp[mix][0]=MAX_AUDIO;
else if (newsample<MIN_AUDIO) mix_buftemp[mix][0]=MIN_AUDIO;
else mix_buftemp[mix][0]=(Bit16s)newsample;
newsample=mix_buftemp[mix][1]+temp_s16[pos][1];
if (newsample>MAX_AUDIO) mix_buftemp[mix][1]=MAX_AUDIO;
else if (newsample<MIN_AUDIO) mix_buftemp[mix][1]=MIN_AUDIO;
else mix_buftemp[mix][1]=(Bit16s)newsample;
}
break;
}
default:
E_Exit("MIXER:Illegal sound mode %2X",chan->mode);
}
}
chan=chan->next;
}
Bit32u buf_remain=MIXER_BUFSIZE-mix_writepos;
/* Fill the samples size buffer with 0's */
if (buf_remain>samples) {
memcpy(&mix_bufout[mix_writepos][0],&mix_buftemp[0][0],samples*MIXER_SSIZE);
mix_writepos+=samples;
} else {
memcpy(&mix_bufout[mix_writepos][0],&mix_buftemp[0][0],buf_remain*MIXER_SSIZE);
memcpy(&mix_bufout[0][0],&mix_buftemp[buf_remain][0],(samples-buf_remain)*MIXER_SSIZE);
mix_writepos=(mix_writepos+samples)-MIXER_BUFSIZE;
}
}
void MIXER_Mix(Bitu ticks) {
/* Check for 1 ms of sound to mix */
Bitu count=(ticks*mix_add)+mix_remain;
mix_remain=count&((1<<10)-1);
count>>=10;
Bit32u size=MIXER_BUFSIZE+mix_writepos-mix_readpos;
if (size>=MIXER_BUFSIZE) size-=MIXER_BUFSIZE;
if (size>MIXER_BLOCKSIZE+2048) return;
MIXER_MixData(count);
}
static Bit32u last_pos;
static void MIXER_CallBack(void * userdata, Uint8 *stream, int len) {
/* Copy data from buf_out to the stream */
Bit32u remain=MIXER_BUFSIZE-mix_readpos;
if (remain>=len/MIXER_SSIZE) {
memcpy((void *)stream,(void *)&mix_bufout[mix_readpos][0],len);
} else {
memcpy((void *)stream,(void *)&mix_bufout[mix_readpos][0],remain*MIXER_SSIZE);
stream+=remain*MIXER_SSIZE;
memcpy((void *)stream,(void *)&mix_bufout[0][0],(len)-remain*MIXER_SSIZE);
}
mix_readpos+=(len/MIXER_SSIZE);
if (mix_readpos>=MIXER_BUFSIZE) mix_readpos-=MIXER_BUFSIZE;
}
void MIXER_Init(void) {
/* Initialize the internal stuff */
first_channel=0;
mix_ticks=GetTicks();
mix_bufextra=0;
mix_writepos=0;
mix_readpos=0;
/* Start the Mixer using SDL Sound at 22 khz */
SDL_AudioSpec spec;
SDL_AudioSpec obtained;
mix_add=((MIXER_FREQ) << 10)/1000;
mix_remain=0;
spec.freq=MIXER_FREQ;
spec.format=AUDIO_S16SYS;
spec.channels=2;
spec.callback=MIXER_CallBack;
spec.userdata=NULL;
spec.samples=MIXER_BLOCKSIZE;
TIMER_RegisterTickHandler(MIXER_Mix);
if ( SDL_OpenAudio(&spec, &obtained) < 0 ) {
LOG_MSG("No sound output device found, starting in no sound mode");
} else {
MIXER_MixData(MIXER_BLOCKSIZE/MIXER_SSIZE);
SDL_PauseAudio(0);
}
}

View file

@ -0,0 +1,88 @@
/*
* 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 <mixer.h>
#include <math.h>
#ifndef PI
#define PI 3.14159265358979323846
#endif
#define SPKR_RATE 22050
#define SPKR_VOLUME 5000
#define FREQ_SHIFT 16
#define FREQ_MAX (2 << FREQ_SHIFT)
#define FREQ_HALF (FREQ_MAX >> 1)
struct Speaker {
Bit32u freq_add;
Bit32u freq_pos;
Bit16s volume;
MIXER_Channel * chan;
bool enabled;
};
static Speaker spkr;
void PCSPEAKER_SetFreq(Bit32u freq) {
spkr.freq_add=(Bit32u)(FREQ_MAX/((float)SPKR_RATE/(float)freq));
spkr.freq_pos=0;
}
void PCSPEAKER_Enable(bool enable) {
spkr.enabled=enable;
MIXER_Enable(spkr.chan,enable);
}
static void PCSPEAKER_CallBack(Bit8u * stream,Bit32u len) {
/* Generate the speaker wave, TODO Improve :) */
for (Bit32u c=0;c<len;c++) {
spkr.freq_pos+=spkr.freq_add;
if (spkr.freq_pos>=FREQ_MAX) spkr.freq_pos-=FREQ_MAX;
if (spkr.freq_pos>=FREQ_HALF) {
*(Bit16s*)(stream)=spkr.volume;
} else {
*(Bit16s*)(stream)=-spkr.volume;
}
/*
if (spkr.freq_pos>=FREQ_HALF) {
spkr.freq_pos-=FREQ_HALF;
spkr.volume=-spkr.volume;
};
*(Bit16s*)(stream)=spkr.volume;
*/
stream+=2;
}
}
void PCSPEAKER_Init(void) {
spkr.chan=MIXER_AddChannel(&PCSPEAKER_CallBack,SPKR_RATE,"PC-SPEAKER");
MIXER_Enable(spkr.chan,false);
MIXER_SetMode(spkr.chan,MIXER_16MONO);
spkr.volume=SPKR_VOLUME;
spkr.enabled=false;
}

369
src/hardware/pic.cpp Normal file
View file

@ -0,0 +1,369 @@
/*
* 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 "inout.h"
#include "cpu.h"
#include "pic.h"
struct IRQ_Block {
bool masked;
bool active;
bool inservice;
Bit8u vector;
char * name;
PIC_EOIHandler * handler;
};
Bit32u PIC_IRQCheck;
static IRQ_Block irqs[16];
static Bit8u pic0_icws=0;
static Bit8u pic1_icws=0;
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
static void write_p20(Bit32u port,Bit8u val) {
Bit32u i;
switch (val) {
case 0x0A: /* select read interrupt request register */
pic0_request_iisr=false;
break;
case 0x0B: /* select read interrupt in-service register */
pic0_request_iisr=true;
break;
case 0x10: /* ICW1 */
pic0_icws=2;
pic0_icw_state=1;
break;
case 0x11: /* ICW1 + need for ICW4 */
pic0_icws=3;
pic0_icw_state=1;
break;
case 0x20: /* end of interrupt command */
/* clear highest current in service bit */
for (i=0;i<=7;i++) {
if (irqs[i].inservice) {
irqs[i].inservice=false;
if (irqs[i].handler!=0) irqs[i].handler();
break;
};
};
break;
case 0x60: /* specific EOI 0 */
case 0x61: /* specific EOI 1 */
case 0x62: /* specific EOI 2 */
case 0x63: /* specific EOI 3 */
case 0x64: /* specific EOI 4 */
case 0x65: /* specific EOI 5 */
case 0x66: /* specific EOI 6 */
case 0x67: /* specific EOI 7 */
if (irqs[val-0x60].inservice) {
irqs[val-0x60].inservice=false;
if (irqs[val-0x60].handler!=0) irqs[val-0x60].handler();
};
break;
// IRQ lowest priority commands
case 0xC0: // 0 7 6 5 4 3 2 1
case 0xC1: // 1 0 7 6 5 4 3 2
case 0xC2: // 2 1 0 7 6 5 4 3
case 0xC3: // 3 2 1 0 7 6 5 4
case 0xC4: // 4 3 2 1 0 7 6 5
case 0xC5: // 5 4 3 2 1 0 7 6
case 0xC6: // 6 5 4 3 2 1 0 7
case 0xC7: // 7 6 5 4 3 2 1 0
// ignore for now TODO
break;
default:
E_Exit("PIC0:Unhandled command %02X",val);
}
}
//Pic 0 Interrupt mask
static void write_p21(Bit32u port,Bit8u val) {
Bit8u i;
switch(pic0_icw_state) {
case 0: /* mask register */
for (i=0;i<=7;i++) {
irqs[i].masked=(val&(1<<i))>0;
if (irqs[i].active && !irqs[i].masked) PIC_IRQCheck|=(1 << 1);
else PIC_IRQCheck&=~(1 << i);
};
break;
case 1: /* icw2 */
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) {
Bit8u ret=0;
Bit32u i;
Bit8u b=1;
if (pic0_request_iisr) {
for (i=0;i<=7;i++) {
if (irqs[i].inservice) ret|=b;
b <<= 1;
}
} else {
for (i=0;i<=7;i++) {
if (irqs[i].active) ret|=b;
b <<= 1;
}
};
return ret;
}
static Bit8u read_p21(Bit32u port) {
Bit8u ret=0;
Bit32u i;
Bit8u b=1;
for (i=0;i<=7;i++) {
if (irqs[i].masked) ret|=b;
b <<= 1;
}
return ret;
}
static void write_pa0(Bit32u port,Bit8u val) {
Bit32u i;
switch (val) {
case 0x0A: /* select read interrupt request register */
pic1_request_iisr=false;
break;
case 0x0B: /* select read interrupt in-service register */
pic1_request_iisr=true;
break;
case 0x10: /* ICW1 */
/* Clear everything set full mask and clear all inservice */
for (i=0;i<=7;i++) {
irqs[i].masked=true;
irqs[i].active=false;
irqs[i].inservice=false;
}
pic1_icws=2;
pic1_icw_state=1;
break;
case 0x11: /* ICW1 + need for ICW4 */
pic1_icws=3;
pic1_icw_state=1;
break;
case 0x20: /* end of interrupt command */
/* clear highest current in service bit */
for (i=8;i<=15;i++) {
if (irqs[i].inservice) {
irqs[i].inservice=false;
if (irqs[i].handler!=0) irqs[i].handler();
break;
};
};
break;
case 0x60: /* specific EOI 0 */
case 0x61: /* specific EOI 1 */
case 0x62: /* specific EOI 2 */
case 0x63: /* specific EOI 3 */
case 0x64: /* specific EOI 4 */
case 0x65: /* specific EOI 5 */
case 0x66: /* specific EOI 6 */
case 0x67: /* specific EOI 7 */
if (irqs[val-0x60+8].inservice) {
irqs[val-0x60+8].inservice=false;
if (irqs[val-0x60+8].handler!=0) irqs[val-0x60+8].handler();
};
break;
// IRQ lowest priority commands
case 0xC0: // 0 7 6 5 4 3 2 1
case 0xC1: // 1 0 7 6 5 4 3 2
case 0xC2: // 2 1 0 7 6 5 4 3
case 0xC3: // 3 2 1 0 7 6 5 4
case 0xC4: // 4 3 2 1 0 7 6 5
case 0xC5: // 5 4 3 2 1 0 7 6
case 0xC6: // 6 5 4 3 2 1 0 7
case 0xC7: // 7 6 5 4 3 2 1 0
//TODO Maybe does it even matter?
break;
default:
E_Exit("Unhandled command %04X sent to port A0",val);
}
}
static void write_pa1(Bit32u port,Bit8u val) {
Bit8u i;
switch(pic1_icw_state) {
case 0: /* mask register */
for (i=0;i<=7;i++) {
irqs[i+8].masked=(val&1 <<i)>0;
};
break;
case 1: /* icw2 */
for (i=0;i<=7;i++) {
irqs[i+8].vector=(val&0xf8)+i;
};
default: /* icw2, 3, and 4*/
if(pic1_icw_state++ >= pic1_icws) pic1_icw_state=0;
}
}
static Bit8u read_pa0(Bit32u port) {
Bit8u ret=0;
Bit32u i;
Bit8u b=1;
if (pic1_request_iisr) {
for (i=0;i<=7;i++) {
if (irqs[i+8].inservice) ret|=b;
b <<= 1;
}
} else {
for (i=0;i<=7;i++) {
if (irqs[i+8].active) ret|=b;
b <<= 1;
}
};
return ret;
}
static Bit8u read_pa1(Bit32u port) {
Bit8u ret=0;
Bit32u i;
Bit8u b=1;
for (i=0;i<=7;i++) {
if (irqs[i+8].masked) ret|=b;
b <<= 1;
}
return ret;
}
void PIC_RegisterIRQ(Bit32u irq,PIC_EOIHandler handler,char * name) {
if (irq>15) E_Exit("PIC:Illegal IRQ");
irqs[irq].name=name;
irqs[irq].handler=handler;
}
void PIC_FreeIRQ(Bit32u irq) {
if (irq>15) E_Exit("PIC:Illegal IRQ");
irqs[irq].name=0;
irqs[irq].handler=0;
irqs[irq].active=0;
irqs[irq].inservice=0;
PIC_IRQCheck&=~(1 << irq);
}
void PIC_ActivateIRQ(Bit32u irq) {
if (irq<16) {
irqs[irq].active=true;
if (!irqs[irq].masked) {
PIC_IRQCheck|=(1 << irq);
}
}
}
void PIC_DeActivateIRQ(Bit32u irq) {
if (irq<16) {
irqs[irq].active=false;
PIC_IRQCheck&=~(1 << irq);
}
}
bool PIC_IRQActive(Bit32u irq) {
if (irq<16) {
return irqs[irq].active;
}
return true;
}
#define PIC_MAXQUEUE 16
static PIC_Function * pic_queue[PIC_MAXQUEUE];
static Bit32u pic_queuesize;
void PIC_QueueFunction(PIC_Function * function) {
if (pic_queuesize<PIC_MAXQUEUE) {
pic_queue[pic_queuesize]=function;
pic_queuesize++;
} else {
E_Exit("PIC Queue OverFlow");
}
}
//TODO check for IRQ 2 being masked before checking 8-15 but then again do i need so many irqs
void PIC_runIRQs(void) {
Bit32u i;
if (!flags.intf) goto noirqs;
if (!PIC_IRQCheck) goto noirqs;
for (i=0;i<=15;i++) {
if (i!=2) {
if (!irqs[i].masked && irqs[i].active /* && !irqs[i].inservice */) {
irqs[i].inservice=true;
irqs[i].active=false;
PIC_IRQCheck&=~(1 << i);
Interrupt(irqs[i].vector);
break;
};
};
};
noirqs:
/* This also runs special hardware functions that can queue themselves here */
for (;pic_queuesize>0;) {
(*pic_queue[--pic_queuesize])();
}
};
void PIC_Init(void) {
/* Setup pic0 and pic1 with initial values like DOS has normally */
PIC_IRQCheck=0;
Bit8u i;
for (i=0;i<=7;i++) {
irqs[i].active=false;
irqs[i].masked=true;
irqs[i].inservice=false;
irqs[i+8].active=false;
irqs[i+8].masked=true;
irqs[i+8].inservice=false;
irqs[i].vector=0x8+i;
irqs[i+8].vector=0x70+i;
};
irqs[0].masked=false; /* Enable system timer */
irqs[1].masked=false; /* Enable Keyboard IRQ */
irqs[2].masked=false; /* Enable 2nd PIC Although i can't care if this is masked */
irqs[12].masked=false;
IO_RegisterReadHandler(0x20,read_p20,"Master PIC Command");
IO_RegisterReadHandler(0x21,read_p21,"Master PIC Data");
IO_RegisterWriteHandler(0x20,write_p20,"Master PIC Command");
IO_RegisterWriteHandler(0x21,write_p21,"Master PIC Data");
IO_RegisterReadHandler(0xa0,read_pa0,"Slave PIC Command");
IO_RegisterReadHandler(0xa1,read_pa1,"Slave PIC Data");
IO_RegisterWriteHandler(0xa0,write_pa0,"Slave PIC Command");
IO_RegisterWriteHandler(0xa1,write_pa1,"Slave PIC Data");
};

613
src/hardware/sblaster.cpp Normal file
View file

@ -0,0 +1,613 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "inout.h"
#include "mixer.h"
#include "dma.h"
#include "pic.h"
#include "hardware.h"
#define SB_BASE 0x220
#define SB_IRQ 5
#define SB_DMA 1
#define DSP_RESET 0x06
#define DSP_READ_DATA 0x0A
#define DSP_WRITE_DATA 0x0C
#define DSP_WRITE_STATUS 0x0C
#define DSP_READ_STATUS 0x0E
#define DSP_NO_COMMAND 0
#define DSP_MAJOR 2
#define DSP_MINOR 0
#define DSP_BUFSIZE 64
#define DSP_DACSIZE 4096
enum {DSP_S_RESET,DSP_S_NORMAL,DSP_S_HIGHSPEED};
enum {
MODE_NONE,MODE_DAC,
MODE_PCM_8S,MODE_PCM_8A,
MODE_ADPCM_4S
};
#ifdef DEBUG_SBLASTER
#define SB_DEBUG LOG_DEBUG
#else
#define SB_DEBUG
#endif
struct SB_INFO {
Bit16u freq;
Bitu samples_total;
Bitu samples_left;
bool speaker;
Bit8u time_constant;
bool use_time_constant;
Bit8u output_mode;
/* DSP Stuff */
Bit8u mode;
Bit8u state;
Bit8u cmd;
Bit8u cmd_len;
Bit8u cmd_in_pos;
Bit8u cmd_in[DSP_BUFSIZE];
Bit8u data_out[DSP_BUFSIZE];
Bit8u data_out_pos;
Bit8u data_out_used;
Bit8u dac_data[DSP_DACSIZE];
Bit32u dac_used;
Bit8u test_register;
/*ADPCM Part */
Bits adpcm_reference;
Bits adpcm_scale;
Bits adpcm_remain;
/* Hardware setup part */
Bit32u base;
Bit8u irq;
Bit8u dma;
bool enabled;
HWBlock hwblock;
MIXER_Channel * chan;
};
static SB_INFO sb;
static Bit8u e2_value;
static Bit8u e2_count;
static char * copyright_string="COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
static Bit8u DSP_cmd_len[256] = {
0,0,0,0, 0,2,0,0, 0,0,0,0, 0,0,0,0, // 0x00
1,0,0,0, 2,0,2,2, 0,0,0,0, 0,0,0,0, // 0x10
0,0,0,0, 2,0,0,0, 0,0,0,0, 0,0,0,0, // 0x20
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x30
1,2,2,0, 0,0,0,0, 2,0,0,0, 0,0,0,0, // 0x40
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x50
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x60
0,0,0,0, 2,2,2,2, 0,0,0,0, 0,0,0,0, // 0x70
2,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x80
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x90
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xa0
3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xb0
3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xc0
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0xd0
1,0,1,0, 1,0,0,0, 0,0,0,0, 0,0,0,0, // 0xe0
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 // 0xf0
};
static int E2_incr_table[4][9] = {
{ 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 },
{ -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 },
{ -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 },
{ 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 }
};
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
static void DSP_SetSpeaker(bool how) {
/* This should just set the mixer value */
MIXER_Enable(sb.chan,how);
sb.speaker=how;
}
static void DSP_HaltDMA(void) {
}
static INLINE void DSP_FlushData(void) {
sb.data_out_used=0;
sb.data_out_pos=0;
}
static void DSP_SetSampleRate(Bit32u rate) {
/* This directly changes the mixer */
}
static void DSP_StopDMA(void) {
sb.mode=MODE_NONE;
// MIXER_SetMode(sb.chan,MIXER_8MONO);
// MIXER_SetFreq(sb.chan,22050);
}
static void DSP_StartDMATranfser(Bit8u mode) {
sb.samples_left=sb.samples_total;
if (sb.use_time_constant) {
sb.freq=(1000000 / (256 - sb.time_constant));
};
switch (mode) {
case MODE_PCM_8S:
MIXER_SetFreq(sb.chan,sb.freq);
SB_DEBUG("DSP:PCM 8 bit single cycle rate %d size %d",sb.freq,sb.samples_total);
break;
case MODE_PCM_8A:
MIXER_SetFreq(sb.chan,sb.freq);
SB_DEBUG("DSP:PCM 8 bit auto init rate %d size %d",sb.freq,sb.samples_total);
break;
case MODE_ADPCM_4S:
MIXER_SetFreq(sb.chan,sb.freq*2);
SB_DEBUG("DSP:ADPCM 4 bit single cycle rate %d size %X",sb.freq,sb.samples_total);
break;
default:
LOG_ERROR("DSP:Illegal transfer mode %d",mode);
return;
}
/* Hack to enable dma transfer when game has speaker disabled */
DSP_SetSpeaker(true);
sb.mode=mode;
}
static void DSP_AddData(Bit8u val) {
if (sb.data_out_used<DSP_BUFSIZE) {
Bit32u start=sb.data_out_used+sb.data_out_pos;
if (start>=DSP_BUFSIZE) start-=DSP_BUFSIZE;
sb.data_out[start]=val;
sb.data_out_used++;
} else {
LOG_ERROR("SB:DSP:Data Output buffer full this is weird");
}
}
static void DSP_Reset(void) {
sb.mode=MODE_NONE;
sb.cmd_len=0;
sb.cmd_in_pos=0;
sb.use_time_constant=false;
sb.dac_used=0;
e2_value=0xaa;
e2_count=0;
DSP_HaltDMA();
MIXER_SetFreq(sb.chan,22050);
MIXER_SetMode(sb.chan,MIXER_8MONO);
DSP_SetSpeaker(false);
}
static void DSP_DoReset(Bit8u val) {
if (val&1!=0) {
//TODO Get out of highspeed mode
DSP_Reset();
sb.state=DSP_S_RESET;
} else {
DSP_FlushData();
DSP_AddData(0xaa);
sb.state=DSP_S_NORMAL;
}
};
static bool dac_warn=false;
static void DSP_DoCommand(void) {
switch (sb.cmd) {
case 0x10: /* Direct DAC */
sb.mode=MODE_DAC;
if (sb.dac_used<DSP_DACSIZE) {
sb.dac_data[sb.dac_used++]=sb.cmd_in[0];
}
break;
case 0x14: /* Singe Cycle 8-Bit DMA */
/* Set the length of the transfer */
sb.samples_total=1+sb.cmd_in[0]+(sb.cmd_in[1] << 8);
DSP_StartDMATranfser(MODE_PCM_8S);
break;
case 0x1c: /* Auto Init 8-bit DMA */
DSP_StartDMATranfser(MODE_PCM_8A);
break;
case 0x40: /* Set Timeconstant */
sb.use_time_constant=true;
sb.time_constant=sb.cmd_in[0];
break;
case 0x48: /* Set DMA Block Size */
sb.samples_total=1+sb.cmd_in[0]+(sb.cmd_in[1] << 8);
break;
case 0x75: /* 075h : Single Cycle 4-bit ADPCM Reference */
sb.adpcm_scale=0;
sb.adpcm_reference=-1;
sb.adpcm_remain=-1;
case 0x74: /* 074h : Single Cycle 4-bit ADPCM */
sb.samples_total=1+sb.cmd_in[0]+(sb.cmd_in[1] << 8);
DSP_StartDMATranfser(MODE_ADPCM_4S);
break;
case 0xd0: /* Halt 8-bit DMA */
DSP_HaltDMA();
break;
case 0xd1: /* Enable Speaker */
DSP_SetSpeaker(true);
break;
case 0xd3: /* Disable Speaker */
DSP_SetSpeaker(false);
break;
case 0xe0: /* DSP Identification - SB2.0+ */
DSP_FlushData();
DSP_AddData(~sb.cmd_in[0]);
break;
case 0xe1: /* Get DSP Version */
DSP_FlushData();
DSP_AddData(DSP_MAJOR);
DSP_AddData(DSP_MINOR);
break;
case 0xe2: /* Weird DMA identification write routine */
{
/*
for (Bit8u i = 0; i < 8; i++)
if ((sb.cmd_in[0] >> i) & 0x01) m_E2Value += E2_incr_table[m_E2Count % 4][i];
m_E2Value += E2_incr_table[m_E2Count % 4][8];
m_E2Count++;
*/
//TODO Ofcourse :)
}
break;
case 0xe3: /* DSP Copyright */
{
DSP_FlushData();
for (Bit32u i=0;i<=strlen(copyright_string);i++) {
DSP_AddData(copyright_string[i]);
}
}
break;
case 0xe4: /* Write Test Register */
sb.test_register=sb.cmd_in[0];
break;
case 0xe8: /* Read Test Register */
DSP_FlushData();
DSP_AddData(sb.test_register);;
break;
case 0xf2: /* Trigger 8bit IRQ */
DSP_FlushData();
DSP_AddData(0xaa);
PIC_ActivateIRQ(sb.irq);
break;
default:
LOG_WARN("SB:DSP:Unhandled command %2X",sb.cmd);
}
sb.cmd=DSP_NO_COMMAND;
sb.cmd_len=0;
sb.cmd_in_pos=0;
}
static void DSP_DoWrite(Bit8u val) {
switch (sb.cmd) {
case DSP_NO_COMMAND:
sb.cmd=val;
sb.cmd_len=DSP_cmd_len[val];
sb.cmd_in_pos=0;
if (!sb.cmd_len) DSP_DoCommand();
break;
default:
sb.cmd_in[sb.cmd_in_pos]=val;
sb.cmd_in_pos++;
if (sb.cmd_in_pos>=sb.cmd_len) DSP_DoCommand();
}
}
static Bit8u DSP_ReadData(void) {
Bit8u data=0;
if (sb.data_out_used) {
data=sb.data_out[sb.data_out_pos];
sb.data_out_pos++;
if (sb.data_out_pos>=DSP_BUFSIZE) sb.data_out_pos-=DSP_BUFSIZE;
sb.data_out_used--;
}
return data;
}
static Bit8u read_sb(Bit32u port) {
switch (port-sb.base) {
case DSP_READ_DATA:
return DSP_ReadData();
case DSP_READ_STATUS:
//TODO Acknowledge 8bit irq
//TODO See for high speed dma :)
if (sb.data_out_used) return 0xff;
else return 0x7f;
case DSP_WRITE_STATUS:
switch (sb.state) {
case DSP_S_NORMAL:
return 0x7f;
case DSP_S_RESET:
return 0xff;
}
return 0xff;
/* For now loop FM Stuff to 0x388 */
case 0x00: case 0x02: case 0x08:
return IO_Read(0x388);
case DSP_RESET:
return 0xff;
default:
LOG_WARN("SB:Unhandled read from SB Port %4X",port);
break;
}
return 0xff;
}
static void write_sb(Bit32u port,Bit8u val) {
switch (port-sb.base) {
case DSP_RESET:
DSP_DoReset(val);
break;
case DSP_WRITE_DATA:
DSP_DoWrite(val);
break;
/* For now loop FM Stuff to 0x388 */
case 0x00: case 0x02: case 0x08:
IO_Write(0x388,val);
break;
case 0x01: case 0x03: case 0x09:
IO_Write(0x389,val);
break;
default:
LOG_WARN("SB:Unhandled write to SB Port %4X",port);
break;
}
}
INLINE Bit8u decode_ADPCM_4_sample(
Bit8u sample,
Bits& reference,
Bits& scale)
{
static int scaleMap[8] = { -2, -1, 0, 0, 1, 1, 1, 1 };
if (sample & 0x08) {
reference = max(0x00, reference - ((sample & 0x07) << scale));
} else {
reference = min(0xff, reference + ((sample & 0x07) << scale));
}
scale = max(2, min(6, scaleMap[sample & 0x07]));
return (Bit8u)reference;
}
static void SBLASTER_CallBack(Bit8u * stream,Bit32u len) {
unsigned char tmpbuf[65536];
if (!len) return;
switch (sb.mode) {
case MODE_NONE:
/* If there isn't a mode it's 8 bit mono mode speaker should be disabled normally */
memset(stream,0x80,len);
break;
case MODE_DAC:
/* Stretch the inputted dac data over len samples */
{
Bit32u dac_add=(sb.dac_used<<16)/len;
Bit32u dac_pos=0;
while (len-->0) {
*(stream++)=sb.dac_data[dac_pos>>16];
dac_pos+=dac_add;
}
}
sb.dac_used=0;
sb.mode=MODE_NONE;
break;
case MODE_PCM_8A:
DMA_8_Read(sb.dma,stream,(Bit16u)len);
if (sb.samples_left>len) {
sb.samples_left-=len;
} else {
if (len>(sb.samples_total+sb.samples_left)) sb.samples_left=sb.samples_total;
else sb.samples_left=sb.samples_total+sb.samples_left-len;
PIC_ActivateIRQ(sb.irq);
}
break;
case MODE_PCM_8S:
if (sb.samples_left>=len) {
DMA_8_Read(sb.dma,stream,(Bit16u)len);
sb.samples_left-=len;
} else if (sb.samples_left && (sb.samples_left<len)) {
DMA_8_Read(sb.dma,stream,(Bit16u)sb.samples_left);
memset(stream+sb.samples_left,0x80,len-sb.samples_left);
sb.samples_left=0;
}
if (sb.samples_left==0) {
DSP_StopDMA();
PIC_ActivateIRQ(sb.irq);
}
break;
case MODE_ADPCM_4S:
{
if (sb.adpcm_remain>=0) {
*stream++=decode_ADPCM_4_sample((Bit8u)sb.adpcm_remain,sb.adpcm_reference,sb.adpcm_scale);
len--;
}
Bitu dma_size=len/2+(len&1); //Amount of bytes that need to be transferred
Bit8u * decode_pos=tmpbuf;
if (sb.adpcm_reference < 0) {
dma_size++;
}
/* Read from the DMA Channel */
if (sb.samples_left>=dma_size) {
DMA_8_Read(sb.dma,decode_pos,(Bit16u)dma_size);
sb.samples_left-=dma_size;
} else if (sb.samples_left<dma_size) {
DMA_8_Read(sb.dma,decode_pos,(Bit16u)sb.samples_left);
//Could go wrong with the reference byte i think.
memset(stream+sb.samples_left*2,0x80,len-sb.samples_left*2);
len=sb.samples_left*2;
sb.samples_left=0;
}
if (sb.samples_left==0) {
// if (sb.mode==MODE_PCM_8A) sb.samples_left=sb.samples_total;
// else
DSP_StopDMA();
PIC_ActivateIRQ(sb.irq);
}
if (sb.adpcm_reference < 0) {
sb.adpcm_reference=*decode_pos++;
}
for (Bitu i=len/2;i>0;i--) {
*stream++=decode_ADPCM_4_sample(*decode_pos >> 4,sb.adpcm_reference,sb.adpcm_scale);
*stream++=decode_ADPCM_4_sample(*decode_pos++ ,sb.adpcm_reference,sb.adpcm_scale);
}
if (len & 1) {
*stream++=decode_ADPCM_4_sample(*decode_pos >> 4,sb.adpcm_reference,sb.adpcm_scale);
sb.adpcm_remain=*decode_pos & 0xf;
} else {
sb.adpcm_remain=-1;
}
}
}
}
static bool SB_enabled;
static void SB_Enable(bool enable) {
Bitu i;
if (enable) {
sb.enabled=true;
for (i=sb.base+4;i<sb.base+0xf;i++) {
IO_RegisterReadHandler(i,read_sb,"SB");
IO_RegisterWriteHandler(i,write_sb,"SB");
}
PIC_RegisterIRQ(sb.irq,0,"SB");
DSP_Reset();
} else {
sb.enabled=false;
PIC_FreeIRQ(sb.irq);
for (i=sb.base+4;i<sb.base+0xf;i++){
IO_FreeReadHandler(i);
IO_FreeWriteHandler(i);
};
}
}
static void SB_InputHandler(char * line) {
bool s_off,s_on,s_base,s_irq,s_dma;
Bits n_base,n_irq,n_dma;
s_off=ScanCMDBool(line,"OFF");
s_on=ScanCMDBool(line,"ON");
s_base=ScanCMDHex(line,"BASE",&n_base);
s_irq=ScanCMDHex(line,"IRQ",&n_irq);
s_dma=ScanCMDHex(line,"DMA",&n_dma);
char * rem=ScanCMDRemain(line);
if (rem) {
sprintf(line,"Illegal Switch");
return;
}
if (s_on && s_off) {
sprintf(line,"Can't use /ON and /OFF at the same time");
return;
}
bool was_enabled=sb.enabled;
if (sb.enabled) SB_Enable(false);
if (s_base) {
sb.base=n_base;
}
if (s_irq) {
sb.irq=n_irq;
}
if (s_dma) {
sb.dma=n_dma;
}
if (s_on) {
SB_Enable(true);
}
if (s_off) {
SB_Enable(false);
sprintf(line,"Sound Blaster has been disabled");
return;
}
if (was_enabled) SB_Enable(true);
sprintf(line,"Sound Blaster enabled with IO %X IRQ %X DMA %X",sb.base,sb.irq,sb.dma);
return;
}
static void SB_OutputHandler (char * towrite) {
if(sb.enabled) {
sprintf(towrite,"IO %X IRQ %X DMA %X",sb.base,sb.irq,sb.dma);
} else {
sprintf(towrite,"Disabled");
}
};
void SBLASTER_Init(void) {
sb.chan=MIXER_AddChannel(&SBLASTER_CallBack,22050,"SBLASTER");
MIXER_Enable(sb.chan,false);
sb.state=DSP_S_NORMAL;
/* Setup the hardware handler part */
sb.base=SB_BASE;
sb.irq=SB_IRQ;
sb.dma=SB_DMA;
SB_Enable(true);
sb.hwblock.dev_name="SB";
sb.hwblock.full_name="Sound Blaster 1.5";
sb.hwblock.next=0;
sb.hwblock.help=
"/ON Enables SB\n"
"/OFF Disables SB\n"
"/BASE XXX Set Base Addres 200-260\n"
"/IRQ X Set IRQ 1-9\n"
"/DMA X Set 8-Bit DMA Channel 0-3\n";
sb.hwblock.get_input=SB_InputHandler;
sb.hwblock.show_status=SB_OutputHandler;
HW_Register(&sb.hwblock);
SHELL_AddAutoexec("SET BLASTER=A%3X I%d D%d T3",sb.base,sb.irq,sb.dma);
}

View file

@ -0,0 +1,143 @@
/*
* 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.
*/
/*
Probably just use the mame code for the same chip sometime
*/
#include <math.h>
#include "dosbox.h"
#include "inout.h"
#include "mixer.h"
#include "mem.h"
#define TANDY_DIV 111860
#define TANDY_RATE 22050
#define BIT_SHIFT 16
#define TANDY_VOLUME 10000
static MIXER_Channel * tandy_chan;
struct TandyChannel {
Bit32u div;
Bit32u freq_add;
Bit32u freq_pos;
};
struct TandyBlock {
TandyChannel chan[3];
Bit32s volume[4];
Bit8u reg;
};
static TandyBlock tandy;
#define REG_CHAN0DIV 0 /* 0 0 0 */
#define REG_CHAN0ATT 1 /* 0 0 1 */
#define REG_CHAN1DIV 2 /* 0 1 0 */
#define REG_CHAN1ATT 3 /* 0 1 1 */
#define REG_CHAN2DIV 4 /* 1 0 0 */
#define REG_CHAN2ATT 5 /* 1 0 1 */
#define REG_NOISEATT 7 /* 1 1 1 */
//TODO a db volume table :)
static Bit32s vol_table[16];
static void write_pc0(Bit32u port,Bit8u val) {
/* Test for a command byte */
if (val & 0x80) {
tandy.reg=(val>>4) & 7;
switch (tandy.reg) {
case REG_CHAN0DIV:
case REG_CHAN1DIV:
case REG_CHAN2DIV:
tandy.chan[tandy.reg>>1].div=val&15;
break;
case REG_CHAN0ATT:
case REG_CHAN1ATT:
case REG_CHAN2ATT:
case REG_NOISEATT:
tandy.volume[tandy.reg>>1]=vol_table[val&15];
if (tandy.volume[0] || tandy.volume[1] || tandy.volume[2] || tandy.volume[3]) {
MIXER_Enable(tandy_chan,true);
} else {
MIXER_Enable(tandy_chan,false);
}
break;
default:
// LOG_WARN("TANDY:Illegal register %d selected",tandy.reg);
break;
}
} else {
/* Dual byte command */
switch (tandy.reg) {
#define MAKE_ADD(DIV)(Bit32u)((2 << BIT_SHIFT)/((float)TANDY_RATE/((float)TANDY_DIV/(float)DIV)));
case REG_CHAN0DIV:
case REG_CHAN1DIV:
case REG_CHAN2DIV:
tandy.chan[tandy.reg>>1].div|=(val & 63)<<4;
tandy.chan[tandy.reg>>1].freq_add=MAKE_ADD(tandy.chan[tandy.reg>>1].div);
// tandy.chan[tandy.reg>>1].freq_pos=0;
break;
default:
LOG_WARN("TANDY:Illegal dual byte reg %d",tandy.reg);
};
}
}
static void TANDYSOUND_CallBack(Bit8u * stream,Bit32u len) {
for (Bit32u i=0;i<len;i++) {
Bit32s sample=0;
/* Generate the sound from the 3 channels */
for (Bit32u c=0;c<3;c++) {
if (tandy.volume[c]) {
if (tandy.chan[c].freq_pos<(1 << BIT_SHIFT)) sample+=tandy.volume[c];
else sample-=tandy.volume[c];
tandy.chan[c].freq_pos+=tandy.chan[c].freq_add;
if (tandy.chan[c].freq_pos>=(2 << BIT_SHIFT)) tandy.chan[c].freq_pos-=(2 << BIT_SHIFT);
}
}
/* Generate the noise channel */
if (sample>MAX_AUDIO) *(Bit16s *)stream=MAX_AUDIO;
else if (sample<MIN_AUDIO) *(Bit16s *)stream=MIN_AUDIO;
else *(Bit16s *)stream=(Bit16s)sample;
stream+=2;
}
};
void TANDY_Init(void) {
IO_RegisterWriteHandler(0xc0,write_pc0,"Tandy Sound");
tandy_chan=MIXER_AddChannel(&TANDYSOUND_CallBack,TANDY_RATE,"TANDY");
MIXER_Enable(tandy_chan,false);
MIXER_SetMode(tandy_chan,MIXER_16MONO);
/* Calculate the volume table */
float out=TANDY_VOLUME;
for (Bit32u i=0;i<15;i++) {
vol_table[i]=(Bit32s)out;
out /= (float)1.258925412; /* = 10 ^ (2/20) = 2dB */
}
vol_table[15]=0;
/* Setup a byte for tandy detection */
real_writeb(0xffff,0xe,0xfd);
}

300
src/hardware/timer.cpp Normal file
View file

@ -0,0 +1,300 @@
/*
* 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 <list>
#include "dosbox.h"
#include "inout.h"
#include "pic.h"
#include "bios.h"
#include "mem.h"
#include "dosbox.h"
#include "mixer.h"
#include "timer.h"
struct PIT_Block {
Bit8u mode; /* Current Counter Mode */
Bit32s cntr;
Bit8u latch_mode;
Bit8u read_state;
Bit16s read_latch;
Bit8u write_state;
Bit16u write_latch;
Bit32u last_ticks;
};
static PIT_Block pit[3];
static Bit32u pit_ticks; /* The amount of pit ticks one host tick is bit shifted */
static Bit32u timer_ticks; /* The amount of pit ticks bitshifted one timer cycle needs */
static Bit32u timer_buildup; /* The amount of pit ticks waiting */
#define PIT_TICK_RATE 1193182
#define PIT_SHIFT 9
#define MAX_PASSED ((PIT_TICK_RATE/4) << PIT_SHIFT) /* Alow 1/4 second of timer build up */
static void counter_latch(Bitu counter) {
/* Fill the read_latch of the selected counter with current count */
PIT_Block * p=&pit[counter];
//TODO Perhaps make it a bit64u for accuracy :)
Bit32u ticks=(((LastTicks - p->last_ticks) * pit_ticks) >> PIT_SHIFT) % p->cntr ;
switch (p->mode) {
case 2:
case 3:
p->read_latch=(Bit16u)ticks;
break;
default:
LOG_ERROR("PIT:Illegal Mode %d for reading counter %d",p->mode,counter);
p->read_latch=(Bit16u)ticks;
break;
}
}
static void write_latch(Bit32u port,Bit8u val) {
Bit32u counter=port-0x40;
PIT_Block * p=&pit[counter];
switch (p->write_state) {
case 0:
p->write_latch = p->write_latch | ((val & 0xff) << 8);
p->write_state = 3;
break;
case 3:
p->write_latch = val & 0xff;
p->write_state = 0;
break;
case 1:
p->write_latch = val & 0xff;
break;
case 2:
p->write_latch = (val & 0xff) << 8;
break;
}
if (p->write_state != 0) {
if (p->write_latch == 0) p->cntr = 0x10000;
else p->cntr = p->write_latch;
p->last_ticks=LastTicks;
switch (counter) {
case 0x00: /* Timer hooked to IRQ 0 */
PIC_DeActivateIRQ(0);
timer_ticks=p->cntr << PIT_SHIFT;
timer_buildup=0;
LOG_DEBUG("PIT 0 Timer at %.3g Hz mode %d",PIT_TICK_RATE/(double)p->cntr,p->mode);
break;
case 0x02: /* Timer hooked to PC-Speaker */
PCSPEAKER_SetFreq(PIT_TICK_RATE/p->cntr);
break;
default:
LOG_ERROR("PIT:Illegal timer selected for writing");
}
}
}
static Bit8u read_latch(Bit32u port) {
Bit32u counter=port-0x40;
if (pit[counter].read_latch == -1)
counter_latch(counter);
Bit8u ret;
switch (pit[counter].read_state) {
case 0: /* read MSB & return to state 3 */
ret=(pit[counter].read_latch >> 8) & 0xff;
pit[counter].read_state = 3;
pit[counter].read_latch = -1;
break;
case 3: /* read LSB followed by MSB */
ret = (pit[counter].read_latch & 0xff);
if (pit[counter].mode & 0x80) pit[counter].mode &= 7; /* moved here */
else
pit[counter].read_state = 0;
break;
case 1: /* read MSB */
ret = (pit[counter].read_latch >> 8) & 0xff;
pit[counter].read_latch = -1;
break;
case 2: /* read LSB */
ret = (pit[counter].read_latch & 0xff);
pit[counter].read_latch = -1;
break;
default:
ret=0;
E_Exit("Timer.cpp: error in readlatch");
break;
}
return ret;
}
static void write_p43(Bit32u port,Bit8u val) {
if (val & 1) {
E_Exit("PIT:BCD Counter not supported");
}
Bitu latch=(val >> 6) & 0x03;
switch (latch) {
case 0:
case 1:
case 2:
if ((val & 0x30) == 0) {
/* Counter latch command */
counter_latch(latch);
} else {
pit[latch].read_state = (val >> 4) & 0x03;
pit[latch].write_state = (val >> 4) & 0x03;
pit[latch].mode = (val >> 1) & 0x07;
}
break;
case 3:
E_Exit("Special PIT Latch Read out thing");
}
}
/* The TIMER Part */
enum { T_TICK,T_MICRO,T_DELAY};
struct Timer {
Bitu type;
union {
struct {
TIMER_TickHandler handler;
} tick;
struct{
Bitu count;
Bitu total;
TIMER_MicroHandler handler;
} micro;
struct {
Bitu end;
TIMER_DelayHandler handler;
} delay;
};
};
static Timer * first_timer=0;
static std::list<Timer *> Timers;
TIMER_Block * TIMER_RegisterTickHandler(TIMER_TickHandler handler) {
Timer * new_timer=new(Timer);
new_timer->type=T_TICK;
new_timer->tick.handler=handler;
Timers.push_front(new_timer);
return (TIMER_Block *)new_timer;
}
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);
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;
}
void TIMER_AddTicks(Bit32u ticks) {
/* This will run through registered handlers and handle the PIT ticks */
timer_buildup+=ticks*pit_ticks;
if (timer_buildup>MAX_PASSED) timer_buildup=MAX_PASSED;
Bitu add_micro=ticks*1000;
std::list<Timer *>::iterator i;
for(i=Timers.begin(); i != Timers.end(); ++i) {
Timer * timer=(*i);
switch (timer->type) {
case T_TICK:
timer->tick.handler(ticks);
break;
case T_MICRO:
timer->micro.count+=add_micro;
if (timer->micro.count>=timer->micro.total) {
timer->micro.count-=timer->micro.total;
timer->micro.handler();
}
break;
case T_DELAY:
/* Also unregister the timer handler from the list */
if (LastTicks>timer->delay.end) {
std::list<Timer *>::iterator remove;
timer->delay.handler();
remove=i++;
Timers.erase(remove);
}
break;
default:
E_Exit("TIMER:Illegal handler type");
};
};
}
void TIMER_CheckPIT(void) {
if (timer_buildup>timer_ticks) {
timer_buildup-=timer_ticks;
PIC_ActivateIRQ(0);
return;
}
}
void TIMER_Init(void) {
IO_RegisterWriteHandler(0x40,write_latch,"PIT Timer 0");
IO_RegisterWriteHandler(0x42,write_latch,"PIT Timer 2");
IO_RegisterWriteHandler(0x43,write_p43,"PIT Mode Control");
IO_RegisterReadHandler(0x40,read_latch,"PIT Timer 0");
// IO_RegisterReadHandler(0x41,read_p41,"PIT Timer 1");
IO_RegisterReadHandler(0x42,read_latch,"PIT Timer 2");
/* Setup Timer 0 */
pit[0].cntr=0x10000;
pit[0].write_state = 3;
pit[0].read_state = 3;
pit[0].read_latch=-1;
pit[0].write_latch=0;
pit[0].mode=3;
timer_ticks=pit[0].cntr << PIT_SHIFT;
timer_buildup=0;
// first_timer=0;
pit_ticks=(PIT_TICK_RATE << PIT_SHIFT)/1000;
PIC_RegisterIRQ(0,&TIMER_CheckPIT,"PIT 0 Timer");
}

165
src/hardware/vga.cpp Normal file
View file

@ -0,0 +1,165 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "dosbox.h"
#include "video.h"
#include "pic.h"
#include "render.h"
#include "timer.h"
#include "vga.h"
VGA_Type vga;
Bit32u CGAWriteTable[256];
Bit32u ExpandTable[256];
Bit32u FillTable[16]={
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
0xffff0000,0xffff00ff,0xffffff00,0xffffffff
};
static PageEntry VGA_PageEntry;
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);
void VGA_FindSettings(void) {
/* Sets up the correct memory handler from the vga.mode setting */
MEMORY_ResetHandler(0xA0000/4096,128*1024/4096);
VGA_PageEntry.type=MEMORY_HANDLER;
/* Detect the kind of video mode this is */
if (vga.config.gfxmode) {
if (vga.config.vga_enabled) {
if (vga.config.chained) {
/* 256 color chained vga */
vga.mode=GFX_256C;
//Doesn't need a memory handler
} else {
/* 256 color unchained vga */
vga.mode=GFX_256U;
VGA_PageEntry.base=0xA0000;
VGA_PageEntry.handler.read=VGA_NormalReadHandler;
VGA_PageEntry.handler.write=VGA_GFX_256U_WriteHandler;
MEMORY_SetupHandler(0xA0000/4096,16,&VGA_PageEntry);
}
} else if (vga.config.cga_enabled) {
/* 4 color cga */
//TODO Detect hercules modes, probably set them up in bios too
vga.mode=GFX_4;
// VGA_PageEntry.base=0xB8000;
// VGA_PageEntry.handler.read=VGA_GFX_4_ReadHandler;
// VGA_PageEntry.handler.write=VGA_GFX_4_WriteHandler;
// MEMORY_SetupHandler(0xB8000/4096,8,&VGA_PageEntry);
} else {
/* 16 color ega */
vga.mode=GFX_16;
VGA_PageEntry.base=0xA0000;
VGA_PageEntry.handler.read=VGA_NormalReadHandler;
VGA_PageEntry.handler.write=VGA_GFX_16_WriteHandler;
MEMORY_SetupHandler(0xA0000/4096,16,&VGA_PageEntry);
}
} else {
vga.mode=TEXT_16;
}
VGA_StartResize();
}
static void VGA_DoResize(void) {
vga.draw.resizing=false;
Bitu width,height,pitch;
RENDER_Handler * renderer;
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;
switch (vga.mode) {
case GFX_256C:
renderer=&VGA_Render_GFX_256C;
width<<=2;
pitch=vga.config.scan_len*8;
break;
case GFX_256U:
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 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 */
if (width>640) width=640;
if (height>480) height=480;
pitch=width;
renderer=&VGA_Render_TEXT_16;
};
vga.draw.width=width;
vga.draw.height=height;
RENDER_SetSize(width,height,8,pitch,((float)width/(float)height),0,renderer);
};
void VGA_StartResize(void) {
if (!vga.draw.resizing) {
vga.draw.resizing=true;
/* Start a resize after 50 ms */
TIMER_RegisterDelayHandler(VGA_DoResize,50);
}
}
void VGA_Init() {
vga.draw.resizing=false;
VGA_SetupMemory();
VGA_SetupMisc();
VGA_SetupDAC();
VGA_SetupCRTC();
VGA_SetupGFX();
VGA_SetupSEQ();
VGA_SetupAttr();
/* Generate tables */
Bit32u i;
for (i=0;i<256;i++) {
ExpandTable[i]=i | (i << 8)| (i <<16) | (i << 24);
CGAWriteTable[i]=((i>>6)&3) | (((i>>4)&3) << 8)| (((i>>2)&3) <<16) | (((i>>0)&3) << 24);
}
}

255
src/hardware/vga.h Normal file
View file

@ -0,0 +1,255 @@
/*
* 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.
*/
#ifndef VGA_H_
#define VGA_H_
#include <mem.h>
enum { TEXT, GRAPH };
enum { GFX_256C,GFX_256U,GFX_16,GFX_4,GFX_2, TEXT_16 };
typedef struct {
bool attrindex;
} VGA_Internal;
typedef struct {
/* Video drawing */
Bit16u display_start;
Bit16u real_start;
bool retrace; /* A retrace has started */
Bitu scan_len;
/* Screen resolution and memory mode */
Bitu vdisplayend;
Bitu hdisplayend;
bool chained; /* Enable or Disabled Chain 4 Mode */
bool gfxmode; /* Yes or No Easy no */
bool blinking; /* Attribute bit 7 is blinking */
bool vga_enabled;
bool cga_enabled;
bool vline_double;
Bit8u vline_height;
/* Pixel Scrolling */
Bit8u pel_panning; /* Amount of pixels to skip when starting horizontal line */
Bit8u hlines_skip;
Bit8u bytes_skip;
/* Specific stuff memory write/read handling */
Bit8u read_mode;
Bit8u write_mode;
Bit8u read_map_select;
Bit8u color_dont_care;
Bit8u color_compare;
Bit8u data_rotate;
Bit8u raster_op;
Bit8u enable_set_reset;
Bit8u set_reset;
Bit32u full_bit_mask;
Bit32u full_map_mask;
} VGA_Config;
typedef struct {
bool resizing;
Bitu width;
Bitu height;
Bit8u font_height;
Bit8u cursor_enable;
Bit8u cursor_row;
Bit8u cursor_col;
Bit8u cursor_count;
} VGA_Draw;
typedef struct {
Bit8u index;
Bit8u reset;
Bit8u clocking_mode;
Bit8u map_mask;
Bit8u character_map_select;
Bit8u memory_mode;
} VGA_Seq;
typedef struct {
Bit8u palette[16];
Bit8u mode_control;
Bit8u horizontal_pel_panning;
Bit8u overscan_color;
Bit8u color_plane_enable;
Bit8u color_select;
Bit8u index;
} VGA_Attr;
typedef struct {
Bit8u horizontal_total;
Bit8u horizontal_display_end;
Bit8u start_horizontal_blanking;
Bit8u end_horizontal_blanking;
Bit8u start_horizontal_retrace;
Bit8u end_horizontal_retrace;
Bit8u vertical_total;
Bit8u overflow;
Bit8u preset_row_scan;
Bit8u maximum_scan_line;
Bit8u cursor_start;
Bit8u cursor_end;
Bit8u start_address_high;
Bit8u start_address_low;
Bit8u cursor_location_high;
Bit8u cursor_location_low;
Bit8u vertical_retrace_start;
Bit8u vertical_retrace_end;
Bit8u vertical_display_end;
Bit8u offset;
Bit8u underline_location;
Bit8u start_vertical_blank;
Bit8u end_vertical_blank;
Bit8u mode_control;
Bit8u line_compare;
Bit8u index;
} VGA_Crtc;
typedef struct {
Bit8u index;
Bit8u set_reset;
Bit8u enable_set_reset;
Bit8u color_compare;
Bit8u data_rotate;
Bit8u read_map_select;
Bit8u mode;
Bit8u miscellaneous;
Bit8u color_dont_care;
Bit8u bit_mask;
} VGA_Gfx;
struct RGBEntry {
Bit8u red;
Bit8u green;
Bit8u blue;
Bit8u attr_entry;
};
typedef struct {
Bit8u bits; /* DAC bits, usually 6 or 8 */
Bit8u pel_mask;
Bit8u pel_index;
Bit8u state;
Bit8u index;
Bitu first_changed;
RGBEntry rgb[0x100];
} VGA_Dac;
union VGA_Latch {
Bit32u d;
Bit8u b[4];
};
union VGA_Memory {
Bit8u linear[64*1024*4];
Bit8u paged[64*1024][4];
VGA_Latch latched[64*1024];
};
typedef struct {
Bitu mode; /* The mode the vga system is in */
VGA_Draw draw;
VGA_Config config;
VGA_Internal internal;
/* Internal module groups */
VGA_Seq seq;
VGA_Attr attr;
VGA_Crtc crtc;
VGA_Gfx gfx;
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];
} VGA_Type;
/* Functions for different resolutions */
//void VGA_FindSize(void);
void VGA_FindSettings(void);
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);
/* The Different Memory Read/Write Handlers */
Bit8u VGA_NormalReadHandler(Bit32u start);
void VGA_NormalWriteHandler(Bit32u start,Bit8u val);
void VGA_GFX_256U_WriteHandler(Bit32u start,Bit8u val);
void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val);
void VGA_GFX_4_WriteHandler(Bit32u start,Bit8u val);
Bit8u VGA_ChainedReadHandler(Bit32u start);
void VGA_ChainedWriteHandler(Bit32u start,Bit8u val);
Bit8u VGA_GFX_4_ReadHandler(Bit32u start);
/* Some support functions */
void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal);
/* The VGA Subfunction startups */
void VGA_SetupAttr(void);
void VGA_SetupMemory(void);
void VGA_SetupDAC(void);
void VGA_SetupCRTC(void);
void VGA_SetupMisc(void);
void VGA_SetupGFX(void);
void VGA_SetupSEQ(void);
/* Some Support Functions */
void VGA_DACSetEntirePalette(void);
extern VGA_Type vga;
extern Bit8u vga_rom_8[256 * 8];
extern Bit8u vga_rom_14[256 * 14];
extern Bit8u vga_rom_16[256 * 16];
//extern Bit8u vga_buffer[1024*1024];
extern Bit32u ExpandTable[256];
extern Bit32u FillTable[16];
extern Bit32u CGAWriteTable[256];
#endif

165
src/hardware/vga_attr.cpp Normal file
View file

@ -0,0 +1,165 @@
/*
* 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 "inout.h"
#include "vga.h"
#define attr(blah) vga.attr.blah
void write_p3c0(Bit32u port,Bit8u val) {
if (!vga.internal.attrindex) {
attr(index)=val & 0x1F;
vga.internal.attrindex=true;
/*
0-4 Address of data register to write to port 3C0h or read from port 3C1h
If set screen output is enabled and the palette can not be modified,
if clear screen output is disabled and the palette can be modified.
*/
return;
} else {
vga.internal.attrindex=false;
switch (attr(index)) {
/* Palette */
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
attr(palette[attr(index)])=val;
VGA_DAC_CombineColor(attr(index),val);
/*
0-5 Index into the 256 color DAC table. May be modified by 3C0h index
10h and 14h.
*/
break;
case 0x10: /* Mode Control Register */
attr(mode_control)=val;
vga.config.gfxmode=val&1;
vga.config.vga_enabled=(val & 64)>0;
VGA_FindSettings();
//TODO Monochrome mode
//TODO 9 bit characters
//TODO line wrapping split screen shit see bit 5
//TODO index 14h weirdo dac switch bits
/*
0 Graphics mode if set, Alphanumeric mode else.
1 Monochrome mode if set, color mode else.
2 9-bit wide characters if set.
The 9th bit of characters C0h-DFh will be the same as
the 8th bit. Otherwise it will be the background color.
3 If set Attribute bit 7 is blinking, else high intensity.
5 If set the PEL panning register (3C0h index 13h) is temporarily set
to 0 from when the line compare causes a wrap around until the next
vertical retrace when the register is automatically reloaded with
the old value, else the PEL panning register ignores line compares.
6 If set pixels are 8 bits wide. Used in 256 color modes.
7 If set bit 4-5 of the index into the DAC table are taken from port
3C0h index 14h bit 0-1, else the bits in the palette register are
used.
*/
if (val&128) {
E_Exit("VGA:Special 16 colour DAC Shift");
}
break;
case 0x11: /* Overscan Color Register */
attr(overscan_color)=val;
/* 0-5 Color of screen border. Color is defined as in the palette registers. */
break;
case 0x12: /* Color Plane Enable Register */
/* Why disable colour planes? */
attr(color_plane_enable)=val;
/*
0 Bit plane 0 is enabled if set.
1 Bit plane 1 is enabled if set.
2 Bit plane 2 is enabled if set.
3 Bit plane 3 is enabled if set.
4-5 Video Status MUX. Diagnostics use only.
Two attribute bits appear on bits 4 and 5 of the Input Status
Register 1 (3dAh). 0: Bit 2/0, 1: Bit 5/4, 2: bit 3/1, 3: bit 7/6
*/
break;
case 0x13: /* Horizontal PEL Panning Register */
attr(horizontal_pel_panning)=val & 0xF;
vga.config.pel_panning=val & 0xF;
/*
0-3 Indicates number of pixels to shift the display left
Value 9bit textmode 256color mode Other modes
0 1 0 0
1 2 n/a 1
2 3 1 2
3 4 n/a 3
4 5 2 4
5 6 n/a 5
6 7 3 6
7 8 n/a 7
8 0 n/a n/a
*/
break;
case 0x14: /* Color Select Register */
attr(color_select)=val;
/*
0-1 If 3C0h index 10h bit 7 is set these 2 bits are used as bits 4-5 of
the index into the DAC table.
2-3 These 2 bits are used as bit 6-7 of the index into the DAC table
except in 256 color mode.
Note: this register does not affect 256 color modes.
*/
if (val) LOG_DEBUG("VGA:ATTR:DAC index set to %d",val);
break;
default:
LOG_ERROR("VGA:ATTR:Write to unkown Index %2X",attr(index));
break;
}
}
}
Bit8u read_p3c1(Bit32u port) {
switch (attr(index)) {
/* Palette */
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0a: case 0x0b:
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
return attr(palette[attr(index)]);
case 0x10: /* Mode Control Register */
return attr(mode_control);
case 0x11: /* Overscan Color Register */
return attr(overscan_color);
case 0x12: /* Color Plane Enable Register */
return attr(color_plane_enable);
case 0x13: /* Horizontal PEL Panning Register */
return attr(horizontal_pel_panning);
case 0x14: /* Color Select Register */
return attr(color_select);
default:
LOG_ERROR("VGA:ATTR:Read from unkown Index %2X",attr(index));
}
return 0;
};
void VGA_SetupAttr(void) {
IO_RegisterWriteHandler(0x3c0,write_p3c0,"VGA Attribute controller");
IO_RegisterReadHandler(0x3c1,read_p3c1,"VGA Attribute Read");
}

332
src/hardware/vga_crtc.cpp Normal file
View file

@ -0,0 +1,332 @@
/*
* 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 "inout.h"
#include "vga.h"
#define crtc(blah) vga.crtc.blah
void write_p3d4(Bit32u port,Bit8u val) {
crtc(index)=val;
}
void write_p3d5(Bit32u port,Bit8u val) {
switch(crtc(index)) {
case 0x00: /* Horizontal Total Register */
crtc(horizontal_total)=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_FindSettings();
/* 0-7 Number of Character Clocks Displayed -1 */
break;
case 0x02: /* Start Horizontal Blanking Register */
crtc(start_horizontal_blanking)=val;
/* 0-7 The count at which Horizontal Blanking starts */
break;
case 0x03: /* End Horizontal Blanking Register */
crtc(end_horizontal_blanking)=val;
/*
0-4 Horizontal Blanking ends when the last 6 bits of the character
counter equals this field. Bit 5 is at 3d4h index 5 bit 7.
5-6 Number of character clocks to delay start of display after Horizontal
Total has been reached.
7 Access to Vertical Retrace registers if set. If clear reads to 3d4h
index 10h and 11h access the Lightpen read back registers ??
*/
break;
case 0x04: /* Start Horizontal Retrace Register */
crtc(start_horizontal_retrace)=val;
/* 0-7 Horizontal Retrace starts when the Character Counter reaches this value. */
break;
case 0x05: /* End Horizontal Retrace Register */
crtc(end_horizontal_retrace)=val;
/*
0-4 Horizontal Retrace ends when the last 5 bits of the character counter
equals this value.
5-6 Number of character clocks to delay start of display after Horizontal
Retrace.
7 bit 5 of the End Horizontal Blanking count (See 3d4h index 3 bit 0-4)
*/
break;
case 0x06: /* Vertical Total Register */
crtc(vertical_total)=val;
/* 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.
*/
break;
case 0x07: /* Overflow Register */
crtc(overflow)=val;
vga.config.vdisplayend=(vga.config.vdisplayend&0xFF)|((val&2)<<7)|((val&64)<<2);
VGA_FindSettings();
/*
0 Bit 8 of Vertical Total (3d4h index 6)
1 Bit 8 of Vertical Display End (3d4h index 12h)
2 Bit 8 of Vertical Retrace Start (3d4h index 10h)
3 Bit 8 of Start Vertical Blanking (3d4h index 15h)
4 Bit 8 of Line Compare Register (3d4h index 18h)
5 Bit 9 of Vertical Total (3d4h index 6)
6 Bit 9 of Vertical Display End (3d4h index 12h)
7 Bit 9 of Vertical Retrace Start (3d4h index 10h)
*/
break;
case 0x08: /* Preset Row Scan Register */
crtc(preset_row_scan)=val;
vga.config.hlines_skip=val&31;
vga.config.bytes_skip=(val>>5)&3;
// LOG_DEBUG("Skip lines %d bytes %d",vga.config.hlines_skip,vga.config.bytes_skip);
/*
0-4 Number of lines we have scrolled down in the first character row.
Provides Smooth Vertical Scrolling.b
5-6 Number of bytes to skip at the start of scanline. Provides Smooth
Horizontal Scrolling together with the Horizontal Panning Register
(3C0h index 13h).
*/
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_FindSettings();
/*
0-4 Number of scan lines in a character row -1. In graphics modes this is
the number of times (-1) the line is displayed before passing on to
the next line (0: normal, 1: double, 2: triple...).
This is independent of bit 7, except in CGA modes which seems to
require this field to be 1 and bit 7 to be set to work.
5 Bit 9 of Start Vertical Blanking
6 Bit 9 of Line Compare Register
7 Doubles each scan line if set. I.e. displays 200 lines on a 400 display.
*/
break;
case 0x0A: /* Cursor Start Register */
crtc(cursor_start)=val;
/*
0-4 First scanline of cursor within character.
5 Turns Cursor off if set
*/
break;
case 0x0B: /* Cursor End Register */
crtc(cursor_end)=val;
/*
0-4 Last scanline of cursor within character
5-6 Delay of cursor data in character clocks.
*/
break;
case 0x0C: /* Start Address High Register */
crtc(start_address_high)=val;
vga.config.display_start=(vga.config.display_start & 0x00FF)| (val << 8);
/* 0-7 Upper 8 bits of the start address of the display buffer */
break;
case 0x0D: /* Start Address Low Register */
crtc(start_address_low)=val;
vga.config.display_start=(vga.config.display_start & 0xFF00)| val;
/* 0-7 Lower 8 bits of the start address of the display buffer */
break;
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);
/* 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);
/* 0-7 Lower 8 bits of the address of the cursor */
break;
case 0x10: /* Vertical Retrace Start Register */
crtc(vertical_retrace_start)=val;
/*
0-7 Lower 8 bits of Vertical Retrace Start. Vertical Retrace starts when
the line counter reaches this value. Bit 8 is found in 3d4h index 7
bit 2. Bit 9 is found in 3d4h index 7 bit 7.
*/
break;
case 0x11: /* Vertical Retrace End Register */
crtc(vertical_retrace_end)=val;
/*
0-3 Vertical Retrace ends when the last 4 bits of the line counter equals
this value.
4 if clear Clears pending Vertical Interrupts.
5 Vertical Interrupts (IRQ 2) disabled if set. Can usually be left
disabled, but some systems (including PS/2) require it to be enabled.
6 If set selects 5 refresh cycles per scanline rather than 3.
7 Disables writing to registers 0-7 if set 3d4h index 7 bit 4 is not
affected by this bit.
*/
break;
case 0x12: /* Vertical Display End Register */
crtc(vertical_display_end)=val;
vga.config.vdisplayend=(vga.config.vdisplayend & 0x300)|val;
VGA_FindSettings();
/*
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.
Bit 9 is found in 3d4h index 7 bit 6.
*/
break;
case 0x13: /* Offset register */
crtc(offset)=val;
vga.config.scan_len=val;
VGA_FindSettings();
/*
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.
*/
break;
case 0x14: /* Underline Location Register */
crtc(underline_location)=val;
/*
0-4 Position of underline within Character cell.
5 If set memory address is only changed every fourth character clock.
6 Double Word mode addressing if set
*/
break;
case 0x15: /* Start Vertical Blank Register */
crtc(start_vertical_blank)=val;
/*
0-7 Lower 8 bits of Vertical Blank Start. Vertical blanking starts when
the line counter reaches this value. Bit 8 is found in 3d4h index 7
bit 3.
*/
break;
case 0x16: /* End Vertical Blank Register */
crtc(end_vertical_blank)=val;
/*
0-6 Vertical blanking stops when the lower 7 bits of the line counter
equals this field. Some SVGA chips uses all 8 bits!
*/
break;
case 0x17: /* Mode Control Register */
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,
thus creating 2 banks for even and odd scan lines.
1 If clear use Hercules compatible memory addressing system by
substituting character row scan counter bit 1 for address bit 14,
thus creating 4 banks.
2 If set increase scan line counter only every second line.
3 If set increase memory address counter only every other character clock.
5 When in Word Mode bit 15 is rotated to bit 0 if this bit is set else
bit 13 is rotated into bit 0.
6 If clear system is in word mode. Addresses are rotated 1 position up
bringing either bit 13 or 15 into bit 0.
7 Clearing this bit will reset the display system until the bit is set again.
*/
break;
case 0x18: /* Line Compare Register */
crtc(line_compare)=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
facilities. Bit 8 is found in 3d4h index 7 bit 4.
Bit 9 is found in 3d4h index 9 bit 6.
*/
break;
default:
LOG_ERROR("VGA:CRTC:Write to unknown index %2X",val,crtc(index));
}
}
Bit8u read_p3d5(Bit32u port) {
switch(crtc(index)) {
case 0x00: /* Horizontal Total Register */
return crtc(horizontal_total);
case 0x01: /* Horizontal Display End Register */
return crtc(horizontal_display_end);
case 0x02: /* Start Horizontal Blanking Register */
return crtc(start_horizontal_blanking);
case 0x03: /* End Horizontal Blanking Register */
return crtc(end_horizontal_blanking);
case 0x04: /* Start Horizontal Retrace Register */
return crtc(start_horizontal_retrace);
case 0x05: /* End Horizontal Retrace Register */
return crtc(end_horizontal_retrace);
case 0x06: /* Vertical Total Register */
return crtc(vertical_total);
case 0x07: /* Overflow Register */
return crtc(overflow);
case 0x08: /* Preset Row Scan Register */
return crtc(preset_row_scan);
case 0x09: /* Maximum Scan Line Register */
return crtc(maximum_scan_line);
case 0x0A: /* Cursor Start Register */
return crtc(cursor_start);
case 0x0B: /* Cursor End Register */
return crtc(cursor_end);
case 0x0C: /* Start Address High Register */
return crtc(start_address_high);
case 0x0D: /* Start Address Low Register */
return crtc(start_address_low);
case 0x0E: /*Cursor Location High Register */
return crtc(cursor_location_high);
case 0x0F: /* Cursor Location Low Register */
return crtc(cursor_location_low);
case 0x10: /* Vertical Retrace Start Register */
return crtc(vertical_retrace_start);
case 0x11: /* Vertical Retrace End Register */
return crtc(vertical_retrace_end);
case 0x12: /* Vertical Display End Register */
return crtc(vertical_display_end);
case 0x13: /* Offset register */
return crtc(offset);
case 0x14: /* Underline Location Register */
return crtc(underline_location);
case 0x15: /* Start Vertical Blank Register */
return crtc(start_vertical_blank);
case 0x16: /* End Vertical Blank Register */
return crtc(end_vertical_blank);
case 0x17: /* Mode Control Register */
return crtc(mode_control);
case 0x18: /* Line Compare Register */
return crtc(line_compare);
default:
LOG_ERROR("VGA:CRTC:Read from unknown index %X",crtc(index));
}
return 0;
}
void VGA_SetupCRTC(void) {
IO_RegisterWriteHandler(0x3d4,write_p3d4,"VGA:CRTC Index Select");
IO_RegisterWriteHandler(0x3d5,write_p3d5,"VGA:CRTC Data Register");
IO_RegisterReadHandler(0x3d5,read_p3d5,"VGA:CRTC Data Register");
// IO_RegisterWriteHandler(0x3b4,write_p3d4,"VGA:CRTC Index Select");
// IO_RegisterWriteHandler(0x3b5,write_p3d5,"VGA:CRTC Data Register");
// IO_RegisterReadHandler(0x3b5,read_p3d5,"VGA:CRTC Data Register");
}

160
src/hardware/vga_dac.cpp Normal file
View file

@ -0,0 +1,160 @@
/*
* 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 "inout.h"
#include "render.h"
#include "vga.h"
/*
//TODO PEL Mask Maybe
//TODO Find some way to get palette lookups in groups
3C6h (R/W): PEL Mask
bit 0-7 This register is anded with the palette index sent for each dot.
Should be set to FFh.
3C7h (R): DAC State Register
bit 0-1 0 indicates the DAC is in Write Mode and 3 indicates Read mode.
3C7h (W): PEL Address Read Mode
bit 0-7 The PEL data register (0..255) to be read from 3C9h.
Note: After reading the 3 bytes at 3C9h this register will increment,
pointing to the next data register.
3C8h (R/W): PEL Address Write Mode
bit 0-7 The PEL data register (0..255) to be written to 3C9h.
Note: After writing the 3 bytes at 3C9h this register will increment, pointing
to the next data register.
3C9h (R/W): PEL Data Register
bit 0-5 Color value
Note: Each read or write of this register will cycle through first the
registers for Red, Blue and Green, then increment the appropriate
address register, thus the entire palette can be loaded by writing 0 to
the PEL Address Write Mode register 3C8h and then writing all 768 bytes
of the palette to this register.
*/
enum {DAC_READ,DAC_WRITE};
static void write_p3c6(Bit32u port,Bit8u val) {
if (val!=0xff) LOG_ERROR("VGA:Pel Mask not 0xff");
}
static void write_p3c7(Bit32u port,Bit8u val) {
vga.dac.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.pel_index=0;
vga.dac.state=DAC_WRITE;
}
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.pel_index=1;
break;
case 1:
vga.dac.rgb[vga.dac.index].green=val;
vga.dac.pel_index=2;
break;
case 2:
vga.dac.rgb[vga.dac.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
);
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
);
}
}
vga.dac.index++;
vga.dac.pel_index=0;
break;
default:
LOG_ERROR("VGA:DAC:Illegal Pel Index"); //If this can actually happen that will be the day
};
}
static Bit8u read_p3c9(Bit32u port) {
Bit8u ret;
switch (vga.dac.pel_index) {
case 0:
ret=vga.dac.rgb[vga.dac.index].red;
vga.dac.pel_index=1;
break;
case 1:
ret=vga.dac.rgb[vga.dac.index].green;
vga.dac.pel_index=2;
break;
case 2:
ret=vga.dac.rgb[vga.dac.index].blue;
vga.dac.index++;
vga.dac.pel_index=0;
break;
default:
LOG_ERROR("VGA:DAC:Illegal Pel Index"); //If this can actually happen that will be the day
}
return ret;
}
void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) {
/* Check if this is a new color */
vga.dac.rgb[pal].attr_entry=attr;
RENDER_SetPal(attr,
vga.dac.rgb[pal].red << 2,
vga.dac.rgb[pal].green << 2,
vga.dac.rgb[pal].blue << 2
);
}
void VGA_SetupDAC(void) {
vga.dac.first_changed=256;
vga.dac.bits=6;
vga.dac.pel_mask=0xff;
vga.dac.pel_index=0;
vga.dac.state=DAC_READ;
/* Setup the DAC IO port Handlers */
IO_RegisterWriteHandler(0x3c6,write_p3c6,"PEL Mask");
IO_RegisterWriteHandler(0x3c7,write_p3c7,"PEL Read Mode");
IO_RegisterWriteHandler(0x3c8,write_p3c8,"PEL Write Mode");
IO_RegisterWriteHandler(0x3c9,write_p3c9,"PEL Data");
IO_RegisterReadHandler(0x3c9,read_p3c9,"PEL Data");
};

165
src/hardware/vga_draw.cpp Normal file
View file

@ -0,0 +1,165 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "video.h"
#include "vga.h"
/* This Should draw a complete 16 colour screen */
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;
VGA_DrawTEXT(vga.buffer,vga.draw.width);
vga.config.retrace=true;
}
void VGA_DrawGFX4_Full(Bit8u * bitdata,Bitu next_line) {
//TODO use vga memory handler
Bit8u * reader=real_host(0xB800,0);
Bit8u * draw;
for (Bitu y=0;y<vga.draw.height;y++) {
Bit8u * tempread;
tempread=reader;
if (y&1) {
tempread+=8*1024;
reader+=80;
};
draw=bitdata;
for (Bit32u x=0;x<vga.draw.width>>2;x++) {
Bit8u val=*(tempread++);
/*
*(draw+0)=(val>>6)&3;
*(draw+1)=(val>>4)&3;
*(draw+2)=(val>>2)&3;
*(draw+3)=(val)&3;
draw+=4;
*/
*(Bit32u *)draw=CGAWriteTable[val];
draw+=4;
}
//TODO use scanline length and dword mode crap
bitdata+=next_line;
};
vga.config.retrace=true;
}
void VGA_DrawGFX16_Full(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++) {
memcpy((void *)bitdata,(void *)reader,vga.draw.width);
bitdata+=vga.draw.width+next_line;
reader+=vga.config.scan_len*16;
}
vga.config.retrace=true;
};
/* This Should draw a complete 256 colour screen */
void VGA_DrawGFX256_Full(Bit8u * bitdata,Bitu next_line) {
Bit16u yreader=vga.config.display_start*1;
/* Now add pel panning */
for (Bitu y=0;y<vga.draw.height;y++) {
Bit16u xreader=yreader;
for (Bitu x=0;x<vga.draw.width>>2;x++) {
for (Bit32u dx=0;dx<4;dx++) {
(*bitdata++)=vga.mem.paged[xreader][dx];
}
xreader++;
}
//TODO use scanline length and dword mode crap
yreader+=vga.config.scan_len*2;
bitdata+=next_line;
};
vga.config.retrace=true;
};
void VGA_DrawGFX256_Fast(Bit8u * bitdata,Bitu next_line) {
/* 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+=vga.draw.width+next_line;
reader+=vga.draw.width;
}
//memcpy((void *)bitdata,(void *)(memory+0xa0000),320*200);
vga.config.retrace=true;
};
void VGA_DrawTEXT(Bit8u * bitdata,Bitu next_line) {
Bit8u * reader=real_off(0xB800,0);
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;
for (Bitu cx=0;cx<(vga.draw.width/8);cx++) {
Bit8u c=*(reader++);
Bit8u * findex=&vga_rom_16[c*16];
Bit8u col=*(reader++);
Bit8u fg=col & 0xF;
Bit8u bg=(col>> 4);
Bit8u * draw=draw_char;
for (Bitu y=0;y<16;y++) {
Bit8u bit_mask=*findex++;
#include "font-switch.h"
draw+=+next_line;
};
draw_char+=8;
};
draw_start+=16*next_line;
};
vga.config.retrace=true;
/* Draw a cursor */
if ((vga.draw.cursor_col*8)>=vga.draw.width) return;
if ((vga.draw.cursor_row*16)>=vga.draw.height) return;
Bit8u * cursor_draw=bitdata+(vga.draw.cursor_row*16+15)*vga.draw.width+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;
};

1254
src/hardware/vga_fonts.cpp Normal file

File diff suppressed because it is too large Load diff

221
src/hardware/vga_gfx.cpp Normal file
View file

@ -0,0 +1,221 @@
/*
* 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 "inout.h"
#include "vga.h"
#define gfx(blah) vga.gfx.blah
static bool index9warned=false;
void write_p3ce(Bit32u port,Bit8u val) {
gfx(index)=val & 0x0f;
}
Bit8u read_p3ce(Bit32u port) {
return gfx(index);
}
void write_p3cf(Bit32u port,Bit8u val) {
switch (gfx(index)) {
case 0: /* Set/Reset Register */
gfx(set_reset)=val & 0x0f;
vga.config.set_reset=val & 0x0f;
/*
0 If in Write Mode 0 and bit 0 of 3CEh index 1 is set a write to
display memory will set all the bits in plane 0 of the byte to this
bit, if the corresponding bit is set in the Map Mask Register (3CEh
index 8).
1 Same for plane 1 and bit 1 of 3CEh index 1.
2 Same for plane 2 and bit 2 of 3CEh index 1.
3 Same for plane 3 and bit 3 of 3CEh index 1.
*/
// LOG_DEBUG("Set Reset = %2X",val);
break;
case 1: /* Enable Set/Reset Register */
gfx(enable_set_reset)=val & 0x0f;
vga.config.enable_set_reset=val & 0x0f;
/*
0 If set enables Set/reset of plane 0 in Write Mode 0.
1 Same for plane 1.
2 Same for plane 2.
3 Same for plane 3.
*/
// LOG_DEBUG("Enable Set Reset = %2X",val);
break;
case 2: /* Color Compare Register */
gfx(color_compare)=val & 0x0f;
/*
0-3 In Read Mode 1 each pixel at the address of the byte read is compared
to this color and the corresponding bit in the output set to 1 if
they match, 0 if not. The Color Don't Care Register (3CEh index 7)
can exclude bitplanes from the comparison.
*/
vga.config.color_compare=val & 0xf;
// LOG_DEBUG("Color Compare = %2X",val);
break;
case 3: /* Data Rotate */
gfx(data_rotate)=val;
vga.config.data_rotate=val & 7;
vga.config.raster_op=(val>>3) & 3;
/*
0-2 Number of positions to rotate data right before it is written to
display memory. Only active in Write Mode 0.
3-4 In Write Mode 2 this field controls the relation between the data
written from the CPU, the data latched from the previous read and the
data written to display memory:
0: CPU Data is written unmodified
1: CPU data is ANDed with the latched data
2: CPU data is ORed with the latch data.
3: CPU data is XORed with the latched data.
*/
// if (vga.config.data_rotate || vga.config.raster_op ) LOG_DEBUG("Data Rotate = %2X Raster op %2X",val & 7,(val>>3) & 3 );
break;
case 4: /* Read Map Select Register */
/* 0-1 number of the plane Read Mode 0 will read from */
gfx(read_map_select)=val & 0x03;
vga.config.read_map_select=val & 0x03;
// LOG_DEBUG("Read Map %2X",val);
break;
case 5: /* Mode Register */ /* Important one very */
gfx(mode)=val;
vga.config.write_mode=val & 3;
vga.config.read_mode=(val >> 3) & 1;
// LOG_DEBUG("Write Mode %d Read Mode %d val %d",vga.config.write_mode,vga.config.read_mode,val);
/*
0-1 Write Mode: Controls how data from the CPU is transformed before
being written to display memory:
0: Mode 0 works as a Read-Modify-Write operation.
First a read access loads the data latches of the VGA with the
value in video memory at the addressed location. Then a write
access will provide the destination address and the CPU data
byte. The data written is modified by the function code in the
Data Rotate register (3CEh index 3) as a function of the CPU
data and the latches, then data is rotated as specified by the
same register.
1: Mode 1 is used for video to video transfers.
A read access will load the data latches with the contents of
the addressed byte of video memory. A write access will write
the contents of the latches to the addressed byte. Thus a single
MOVSB instruction can copy all pixels in the source address byte
to the destination address.
2: Mode 2 writes a color to all pixels in the addressed byte of
video memory. Bit 0 of the CPU data is written to plane 0 et
cetera. Individual bits can be enabled or disabled through the
Bit Mask register (3CEh index 8).
3: Mode 3 can be used to fill an area with a color and pattern. The
CPU data is rotated according to 3CEh index 3 bits 0-2 and anded
with the Bit Mask Register (3CEh index 8). For each bit in the
result the corresponding pixel is set to the color in the
Set/Reset Register (3CEh index 0 bits 0-3) if the bit is set and
to the contents of the processor latch if the bit is clear.
3 Read Mode
0: Data is read from one of 4 bit planes depending on the Read Map
Select Register (3CEh index 4).
1: Data returned is a comparison between the 8 pixels occupying the
read byte and the color in the Color Compare Register (3CEh
index 2). A bit is set if the color of the corresponding pixel
matches the register.
4 Enables Odd/Even mode if set (See 3C4h index 4 bit 2).
5 Enables CGA style 4 color pixels using even/odd bit pairs if set.
6 Enables 256 color mode if set.
*/
break;
case 6: /* Miscellaneous Register */
gfx(miscellaneous)=val;
/*
0 Indicates Graphics Mode if set, Alphanumeric mode else.
1 Enables Odd/Even mode if set.
2-3 Memory Mapping:
0: use A000h-BFFFh
1: use A000h-AFFFh VGA Graphics modes
2: use B000h-B7FFh Monochrome modes
3: use B800h-BFFFh CGA modes
*/
break;
case 7: /* Color Don't Care Register */
gfx(color_dont_care)=val & 0x0f;
/*
0 Ignore bit plane 0 in Read mode 1 if clear.
1 Ignore bit plane 1 in Read mode 1 if clear.
2 Ignore bit plane 2 in Read mode 1 if clear.
3 Ignore bit plane 3 in Read mode 1 if clear.
*/
vga.config.color_dont_care=val & 0xf;
// LOG_DEBUG("Color don't care = %2X",val);
break;
case 8: /* Bit Mask Register */
gfx(bit_mask)=val;
vga.config.full_bit_mask=ExpandTable[val];
// LOG_DEBUG("Bit mask %2X",val);
/*
0-7 Each bit if set enables writing to the corresponding bit of a byte in
display memory.
*/
break;
case 9: /* Unknown */
/* Crystal Dreams seems to like to write tothis register very weird */
if (!index9warned) {
LOG_WARN("VGA:3CF:Write %2X to illegal index 9",val);
index9warned=true;
}
break;
default:
LOG_WARN("VGA:3CF:Write %2X to illegal index %2X",val,gfx(index));
break;
}
}
Bit8u read_p3cf(Bit32u port) {
switch (gfx(index)) {
case 0: /* Set/Reset Register */
return gfx(set_reset);
case 1: /* Enable Set/Reset Register */
return gfx(enable_set_reset);
case 2: /* Color Compare Register */
return gfx(color_compare);
case 3: /* Data Rotate */
return gfx(data_rotate);
case 4: /* Read Map Select Register */
return gfx(read_map_select);
case 5: /* Mode Register */
return gfx(mode);
case 6: /* Miscellaneous Register */
return gfx(miscellaneous);
case 7: /* Color Don't Care Register */
return gfx(color_dont_care);
case 8: /* Bit Mask Register */
return gfx(bit_mask);
default:
LOG_WARN("Reading from illegal index %2X in port %4X",gfx(index),port);
}
return 0; /* Compiler happy */
}
void VGA_SetupGFX(void) {
IO_RegisterWriteHandler(0x3ce,write_p3ce,"VGA Graphics Index");
IO_RegisterWriteHandler(0x3cf,write_p3cf,"VGA Graphics Data");
IO_RegisterReadHandler(0x3ce,read_p3ce,"Vga Graphics Index");
IO_RegisterReadHandler(0x3cf,read_p3cf,"Vga Graphics Data");
}

214
src/hardware/vga_memory.cpp Normal file
View file

@ -0,0 +1,214 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "dosbox.h"
#include "mem.h"
#include "vga.h"
Bit8u VGA_ChainedReadHandler(Bit32u start) {
return vga.mem.linear[start];
}
void VGA_ChainedWriteHandler(Bit32u start,Bit8u val) {
vga.mem.linear[start]=val;
};
Bit8u VGA_NormalReadHandler(Bit32u start) {
vga.latch.d=vga.mem.latched[start].d;
switch (vga.config.read_mode) {
case 0:
return(vga.latch.b[vga.config.read_map_select]);
case 1:
VGA_Latch templatch;
templatch.d=(vga.latch.d & FillTable[vga.config.color_dont_care]) ^ FillTable[vga.config.color_compare & vga.config.color_dont_care];
return ~(templatch.b[0] | templatch.b[1] | templatch.b[2] | templatch.b[3]);
}
return 0;
}
//Nice one from DosEmu
INLINE Bit32u RasterOp(Bit32u input,Bit32u mask) {
switch (vga.config.raster_op) {
case 0x00: /* None */
return (input & mask) | (vga.latch.d & ~mask);
case 0x01: /* AND */
return (input | ~mask) & vga.latch.d;
case 0x02: /* OR */
return (input & mask) | vga.latch.d;
case 0x03: /* XOR */
return (input & mask) ^ vga.latch.d;
};
return 0;
}
Bit8u VGA_GFX_4_ReadHandler(Bit32u start) {
return vga.mem.linear[start];
}
void VGA_GFX_4_WriteHandler(Bit32u start,Bit8u val) {
vga.mem.linear[start]=val;
Bitu line=start / 320;
Bitu x=start % 320;
Bit8u * draw=&vga.buffer[start<<2];
/* 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;
}
void VGA_GFX_16_WriteHandler(Bit32u start,Bit8u val) {
VGA_Latch new_latch;
Bitu bit_mask;
switch (vga.config.write_mode) {
case 0x00:
// Write Mode 0: In this mode, the host data is first rotated as per the Rotate Count field, then the Enable Set/Reset mechanism selects data from this or the Set/Reset field. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
// val=(val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate));
//Todo could also include the rotation in the table :)
new_latch.d=ExpandTable[val];
{
Bit32u resetmask=FillTable[vga.config.enable_set_reset];
new_latch.d=(new_latch.d & ~resetmask) | ( FillTable[vga.config.set_reset] & resetmask);
};
new_latch.d=RasterOp(new_latch.d,vga.config.full_bit_mask);
bit_mask=vga.gfx.bit_mask;
break;
case 0x01:
// Write Mode 1: In this mode, data is transferred directly from the 32 bit latch register to display memory, affected only by the Memory Plane Write Enable field. The host data is not used in this mode.
new_latch.d=vga.latch.d;
bit_mask=0xff;
break;
case 0x02:
//Write Mode 2: In this mode, the bits 3-0 of the host data are replicated across all 8 bits of their respective planes. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
new_latch.d=RasterOp(FillTable[val&0xF],vga.config.full_bit_mask);
bit_mask=vga.gfx.bit_mask;
break;
case 0x03:
// Write Mode 3: In this mode, the data in the Set/Reset field is used as if the Enable Set/Reset field were set to 1111b. Then the host data is first rotated as per the Rotate Count field, then logical ANDed with the value of the Bit Mask field. The resulting value is used on the data obtained from the Set/Reset field in the same way that the Bit Mask field would ordinarily be used. to select which bits come from the expansion of the Set/Reset field and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
new_latch.d=ExpandTable[val];
new_latch.d&=vga.config.full_bit_mask; //Dunno would anyone use this seems a bit pointless
bit_mask=new_latch.b[0];
new_latch.d=RasterOp(FillTable[vga.config.set_reset],new_latch.d);
break;
default:
LOG_ERROR("VGA:Unsupported write mode %d",vga.config.write_mode);
}
/* Update video memory and the pixel buffer */
VGA_Latch pixels;
pixels.d=vga.mem.latched[start].d;
pixels.d&=~vga.config.full_map_mask;
pixels.d|=(new_latch.d & vga.config.full_map_mask);
vga.mem.latched[start].d=pixels.d;
Bit8u * write_pixels=&vga.buffer[start<<3];
#if 1
Bit8u sel=128;
do {
if (bit_mask & sel) {
Bitu color;
color=0;
if (pixels.b[0] & sel) color|=1;
if (pixels.b[1] & sel) color|=2;
if (pixels.b[2] & sel) color|=4;
if (pixels.b[3] & sel) color|=8;
*write_pixels=color;
*(write_pixels+512*1024)=color;
}
write_pixels++;
sel>>=1;
} while (sel);
#else
#include "ega-switch.h"
#endif
}
void VGA_GFX_256U_WriteHandler(Bit32u start,Bit8u val) {
VGA_Latch new_latch;
switch (vga.config.write_mode) {
case 0x00:
/* This should be no problem with big or little endian */
// Write Mode 0: In this mode, the host data is first rotated as per the Rotate Count field, then the Enable Set/Reset mechanism selects data from this or the Set/Reset field. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
// val=(val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate));
//Todo could also include the rotation in the table :)
new_latch.d=ExpandTable[val];
{
Bit32u resetmask=FillTable[vga.config.enable_set_reset];
new_latch.d=(new_latch.d & ~resetmask) | ( FillTable[vga.config.set_reset] & resetmask);
};
new_latch.d=RasterOp(new_latch.d,vga.config.full_bit_mask);
break;
case 0x01:
// Write Mode 1: In this mode, data is transferred directly from the 32 bit latch register to display memory, affected only by the Memory Plane Write Enable field. The host data is not used in this mode.
new_latch.d=vga.latch.d;
break;
case 0x02:
//TODO this mode also has Raster op
//Write Mode 2: In this mode, the bits 3-0 of the host data are replicated across all 8 bits of their respective planes. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
new_latch.d=RasterOp(FillTable[val&0xF],vga.config.full_bit_mask);
break;
case 0x03:
// Write Mode 3: In this mode, the data in the Set/Reset field is used as if the Enable Set/Reset field were set to 1111b. Then the host data is first rotated as per the Rotate Count field, then logical ANDed with the value of the Bit Mask field. The resulting value is used on the data obtained from the Set/Reset field in the same way that the Bit Mask field would ordinarily be used. to select which bits come from the expansion of the Set/Reset field and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory.
new_latch.d=ExpandTable[val];
new_latch.d&=vga.config.full_bit_mask; //Dunno would anyone use this seems a bit pointless
new_latch.d=RasterOp(FillTable[vga.config.set_reset],new_latch.d);
break;
default:
E_Exit("VGA:Unsupported write mode %d",vga.config.write_mode);
}
VGA_Latch pixels;
pixels.d=vga.mem.latched[start].d;
pixels.d&=~vga.config.full_map_mask;
pixels.d|=(new_latch.d & vga.config.full_map_mask);
vga.mem.latched[start].d=pixels.d;
vga.mem.latched[start+64*1024].d=pixels.d;
};
void VGA_SetupMemory() {
memset((void *)&vga.mem,0,256*1024);
/* Alocate Video Memory */
/* Not needed for VGA memory it gets allocated together with emulator maybe
later for VESA memory */
}

70
src/hardware/vga_misc.cpp Normal file
View file

@ -0,0 +1,70 @@
/*
* 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 "inout.h"
#include "timer.h"
#include "vga.h"
static Bit8u flip=0;
static Bit32u keep_vretrace;
static bool keeping=false;
static Bit8u p3c2data;
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;
}
};
static void write_p3d8(Bit32u port,Bit8u val) {
return;
}
static void write_p3c2(Bit32u port,Bit8u val) {
p3c2data=val;
}
static Bit8u read_p3c2(Bit32u port) {
return p3c2data;
}
void VGA_SetupMisc(void) {
IO_RegisterReadHandler(0x3da,read_p3da,"VGA Input Status 1");
// IO_RegisterWriteHandler(0x3d8,write_p3d8,"VGA Mode Control");
IO_RegisterWriteHandler(0x3c2,write_p3c2,"VGA Misc Output");
IO_RegisterReadHandler(0x3c2,read_p3c2,"VGA Misc Output");
}

125
src/hardware/vga_seq.cpp Normal file
View file

@ -0,0 +1,125 @@
/*
* 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 "inout.h"
#include "vga.h"
#define seq(blah) vga.seq.blah
Bit8u read_p3c4(Bit32u port) {
return seq(index);
}
void write_p3c4(Bit32u port,Bit8u val) {
seq(index)=val;
};
void write_p3c5(Bit32u port,Bit8u val) {
switch(seq(index)) {
case 0: /* Reset */
seq(reset)=val;
break;
case 1: /* Clocking Mode */
seq(clocking_mode)=val;
/* TODO Figure this out :)
0 If set character clocks are 8 dots wide, else 9.
2 If set loads video serializers every other character
clock cycle, else every one.
3 If set the Dot Clock is Master Clock/2, else same as Master Clock
(See 3C2h bit 2-3). (Doubles pixels). Note: on some SVGA chipsets
this bit also affects the Sequencer mode.
4 If set loads video serializers every fourth character clock cycle,
else every one.
5 if set turns off screen and gives all memory cycles to the CPU
interface.
*/
break;
case 2: /* Map Mask */
seq(map_mask)=val & 15;
vga.config.full_map_mask=FillTable[val & 15];
/*
0 Enable writes to plane 0 if set
1 Enable writes to plane 1 if set
2 Enable writes to plane 2 if set
3 Enable writes to plane 3 if set
*/
break;
case 3: /* Character Map Select */
seq(character_map_select)=val;
/*
0,1,4 Selects VGA Character Map (0..7) if bit 3 of the character
attribute is clear.
2,3,5 Selects VGA Character Map (0..7) if bit 3 of the character
attribute is set.
Note: Character Maps are placed as follows:
Map 0 at 0k, 1 at 16k, 2 at 32k, 3: 48k, 4: 8k, 5: 24k, 6: 40k, 7: 56k
*/
break;
case 4: /* Memory Mode */
/*
0 Set if in an alphanumeric mode, clear in graphics modes.
1 Set if more than 64kbytes on the adapter.
2 Enables Odd/Even addressing mode if set. Odd/Even mode places all odd
bytes in plane 1&3, and all even bytes in plane 0&2.
3 If set address bit 0-1 selects video memory planes (256 color mode),
rather than the Map Mask and Read Map Select Registers.
*/
seq(memory_mode)=val;
/* Changing this means changing the VGA Memory Read/Write Handler */
if (val&0x08) vga.config.chained=true;
else vga.config.chained=false;
VGA_FindSettings();
break;
default:
LOG_ERROR("VGA:SEQ:Write to illegal index %2X",seq(index));
};
};
Bit8u read_p3c5(Bit32u port) {
switch(seq(index)) {
case 0: /* Reset */
return seq(reset);
break;
case 1: /* Clocking Mode */
return seq(clocking_mode);
break;
case 2: /* Map Mask */
return seq(map_mask);
break;
case 3: /* Character Map Select */
return seq(character_map_select);
break;
case 4: /* Memory Mode */
return seq(memory_mode);
default:
LOG_ERROR("VGA:SEQ:Read from illegal index %2X",seq(index));
};
return 0;
};
void VGA_SetupSEQ(void) {
IO_RegisterWriteHandler(0x3c4,write_p3c4,"VGA:Sequencer Index");
IO_RegisterWriteHandler(0x3c5,write_p3c5,"VGA:Sequencer Data");
IO_RegisterReadHandler(0x3c4,read_p3c4,"VGA:Sequencer Index");
IO_RegisterReadHandler(0x3c5,read_p3c5,"VGA:Sequencer Data");
}

6
src/ints/Makefile.am Normal file
View file

@ -0,0 +1,6 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libints.a
libints_a_SOURCES = mouse.cpp xms.cpp ems.cpp \
int10.cpp int10.h int10_char.cpp int10_memory.cpp int10_misc.cpp int10_modes.cpp int10_pal.cpp int10_put_pixel.cpp \
bios.cpp bios_disk.cpp bios_keyboard.cpp

235
src/ints/bios.cpp Normal file
View file

@ -0,0 +1,235 @@
/*
* 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 <time.h>
#include "dosbox.h"
#include "bios.h"
#include "regs.h"
#include "callback.h"
#include "inout.h"
#include "mem.h"
static Bitu call_int1a,call_int11,call_int8,call_int17,call_int12,call_int15,call_int1c;
static Bitu INT1A_Handler(void) {
switch (reg_ah) {
case 0x00: /* Get System time */
{
Bit32u ticks=mem_readd(BIOS_TIMER);
reg_al=0; /* Midnight never passes :) */
reg_cx=(Bit16u)(ticks >> 16);
reg_dx=(Bit16u)(ticks & 0xffff);
break;
}
case 0x01: /* Set System time */
mem_writed(BIOS_TIMER,(reg_cx<<16)|reg_dx);
break;
case 0x02: /* GET REAL-TIME CLOCK TIME (AT,XT286,PS) */
reg_dx=reg_cx=0;
CALLBACK_SCF(false);
LOG_WARN("INT1A:02:Faked RTC get time call");
break;
case 0x04: /* GET REAL-TIME ClOCK DATA (AT,XT286,PS) */
reg_dx=reg_cx=0;
CALLBACK_SCF(false);
LOG_WARN("INT1A:04:Faked RTC get date call");
break;
case 0x80: /* Pcjr Setup Sound Multiplexer */
LOG_WARN("INT1A:80:Setup tandy sound multiplexer to %d",reg_al);
break;
case 0x81: /* Tandy sound system checks */
LOG_WARN("INT1A:81:Tandy DAC Check failing");
break;
/*
INT 1A - Tandy 2500, Tandy 1000L series - DIGITAL SOUND - INSTALLATION CHECK
AX = 8100h
Return: AL > 80h if supported
AX = 00C4h if supported (1000SL/TL)
CF set if sound chip is busy
CF clear if sound chip is free
Note: the value of CF is not definitive; call this function until CF is
clear on return, then call AH=84h"Tandy"
*/
default:
LOG_WARN("INT1A:Undefined call %2X",reg_ah);
}
return CBRET_NONE;
}
static Bitu INT11_Handler(void) {
/*
AX = BIOS equipment list word
bits
0 floppy disk(s) installed (see bits 6-7)
1 80x87 coprocessor installed
2,3 number of 16K banks of RAM on motherboard (PC only)
number of 64K banks of RAM on motherboard (XT only)
2 pointing device installed (PS)
3 unused (PS)
4-5 initial video mode
00 EGA, VGA, or PGA
01 40x25 color
10 80x25 color
11 80x25 monochrome
6-7 number of floppies installed less 1 (if bit 0 set)
8 DMA support installed (PCjr, some Tandy 1000s, 1400LT)
9-11 number of serial ports installed
12 game port installed
13 serial printer attached (PCjr)
internal modem installed (PC/Convertible)
14-15 number of parallel ports installed
*/
reg_eax=0x104D;
return CBRET_NONE;
}
static Bitu INT8_Handler(void) {
/* Increase the bios tick counter */
mem_writed(BIOS_TIMER,mem_readd(BIOS_TIMER)+1);
CALLBACK_RunRealInt(0x1c);
IO_Write(0x20,0x20);
return CBRET_NONE;
};
static Bitu INT1C_Handler(void) {
return CBRET_NONE;
};
static Bitu INT12_Handler(void) {
reg_ax=mem_readw(BIOS_MEMORY_SIZE);
return CBRET_NONE;
};
static Bitu INT17_Handler(void) {
LOG_ERROR("INT17:Not supported call for bios printer support");
switch(reg_ah) {
case 0x00: /* PRINTER: Write Character */
reg_ah=1; /* Report a timeout */
break;
case 0x01: /* PRINTER: Initialize port */
break;
case 0x02: /* PRINTER: Get Status */
reg_ah=0;
break;
default:
E_Exit("Unhandled INT 17 call %2X",reg_ah);
};
return CBRET_NONE;
};
static Bitu INT15_Handler(void) {
switch (reg_ah) {
case 0x06:
LOG_WARN("Calling unkown int15 function 6");
break;
case 0xC0: /* Get Configuration*/
LOG_WARN("Request BIOS Configuration INT 15 C0");
CALLBACK_SCF(true);
break;
case 0x84: /* BIOS - JOYSTICK SUPPORT (XT after 11/8/82,AT,XT286,PS) */
//Does anyone even use this?
LOG_WARN("INT15:84:Bios Joystick functionality not done");
reg_ax=reg_bx=reg_cx=reg_dx=0;
break;
case 0x86: /* BIOS - WAIT (AT,PS) */
{
//TODO Perhaps really wait :)
Bit32u micro=(reg_cx<<16)|reg_dx;
CALLBACK_SCF(false);
}
case 0x88: /* SYSTEM - GET EXTENDED MEMORY SIZE (286+) */
reg_ax=0;
CALLBACK_SCF(false);
break;
case 0x90: /* OS HOOK - DEVICE BUSY */
CALLBACK_SCF(true);
reg_ah=0;
break;
case 0xc2: /* BIOS PS2 Pointing Device Support */
/*
Damn programs should use the mouse drivers
So let's fail these calls
*/
CALLBACK_SCF(true);
break;
case 0xc4: /* BIOS POS Programma option Select */
LOG_WARN("INT15:C4:Call for POS Function %2x",reg_al);
CALLBACK_SCF(true);
break;
default:
LOG_WARN("INT15:Unknown call %2X",reg_ah);
}
return CBRET_NONE;
};
static void INT15_StartUp(void) {
/* TODO Start the time correctly */
};
void BIOS_SetupKeyboard(void);
void BIOS_SetupDisks(void);
void BIOS_Init(void) {
/* Clear the Bios Data Area */
for (Bit16u i=0;i<1024;i++) real_writeb(0x40,i,0);
/* Setup all the interrupt handlers the bios controls */
/* INT 8 Clock IRQ Handler */
//TODO Maybe give this a special callback that will also call int 8 instead of starting
//a new system
call_int8=CALLBACK_Allocate();
CALLBACK_Setup(call_int8,&INT8_Handler,CB_IRET);
mem_writed(BIOS_TIMER,0); //Calculate the correct time
RealSetVec(0x8,CALLBACK_RealPointer(call_int8));
/* INT10 Video Bios */
INT10_StartUp();
/* INT 11 Get equipment list */
call_int11=CALLBACK_Allocate();
CALLBACK_Setup(call_int11,&INT11_Handler,CB_IRET);
RealSetVec(0x11,CALLBACK_RealPointer(call_int11));
/* INT 12 Memory Size default at 640 kb */
call_int12=CALLBACK_Allocate();
CALLBACK_Setup(call_int12,&INT12_Handler,CB_IRET);
RealSetVec(0x12,CALLBACK_RealPointer(call_int12));
mem_writew(BIOS_MEMORY_SIZE,640);
/* INT 13 Bios Disk Support */
BIOS_SetupDisks();
/* INT 15 Misc Calls */
call_int15=CALLBACK_Allocate();
CALLBACK_Setup(call_int15,&INT15_Handler,CB_IRET);
RealSetVec(0x15,CALLBACK_RealPointer(call_int15));
/* INT 16 Keyboard handled in another file */
BIOS_SetupKeyboard();
/* INT 16 Printer Routines */
call_int17=CALLBACK_Allocate();
CALLBACK_Setup(call_int17,&INT17_Handler,CB_IRET);
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);
RealSetVec(0x1A,CALLBACK_RealPointer(call_int1a));
/* INT 1C System Timer tick called from INT 8 */
call_int1c=CALLBACK_Allocate();
CALLBACK_Setup(call_int1c,&INT1C_Handler,CB_IRET);
RealSetVec(0x1C,CALLBACK_RealPointer(call_int1c));
}

95
src/ints/bios_disk.cpp Normal file
View file

@ -0,0 +1,95 @@
/*
* 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 "callback.h"
#include "bios.h"
#include "regs.h"
#include "mem.h"
static Bitu call_int13;
static BIOS_Disk * Floppys[2];
static BIOS_Disk * Harddisks[BIOS_MAX_DISK];
static Bit8u last_status;
static Bitu INT13_FullHandler(void) {
/* Check for disk numbers */
BIOS_Disk * disk=Floppys[0];
switch (reg_ah) {
case 0x00:
last_status=reg_ah=0;
break;
case 0x01: /* Get Status of last operation */
reg_ah=last_status;
break;
case 0x02: /* Read Sectors into Memory */
last_status=reg_ah=disk->Read_Sector(&reg_al,reg_dh,reg_ch,(reg_cl & 0x3f)-1,real_off(Segs[es].value,reg_bx));
CALLBACK_SCF(false);
break;
case 0x03: /* Write Sectors from Memory */
last_status=reg_ah=disk->Write_Sector(&reg_al,reg_dh,reg_ch,(reg_cl & 0x3f)-1,real_off(Segs[es].value,reg_bx));
CALLBACK_SCF(false);
break;
default:
LOG_DEBUG("INT13:Illegal call %2X",reg_ah);
reg_ah=0xff;
CALLBACK_SCF(true);
}
return CBRET_NONE;
};
static Bitu INT13_SmallHandler(void) {
switch (reg_ah) {
case 0x02: /* Read Disk Sectors */
LOG_DEBUG("INT13:02:Read Disk Sectors not supported failing");
reg_ah=0xff;
CALLBACK_SCF(true);
break;
case 0x08: /* Get Drive Parameters */
LOG_DEBUG("INT13:08:Get Drive parameters not supported failing");
reg_ah=0xff;
CALLBACK_SCF(true);
break;
case 0xff:
default:
LOG_WARN("Illegal int 13h call %2X Fail it",reg_ah);
reg_ah=0xff;
CALLBACK_SCF(true);
}
return CBRET_NONE;
}
void BIOS_SetupDisks(void) {
/* TODO Start the time correctly */
call_int13=CALLBACK_Allocate();
#ifdef C_IMAGE
Floppys[0]=new imageDisk("c:\\test.img");
for (Bit32u i=0;i<BIOS_MAX_DISK;i++) Harddisks[i]=0;
CALLBACK_Setup(call_int13,&INT13_FullHandler,CB_IRET);
#else
CALLBACK_Setup(call_int13,&INT13_SmallHandler,CB_IRET);
#endif
RealSetVec(0x13,CALLBACK_RealPointer(call_int13));
/* Init the Disk Tables */
last_status=0;
/* Setup the Bios Area */
mem_writeb(BIOS_HARDDISK_COUNT,0);
};

381
src/ints/bios_keyboard.cpp Normal file
View file

@ -0,0 +1,381 @@
/*
* 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 "callback.h"
#include "mem.h"
#include "bios.h"
#include "keyboard.h"
#include "regs.h"
#include "inout.h"
static Bitu call_int16,call_irq1;
/* Nice table from BOCHS i should feel bad for ripping this */
#define none 0
#define MAX_SCAN_CODE 0x53
static struct {
Bit16u normal;
Bit16u shift;
Bit16u control;
Bit16u alt;
} scan_to_scanascii[MAX_SCAN_CODE + 1] = {
{ none, none, none, none },
{ 0x011b, 0x011b, 0x011b, 0x0100 }, /* escape */
{ 0x0231, 0x0221, none, 0x7800 }, /* 1! */
{ 0x0332, 0x0340, 0x0300, 0x7900 }, /* 2@ */
{ 0x0433, 0x0423, none, 0x7a00 }, /* 3# */
{ 0x0534, 0x0524, none, 0x7b00 }, /* 4$ */
{ 0x0635, 0x0625, none, 0x7c00 }, /* 5% */
{ 0x0736, 0x075e, 0x071e, 0x7d00 }, /* 6^ */
{ 0x0837, 0x0826, none, 0x7e00 }, /* 7& */
{ 0x0938, 0x092a, none, 0x7f00 }, /* 8* */
{ 0x0a39, 0x0a28, none, 0x8000 }, /* 9( */
{ 0x0b30, 0x0b29, none, 0x8100 }, /* 0) */
{ 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* -_ */
{ 0x0d3d, 0x0d2b, none, 0x8300 }, /* =+ */
{ 0x0e08, 0x0e08, 0x0e7f, none }, /* backspace */
{ 0x0f09, 0x0f00, none, none }, /* tab */
{ 0x1071, 0x1051, 0x1011, 0x1000 }, /* Q */
{ 0x1177, 0x1157, 0x1117, 0x1100 }, /* W */
{ 0x1265, 0x1245, 0x1205, 0x1200 }, /* E */
{ 0x1372, 0x1352, 0x1312, 0x1300 }, /* R */
{ 0x1474, 0x1454, 0x1414, 0x1400 }, /* T */
{ 0x1579, 0x1559, 0x1519, 0x1500 }, /* Y */
{ 0x1675, 0x1655, 0x1615, 0x1600 }, /* U */
{ 0x1769, 0x1749, 0x1709, 0x1700 }, /* I */
{ 0x186f, 0x184f, 0x180f, 0x1800 }, /* O */
{ 0x1970, 0x1950, 0x1910, 0x1900 }, /* P */
{ 0x1a5b, 0x1a7b, 0x1a1b, none }, /* [{ */
{ 0x1b5d, 0x1b7d, 0x1b1d, none }, /* ]} */
{ 0x1c0d, 0x1c0d, 0x1c0a, none }, /* Enter */
{ none, none, none, none }, /* L Ctrl */
{ 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* A */
{ 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* S */
{ 0x2064, 0x2044, 0x2004, 0x2000 }, /* D */
{ 0x2166, 0x2146, 0x2106, 0x2100 }, /* F */
{ 0x2267, 0x2247, 0x2207, 0x2200 }, /* G */
{ 0x2368, 0x2348, 0x2308, 0x2300 }, /* H */
{ 0x246a, 0x244a, 0x240a, 0x2400 }, /* J */
{ 0x256b, 0x254b, 0x250b, 0x2500 }, /* K */
{ 0x266c, 0x264c, 0x260c, 0x2600 }, /* L */
{ 0x273b, 0x273a, none, none }, /* ;: */
{ 0x2827, 0x2822, none, none }, /* '" */
{ 0x2960, 0x297e, none, none }, /* `~ */
{ none, none, none, none }, /* L shift */
{ 0x2b5c, 0x2b7c, 0x2b1c, none }, /* |\ */
{ 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* Z */
{ 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* X */
{ 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* C */
{ 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* V */
{ 0x3062, 0x3042, 0x3002, 0x3000 }, /* B */
{ 0x316e, 0x314e, 0x310e, 0x3100 }, /* N */
{ 0x326d, 0x324d, 0x320d, 0x3200 }, /* M */
{ 0x332c, 0x333c, none, none }, /* ,< */
{ 0x342e, 0x343e, none, none }, /* .> */
{ 0x352f, 0x353f, none, none }, /* /? */
{ none, none, none, none }, /* R Shift */
{ 0x372a, 0x372a, none, none }, /* * */
{ none, none, none, none }, /* L Alt */
{ 0x3920, 0x3920, 0x3920, 0x3920 }, /* space */
{ none, none, none, none }, /* caps lock */
{ 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* F1 */
{ 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* F2 */
{ 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* F3 */
{ 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* F4 */
{ 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* F5 */
{ 0x4000, 0x5900, 0x6300, 0x6d00 }, /* F6 */
{ 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* F7 */
{ 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* F8 */
{ 0x4300, 0x5c00, 0x6600, 0x7000 }, /* F9 */
{ 0x4400, 0x5d00, 0x6700, 0x7100 }, /* F10 */
{ none, none, none, none }, /* Num Lock */
{ none, none, none, none }, /* Scroll Lock */
{ 0x4700, 0x4737, 0x7700, none }, /* 7 Home */
{ 0x4800, 0x4838, none, none }, /* 8 UP */
{ 0x4900, 0x4939, 0x8400, none }, /* 9 PgUp */
{ 0x4a2d, 0x4a2d, none, none }, /* - */
{ 0x4b00, 0x4b34, 0x7300, none }, /* 4 Left */
{ 0x4c00, 0x4c35, none, none }, /* 5 */
{ 0x4d00, 0x4d36, 0x7400, none }, /* 6 Right */
{ 0x4e2b, 0x4e2b, none, none }, /* + */
{ 0x4f00, 0x4f31, 0x7500, none }, /* 1 End */
{ 0x5000, 0x5032, none, none }, /* 2 Down */
{ 0x5100, 0x5133, 0x7600, none }, /* 3 PgDn */
{ 0x5200, 0x5230, none, none }, /* 0 Ins */
{ 0x5300, 0x532e, none, none } /* Del */
};
/*
Old Stuff not needed after i ripped Bochs :)
static Bit8u KeyNoShift[128]={
27,'1','2','3', '4','5','6','7', '8','9','0','-', '=',8,9,'q',
'w','e','r','t', 'y','u','i','o', 'p','[',']',13, 255,'a','s','d',
'f','g','h','j', 'k','l',';','\'', '`',255,'\\','z', 'x','c','v','b',
'n','m',',','.', '/',255,'*',255, ' ',255,0,0, 0,0,0,0,
0,0,0,0, 255,255,0,0, 0,'-',0,255, 0,'+',0,0,
0,0,0,0, 0
};
static Bit8u KeyShift[128]={
27,'!','@','#', '$','%','^','&', '*','(',')','_', '+',8,9,'Q',
'W','E','R','T', 'Y','U','I','O', 'P','{','}',13, 255,'A','S','D',
'F','G','H','J', 'K','L',':','"', '~',255,'|','Z', 'X','C','V','B',
'N','M','<','>', '?',255,'*',255, ' ',255,0,0, 0,0,0,0,
0,0,0,0, 255,255,0,0, 0,'-',0,255, 0,'+',0,0,
0,0,0,0, 0
};
*/
static void add_key(Bit16u code) {
Bit16u start,end,head,tail,ttail;
start=mem_readw(BIOS_KEYBOARD_BUFFER_START);
end =mem_readw(BIOS_KEYBOARD_BUFFER_END);
head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
ttail=tail+2;
if (ttail>=end) ttail=start;
/* Check for buffer Full */
//TODO Maybe beeeeeeep or something although that should happend when internal buffer is full
if (ttail==head) return;
real_writew(0x40,tail,code);
mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,ttail);
}
static Bit16u get_key(void) {
Bit16u start,end,head,tail,thead;
start=mem_readw(BIOS_KEYBOARD_BUFFER_START);
end =mem_readw(BIOS_KEYBOARD_BUFFER_END);
head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
if (head==tail) return 0;
thead=head+2;
if (thead>=end) thead=start;
mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,thead);
return real_readw(0x40,head);
}
static Bit16u check_key(void) {
Bit16u head,tail;
head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD);
tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL);
if (head==tail) return 0;
return real_readw(0x40,head);
}
/* Flag Byte 1
bit 7 =1 INSert active
bit 6 =1 Caps Lock active
bit 5 =1 Num Lock active
bit 4 =1 Scroll Lock active
bit 3 =1 either Alt pressed
bit 2 =1 either Ctrl pressed
bit 1 =1 Left Shift pressed
bit 0 =1 Right Shift pressed
*/
/* Flag Byte 2
bit 7 =1 INSert pressed
bit 6 =1 Caps Lock pressed
bit 5 =1 Num Lock pressed
bit 4 =1 Scroll Lock pressed
bit 3 =1 Pause state active
bit 2 =1 Sys Req pressed
bit 1 =1 Left Alt pressed
bit 0 =1 Left Ctrl pressed
*/
/*
Keyboard status byte 3
bit 7 =1 read-ID in progress
bit 6 =1 last code read was first of two ID codes
bit 5 =1 force Num Lock if read-ID and enhanced keyboard
bit 4 =1 enhanced keyboard installed
bit 3 =1 Right Alt pressed
bit 2 =1 Right Ctrl pressed
bit 1 =1 last code read was E0h
bit 0 =1 last code read was E1h
*/
static Bitu IRQ1_Handler(void) {
//TODO CAPSLOCK NUMLOCK SCROLLLOCK maybe :)
Bit8u code=IO_Read(0x60);
//TODO maybe implement the int 0x15 ah=4f scancode lookup hook
/* Changed it so the flag handling takes place in here too */
Bit8u flags1=mem_readb(BIOS_KEYBOARD_FLAGS1);
Bit8u flags2=mem_readb(BIOS_KEYBOARD_FLAGS2);
Bit8u flags3=mem_readb(BIOS_KEYBOARD_FLAGS3);
switch (code) {
/* First the hard ones */
case 0xe0:
//TODO Think of something else maybe
flags3|=2;
break;
case 29: /* Ctrl Pressed */
flags1|=4;
if (flags3 & 2) flags3|=4;
else flags2|=1;
break;
case 157: /* Ctrl Released */
flags1&=~4;
if (flags3 & 2) flags3&=~4;
else flags2&=~1;
break;
case 42: /* Left Shift Pressed */
flags1|=2;
break;
case 170: /* Left Shift Released */
flags1&=~2;
break;
case 54: /* Right Shift Pressed */
flags1|=1;
break;
case 182: /* Right Shift Released */
flags1&=~1;
break;
case 56: /* Alt Pressed */
flags1|=8;
if (flags3 & 2) flags3|=8;
else flags2|=2;
break;
case 184: /* Alt Released */
flags1&=~8;
if (flags3 & 2) flags3&=~8;
else flags2&=~2;
break;
#if 0
case 58:p_capslock=true;break; /* Caps Lock */
case 186:p_capslock=false;break;
case 69:p_numlock=true;break; /* Num Lock */
case 197:p_numlock=false;break;
case 70:p_scrolllock=true;break; /* Scroll Lock */
case 198:p_scrolllock=false;break;
case 82:p_insert=true;break; /* Insert */
case 210:p_insert=false;a_insert=!a_insert;break;
#endif
default: /* Normal Key */
Bit16u asciiscan;
/* Now Handle the releasing of keys and see if they match up for a code */
flags3&=~2; //Reset 0xE0 Flag
/* Handle the actual scancode */
if (code & 0x80) goto irq1_end;
if (code > MAX_SCAN_CODE) goto irq1_end;
if (flags1 & 8) { /* Alt is being pressed */
asciiscan=scan_to_scanascii[code].alt;
} else if (flags1 & 4) { /* Ctrl is being pressed */
asciiscan=scan_to_scanascii[code].control;
} else if (flags1 & 3) { /* Either shift is being pressed */
//TODO Maybe check for Capslock sometime in some bored way
asciiscan=scan_to_scanascii[code].shift;
} else {
asciiscan=scan_to_scanascii[code].normal;
}
add_key(asciiscan);
};
irq1_end:
mem_writeb(BIOS_KEYBOARD_FLAGS1,flags1);
mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2);
mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3);
IO_Write(0x20,0x20);
/* Signal the keyboard for next code */
Bit8u old61=IO_Read(0x61);
IO_Write(0x61,old61 | 128);
IO_Write(0x61,old61 & 127);
return CBRET_NONE;
}
static Bitu INT16_Handler(void) {
Bit16u temp;
switch (reg_ah) {
case 0x00: /* GET KEYSTROKE */
case 0x10:
{
//TODO find a more elegant way to do this
do {
temp=get_key();
if (temp==0) { flags.intf=true;CALLBACK_Idle();};
} while (temp==0);
reg_ax=temp;
break;
}
case 0x01: /* CHECK FOR KEYSTROKE */
case 0x11:
temp=check_key();
if (temp==0) {
CALLBACK_SZF(true);
} else {
CALLBACK_SZF(false);
reg_ax=temp;
}
break;
case 0x02: /* GET SHIFT FlAGS */
reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1);
break;
case 0x03: /* SET TYPEMATIC RATE AND DELAY */
//Have to implement this trhough SDL
LOG_DEBUG("INT16:Unhandled Typematic Rate Call %2X",reg_al);
break;
case 0x05: /* STORE KEYSTROKE IN KEYBOARD BUFFER */
//TODO make add_key bool :)
add_key(reg_ax);
reg_al=0;
break;
case 0x12: /* GET EXTENDED SHIFT STATES */
reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1);
reg_ah=mem_readb(BIOS_KEYBOARD_FLAGS2);
break;
case 0x55:
/* Weird call used by some dos apps */
LOG_DEBUG("INT16:55:Word TSR compatible call");
break;
default:
E_Exit("INT16:Unhandled call %02X",reg_ah);
break;
};
return CBRET_NONE;
}
static void InitBiosSegment(void) {
/* Setup the variables for keyboard in the bios data segment */
mem_writew(BIOS_KEYBOARD_BUFFER_START,0x1e);
mem_writew(BIOS_KEYBOARD_BUFFER_END,0x3e);
mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,0x1e);
mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,0x1e);
mem_writeb(BIOS_KEYBOARD_FLAGS1,0);
mem_writeb(BIOS_KEYBOARD_FLAGS2,0);
mem_writeb(BIOS_KEYBOARD_FLAGS3,16); /* Enhanced keyboard installed */
}
void BIOS_SetupKeyboard(void) {
/* Init the variables */
InitBiosSegment();
/* 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);
RealSetVec(0x16,CALLBACK_RealPointer(call_int16));
CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRET);
RealSetVec(0x9,CALLBACK_RealPointer(call_irq1));
}

165
src/ints/ems.cpp Normal file
View file

@ -0,0 +1,165 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "callback.h"
#include "mem.h"
#include "bios.h"
#include "keyboard.h"
#include "regs.h"
#include "inout.h"
#include "dos_inc.h"
#define PAGEFRAME_SEG 0xe000
class device_EMS : public DOS_Device {
public:
device_EMS();
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
Bit8u cache;
};
bool device_EMS::Read(Bit8u * data,Bit16u * size) {
return false;
}
bool device_EMS::Write(Bit8u * data,Bit16u * size) {
return false;
}
bool device_EMS::Seek(Bit32u * pos,Bit32u type) {
return false;
}
bool device_EMS::Close() {
return false;
}
Bit16u device_EMS::GetInformation(void) {
return 0x8093;
};
device_EMS::device_EMS() {
name="EMMXXXX0";
}
PageEntry ems_entries[4];
Bitu call_int67;
static Bitu INT67_Handler(void) {
switch (reg_ah) {
case 0x40: /* Get Status */
reg_ah=0; //Status ok :)
break;
case 0x41: /* Get PageFrame Segment */
reg_bx=PAGEFRAME_SEG;
reg_ah=0;
break;
case 0x42: /* Get number of pages */
{
//HEHE Hope this works not exactly like the specs but who cares
Bit16u maxfree,total;
EMM_GetFree(&maxfree,&total);
reg_dx=maxfree>>2;
reg_bx=total>>2;
reg_ah=0;
};
break;
case 0x43: /* Get Handle and Allocate Pages */
{
if (!reg_bx) { reg_ah=0x89;break; }
Bit16u handle;
EMM_Allocate(reg_bx*4,&handle);
if (handle) {
reg_ah=0;
reg_dx=handle;
} else { reg_ah=0x88; }
break;
}
case 0x44: /* Map Memory */
{
if (reg_al>3) { reg_ah=0x8b;break; }
HostPt pagestart=memory+EMM_Handles[reg_dx].phys_base+reg_bx*16*1024;
ems_entries[reg_al].relocate=pagestart;
reg_ah=0;
break;
}
case 0x45: /* Release handle and free pages */
EMM_Free(reg_dx);
reg_ah=0;
break;
case 0x46: /* Get EMM Version */
reg_ah=0;
reg_al=0x32; //Only 3.2 support for now
break;
case 0x47: /* Save Mapping Context */
LOG_ERROR("EMS:47:Save Mapping Context not supported");
reg_ah=0x8c;
break;
case 0xDE: /* VCPI Functions */
LOG_ERROR("VCPI Functions not supported");
reg_ah=0x8c;
break;
default:
LOG_ERROR("EMS:Call %2X not supported",reg_ah);
reg_ah=0x8c;
break;
}
return CBRET_NONE;
}
void EMS_Init(void) {
call_int67=CALLBACK_Allocate();
CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET);
/* Register the ems device */
DOS_Device * newdev = new device_EMS();
DOS_AddDevice(newdev);
/* Setup the page handlers for the page frame */
for (Bitu i=0;i<4;i++) {
ems_entries[i].base=(PAGEFRAME_SEG<<4)+i*16*1024;
ems_entries[i].type=MEMORY_RELOCATE;
ems_entries[i].relocate=memory+(PAGEFRAME_SEG<<4)+i*16*1024;
/* Place the page handlers in the ems page fram piece of the memory handler*/
MEMORY_SetupHandler(((PAGEFRAME_SEG<<4)+i*16*1024)>>12,4,&ems_entries[i]);
}
/* Add a little hack so it appears that there is an actual ems device installed */
char * emsname="EMMXXXX0";
Bit16u seg=DOS_GetMemory(2); //We have 32 bytes
MEM_BlockWrite(real_phys(seg,0xa),emsname,strlen(emsname)+1);
/* Copy the callback piece into the beginning */
char buf[16];
MEM_BlockRead(real_phys(CB_SEG,call_int67<<4),buf,0xa);
MEM_BlockWrite(real_phys(seg,0),buf,0xa);
RealSetVec(0x67,RealMake(seg,0));
}

278
src/ints/int10.cpp Normal file
View file

@ -0,0 +1,278 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "bios.h"
#include "mem.h"
#include "callback.h"
#include "regs.h"
#include "video.h"
#include "inout.h"
#include "int10.h"
#define TEXT_SEG 0xb800
static Bitu call_10;
static bool warned_ff=false;
static Bitu INT10_Handler(void) {
switch (reg_ah) {
case 0x00: /* Set VideoMode */
INT10_SetVideoMode(reg_al);
break;
case 0x01: /* Set TextMode Cursor Shape */
LOG_WARN("INT10:01:Set textmode cursor shape not supported");
break;
case 0x02: /* Set Cursor Pos */
//TODO Check some shit but not really usefull
INT10_SetCursorPos(reg_dh,reg_dl,reg_bh);
break;
case 0x03: /* get Cursor Pos and Cursor Shape*/
//TODO the Cursor Shape Stuff
reg_dl=CURSOR_POS_COL(reg_bh);
reg_dh=CURSOR_POS_ROW(reg_bh);
break;
case 0x04: /* read light pen pos YEAH RIGHT */
LOG_WARN("INT10:04:Ligthpen not supported");
break;
case 0x05: /* Set Active Page */
INT10_SetActivePage(reg_al);
break;
case 0x06: /* Scroll Up */
//TODO Graphics mode scroll
INT10_ScrollUpWindow(reg_ch,reg_cl,reg_dh,reg_dl,reg_al,reg_bh,0xFF);
break;
case 0x07: /* Scroll Down */
INT10_ScrollDownWindow(reg_ch,reg_cl,reg_dh,reg_dl,reg_al,reg_bh,0xFF);
break;
case 0x08: /* Read character & attribute at cursor */
//TODO Check for GRAPH and then just return
INT10_ReadCharAttr(&reg_ax,reg_bh);
break;
case 0x09: /* Write Character & Attribute at cursor CX times */
INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,true);
break;
case 0x0A: /* Write Character at cursor CX times */
INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,false);
break;
case 0x0B: /* Set Background/Border Colour & Set Palette*/
break;
E_Exit("Unsupported int 10 call %02X" ,reg_ah);
break;
case 0x0C: /* Write Graphics Pixel */
INT10_PutPixel(reg_cx,reg_dx,reg_bh,reg_al);
break;
case 0x0D: /* Read Graphics Pixel */
INT10_GetPixel(reg_cx,reg_dx,reg_bh,&reg_al);
break;
case 0x0E: /* Teletype OutPut */
//TODO FIX
INT10_TeletypeOutput(reg_al,reg_bl,false,0);
// INT10_TeletypeOutput(reg_al,reg_bl,false,reg_bh);
break;
case 0x0F: /* Get videomode */
reg_bh=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
reg_al=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE);
reg_ah=(Bit8u)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS);
break;
case 0x10: /* EGA/VGA Palette functions */
switch (reg_al) {
case 0x00: /* SET SINGLE PALETTE REGISTER */
INT10_SetSinglePaletteRegister(reg_bl,reg_bh);
break;
case 0x01: /* SET BORDER (OVERSCAN) COLOR*/
INT10_SetOverscanBorderColor(reg_bh);
break;
case 0x02: /* SET ALL PALETTE REGISTERS */
INT10_SetAllPaletteRegisters(real_phys(Segs[es].value,reg_dx));
break;
case 0x03: /* TOGGLE INTENSITY/BLINKING BIT */
INT10_ToggleBlinkingBit(reg_bl);
break;
case 0x07: /* GET SINGLE PALETTE REGISTER */
INT10_GetSinglePaletteRegister(reg_bl,&reg_bh);
break;
case 0x08: /* READ OVERSCAN (BORDER COLOR) REGISTER */
INT10_GetOverscanBorderColor(&reg_bh);
break;
case 0x09: /* READ ALL PALETTE REGISTERS AND OVERSCAN REGISTER */
INT10_GetAllPaletteRegisters(real_phys(Segs[es].value,reg_dx));
break;
case 0x10: /* SET INDIVIDUAL DAC REGISTER */
INT10_SetSingleDacRegister(reg_bl,reg_dh,reg_ch,reg_cl);
break;
case 0x12: /* SET BLOCK OF DAC REGISTERS */
INT10_SetDACBlock(reg_bx,reg_cx,real_phys(Segs[es].value,reg_dx));
break;
case 0x15: /* GET INDIVIDUAL DAC REGISTER */
INT10_GetSingleDacRegister(reg_bl,&reg_dh,&reg_ch,&reg_cl);
break;
case 0x17: /* GET BLOCK OF DAC REGISTER */
INT10_GetDACBlock(reg_bx,reg_cx,real_phys(Segs[es].value,reg_dx));
break;
default:
LOG_WARN("INT10:10:Unhandled EGA/VGA Palette Function %2X",reg_al);
}
break;
case 0x11: /* Character generator functions */
switch (reg_al) {
case 0x30:/* Get Font Information */
switch (reg_bh) {
case 0x00: /* interupt 0x1f vector */
{
RealPt int_1f=RealGetVec(0x1f);
SetSegment_16(es,RealSeg(int_1f));
reg_bp=RealOff(int_1f);
reg_cx=8;
}
break;
case 0x01: /* interupt 0x43 vector */
{
RealPt int_43=RealGetVec(0x43);
SetSegment_16(es,RealSeg(int_43));
reg_bp=RealOff(int_43);
reg_cx=8;
}
break;
case 0x02: /* font 8x14 */
SetSegment_16(es,RealSeg(int10_romarea.font_14));
reg_bp=RealOff(int10_romarea.font_14);
reg_cx=14;
break;
case 0x03: /* font 8x8 first 128 */
SetSegment_16(es,RealSeg(int10_romarea.font_8_first));
reg_bp=RealOff(int10_romarea.font_8_first);
reg_cx=8;
break;
case 0x04: /* font 8x8 second 128 */
SetSegment_16(es,RealSeg(int10_romarea.font_8_second));
reg_bp=RealOff(int10_romarea.font_8_second);
reg_cx=8;
break;
case 0x06: /* font 8x16 */
SetSegment_16(es,RealSeg(int10_romarea.font_16));
reg_bp=RealOff(int10_romarea.font_16);
reg_cx=16;
break;
default:
reg_cx=16;
LOG_DEBUG("INT10:11:30 Request for font %2X",reg_bh);
}
reg_dl=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS);
break;
default:
LOG_WARN("INT10:11:Unsupported character generator call %2X",reg_al);
}
break;
case 0x12: /* alternate function select */
switch (reg_bl) {
case 0x10: /* Get EGA Information */
{
reg_bh=(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)==0x3B4);
reg_bl=3; //256 kb
reg_cx=real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES) & 0x0F;
break;
}
default:
LOG_WARN("Alternate functions select %2X not handled",reg_bl);
}
break;
case 0x13: /* Write String */
INT10_WriteString(reg_dh,reg_dl,reg_al,reg_bl,real_phys(Segs[es].value,reg_bp),reg_cx,reg_bh);
break;
case 0x1A: /* Display Combination */
if (reg_al==0) {
reg_bx=real_readb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX);
reg_al=0x1A;
break;
}
if (reg_al==1) {
real_writeb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,reg_bl);
reg_al=0x1A;
break;
}
LOG_DEBUG("INT10:1A:Display Combination call %2X",reg_al);
break;
case 0x1B: /* functionality State Information */
switch (reg_bx) {
case 0x0000:
INT10_GetFuncStateInformation(Segs[es].value,reg_di);
reg_al=0x1B;
break;
default:
LOG_WARN("INT10:1B:Unhandled call BX %2X",reg_bx);
}
break;
case 0xff:
if (!warned_ff) LOG_WARN("INT10:FF:Weird NC call");
warned_ff=true;
break;
default:
LOG_WARN("Unhandled INT 10 call %2X",reg_ah);
};
return CBRET_NONE;
}
static void INT10_Seg40Init(void) {
//This should fill the ega vga structures
// init detected hardware BIOS Area
real_writew(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE,real_readw(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE)&0xFFCF);
// Just for the first int10 find its children
// the default char height
real_writeb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16);
// Clear the screen
real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,0x60);
// Set the basic screen we have
real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0xF9);
// Set the basic modeset options
real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,0x51);
// Set the default MSR
real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x09);
INT10_SetVideoMode(3);
}
static void INT10_InitVGA(void) {
/* switch to color mode and enable CPU access 480 lines */
IO_Write(0x3c2,0xc3);
/* More than 64k */
IO_Write(0x3c4,0x04);
IO_Write(0x3c5,0x02);
};
void INT10_StartUp(void) {
INT10_InitVGA();
/* Setup the INT 10 vector */
call_10=CALLBACK_Allocate();
//TODO ERRORS ERRORS ERRORS
if (call_10==-1) E_Exit("Error can't allocate Video Int 10 CallBack\n");
CALLBACK_Setup(call_10,&INT10_Handler,CB_IRET);
RealSetVec(0x10,CALLBACK_RealPointer(call_10));
//Init the 0x40 segment and init the datastructures in the the video rom area
INT10_SetupRomMemory();
INT10_Seg40Init();
};

205
src/ints/int10.h Normal file
View file

@ -0,0 +1,205 @@
/*
* 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.
*/
#define BIOSMEM_SEG 0x40
#define BIOSMEM_INITIAL_MODE 0x10
#define BIOSMEM_CURRENT_MODE 0x49
#define BIOSMEM_NB_COLS 0x4A
#define BIOSMEM_PAGE_SIZE 0x4C
#define BIOSMEM_CURRENT_START 0x4E
#define BIOSMEM_CURSOR_POS 0x50
#define BIOSMEM_CURSOR_TYPE 0x60
#define BIOSMEM_CURRENT_PAGE 0x62
#define BIOSMEM_CRTC_ADDRESS 0x63
#define BIOSMEM_CURRENT_MSR 0x65
#define BIOSMEM_CURRENT_PAL 0x66
#define BIOSMEM_NB_ROWS 0x84
#define BIOSMEM_CHAR_HEIGHT 0x85
#define BIOSMEM_VIDEO_CTL 0x87
#define BIOSMEM_SWITCHES 0x88
#define BIOSMEM_MODESET_CTL 0x89
#define BIOSMEM_DCC_INDEX 0x8A
#define BIOSMEM_VS_POINTER 0xA8
/*
*
* VGA registers
*
*/
#define VGAREG_ACTL_ADDRESS 0x3c0
#define VGAREG_ACTL_WRITE_DATA 0x3c0
#define VGAREG_ACTL_READ_DATA 0x3c1
#define VGAREG_INPUT_STATUS 0x3c2
#define VGAREG_WRITE_MISC_OUTPUT 0x3c2
#define VGAREG_VIDEO_ENABLE 0x3c3
#define VGAREG_SEQU_ADDRESS 0x3c4
#define VGAREG_SEQU_DATA 0x3c5
#define VGAREG_PEL_MASK 0x3c6
#define VGAREG_DAC_STATE 0x3c7
#define VGAREG_DAC_READ_ADDRESS 0x3c7
#define VGAREG_DAC_WRITE_ADDRESS 0x3c8
#define VGAREG_DAC_DATA 0x3c9
#define VGAREG_READ_FEATURE_CTL 0x3ca
#define VGAREG_READ_MISC_OUTPUT 0x3cc
#define VGAREG_GRDC_ADDRESS 0x3ce
#define VGAREG_GRDC_DATA 0x3cf
#define VGAREG_MDA_CRTC_ADDRESS 0x3b4
#define VGAREG_MDA_CRTC_DATA 0x3b5
#define VGAREG_VGA_CRTC_ADDRESS 0x3d4
#define VGAREG_VGA_CRTC_DATA 0x3d5
#define VGAREG_MDA_WRITE_FEATURE_CTL 0x3ba
#define VGAREG_VGA_WRITE_FEATURE_CTL 0x3da
#define VGAREG_ACTL_RESET 0x3da
#define VGAREG_MDA_MODECTL 0x3b8
#define VGAREG_CGA_MODECTL 0x3d8
#define VGAREG_CGA_PALETTE 0x3d9
/* Video memory */
#define VGAMEM_GRAPH 0xA000
#define VGAMEM_CTEXT 0xB800
#define VGAMEM_MTEXT 0xB000
/*
*
* Tables of default values for each mode
*
*/
#define MODE_MAX 0x13
#define TEXT 0x00
#define GRAPH 0x01
#define CTEXT 0x00
#define MTEXT 0x01
#define CGA 0x02
#define PLANAR1 0x03
#define PLANAR2 0x04
#define PLANAR4 0x05
#define LINEAR8 0x06
// for SVGA
#define LINEAR15 0x07
#define LINEAR16 0x08
#define LINEAR24 0x09
#define LINEAR32 0x0
#define SCREEN_SIZE(x,y) (((x*y*2)|0x00ff)+1)
#define SCREEN_MEM_START(x,y,p) ((((x*y*2)|0x00ff)+1)*p)
#define SCREEN_IO_START(x,y,p) ((((x*y)|0x00ff)+1)*p)
extern Bit8u int10_font_08[256 * 8];
extern Bit8u int10_font_14[256 * 14];
extern Bit8u int10_font_16[256 * 16];
typedef struct
{Bit8u svgamode;
Bit16u vesamode;
Bit8u type; /* TEXT, GRAPH */
Bit8u memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
Bit8u nbpages;
Bit8u pixbits;
Bit16u swidth, sheight;
Bit16u twidth, theight;
Bit16u cwidth, cheight;
Bit16u sstart;
Bit16u slength;
Bit8u miscreg;
Bit8u pelmask;
Bit8u crtcmodel;
Bit8u actlmodel;
Bit8u grdcmodel;
Bit8u sequmodel;
Bit8u dacmodel; /* 0 1 2 3 */
} VGAMODES;
extern VGAMODES vga_modes[MODE_MAX+1];
typedef struct {
RealPt font_8_first;
RealPt font_8_second;
RealPt font_14;
RealPt font_16;
RealPt static_state;
} VGAROMAREA;
extern VGAROMAREA int10_romarea;
#define BIOS_NCOLS Bit16u ncols=real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS);
#define BIOS_NROWS Bit16u nrows=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1;
inline Bit8u CURSOR_POS_COL(Bit8u page) {
return real_readb(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2);
}
inline Bit8u CURSOR_POS_ROW(Bit8u page) {
return real_readb(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2+1);
}
void INT10_SetVideoMode(Bit8u mode);
void INT10_ScrollUpWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8u nlines,Bit8u attr,Bit8u page);
void INT10_ScrollDownWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8u nlines,Bit8u attr,Bit8u page);
void INT10_SetActivePage(Bit8u page);
void INT10_GetFuncStateInformation(Bit16u seg,Bit16u off);
void INT10_SetCursorPos(Bit8u row,Bit8u col,Bit8u page);
void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page);
void INT10_ReadCharAttr(Bit16u * result,Bit8u page);
void INT10_WriteChar(Bit8u chr,Bit8u attr,Bit8u page,Bit16u count,bool showattr);
void INT10_WriteString(Bit8u row,Bit8u col,Bit8u flag,Bit8u attr,PhysPt string,Bit16u count,Bit8u page);
/* Graphics Stuff */
void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color);
void INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color);
VGAMODES * GetCurrentMode(void);
/* Palette Group */
void INT10_SetSinglePaletteRegister(Bit8u reg,Bit8u val);
void INT10_SetOverscanBorderColor(Bit8u val);
void INT10_SetAllPaletteRegisters(PhysPt data);
void INT10_ToggleBlinkingBit(Bit8u state);
void INT10_GetSinglePaletteRegister(Bit8u reg,Bit8u * val);
void INT10_GetOverscanBorderColor(Bit8u * val);
void INT10_GetAllPaletteRegisters(PhysPt data);
void INT10_SetSingleDacRegister(Bit8u index,Bit8u red,Bit8u green,Bit8u blue);
void INT10_GetSingleDacRegister(Bit8u index,Bit8u * red,Bit8u * green,Bit8u * blue);
void INT10_SetDACBlock(Bit16u index,Bit16u count,PhysPt data);
void INT10_GetDACBlock(Bit16u index,Bit16u count,PhysPt data);
/* Sup Groups */
void INT10_SetupRomMemory(void);

394
src/ints/int10_char.cpp Normal file
View file

@ -0,0 +1,394 @@
/*
* 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.
*/
/* Character displaying moving functions */
#include "dosbox.h"
#include "bios.h"
#include "mem.h"
#include "inout.h"
#include "int10.h"
void INT10_ScrollDownWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8u nlines,Bit8u attr,Bit8u page) {
// Bit8u mode;
Bit16u fill=( (attr << 8) | ' ');
BIOS_NCOLS;BIOS_NROWS;
if(rul>rlr) return;
if(cul>clr) return;
if(rlr>=nrows) rlr=(Bit8u)nrows-1;
if(clr>=ncols) clr=(Bit8u)ncols-1;
// Get the current page
if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
/* Get this from active video mode */
Bit16u textseg=0xb800;
PhysPt start=real_phys(textseg,ncols*nrows*2*page);
Bit32u dcol=clr-cul+1;
Bit32u drow=rlr-rul+1;
Bit32u tocopy;
PhysPt dest=start+((rlr*ncols)+cul)*2;
PhysPt src = 0;/* for gcc */
if (nlines==0) {
nlines=(Bit8u)nrows;
}
if (nlines>=drow) {
tocopy=0;
} else {
tocopy=drow-nlines;
src=start+(((rul+tocopy-1)*ncols)+cul)*2;
}
for (Bit32u y=0;y<drow;y++) {
if (tocopy) {
for(Bit32u x=0;x<dcol;x++) {
mem_writew(dest,mem_readw(src));
src+=2;
dest+=2;
}
src-=(ncols+dcol)*2;
dest-=(ncols+dcol)*2;
tocopy--;
} else {
for(Bit32u x=0;x<dcol;x++) {
mem_writew(dest,fill);
dest+=2;
}
dest-=(ncols+dcol)*2;
}
}
}
void INT10_ScrollUpWindow(Bit8u rul,Bit8u cul,Bit8u rlr,Bit8u clr,Bit8u nlines,Bit8u attr,Bit8u page) {
// Bit8u mode;
Bit16u fill=( (attr << 8) | ' ');
BIOS_NCOLS;BIOS_NROWS;
if(rlr>nrows) rlr=(Bit8u)nrows;
if(clr>ncols) clr=(Bit8u)ncols;
if(rul>rlr) return;
if(cul>clr) return;
VGAMODES * curmode=GetCurrentMode();
switch (curmode->memmodel) {
case CGA:
{
if (nlines==0) {
/* Clear Screen that we can */
PhysPt dest=real_phys(0xb800,0);
for (Bit32u tel=0;tel<0x4000;tel++) {
mem_writew(dest,0x0000);
dest+=2;
}
return;
}
LOG_WARN("INT10:Scroll in CGA Mode");
}
case MTEXT:
case CTEXT:
break;
default:
LOG_ERROR("INT10:Scroll on non supported graphics mode");
}
// Get the current page
if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
/* Get this from active video mode */
Bit16u textseg=0xb800;
PhysPt start=real_phys(textseg,ncols*nrows*2*page);
Bit32u dcol=clr-cul+1;
Bit32u drow=rlr-rul+1;
Bit32u tocopy;
PhysPt dest=start+((rul*ncols)+cul)*2;
PhysPt src;
if (nlines==0) {
nlines=(Bit8u)nrows;
}
if (nlines>=drow) {
tocopy=0;
} else {
tocopy=drow-nlines;
src=start+(((rul+nlines)*ncols)+cul)*2;
}
for (Bit32u y=0;y<drow;y++) {
if (tocopy) {
for (Bit32u x=0;x<dcol;x++) {
mem_writew(dest,mem_readw(src));
src+=2;
dest+=2;
}
src+=(ncols-dcol)*2;
dest+=(ncols-dcol)*2;
tocopy--;
} else {
for(Bit32u x=0;x<dcol;x++) {
mem_writew(dest,fill);
dest+=2;
}
dest+=(ncols-dcol)*2;
}
}
}
void INT10_SetActivePage(Bit8u page) {
Bit16u mem_address;
Bit16u vid_address;
Bit8u cur_col=0 ,cur_row=0 ;
VGAMODES * curmode=GetCurrentMode();
if (curmode==0) return;
if (page>7) return;
switch (curmode->memmodel) {
case MTEXT:
case CTEXT:{
BIOS_NCOLS;BIOS_NROWS;
cur_col=CURSOR_POS_COL(page);
cur_row=CURSOR_POS_ROW(page);
vid_address=SCREEN_IO_START(ncols,nrows,page);
mem_address=SCREEN_MEM_START(ncols,nrows,page);
break;
}
case CGA:{
vid_address=0;
mem_address=0;
break;
}
case PLANAR4:{
mem_address=0;
vid_address=((((curmode->sheight*curmode->swidth)>>3)|0xff)+1)*page;
break;
}
default:
vid_address=0;
mem_address=0;
break;
}
// Calculate the address knowing nbcols nbrows and page num
real_writew(BIOSMEM_SEG,BIOSMEM_CURRENT_START,mem_address);
// CRTC regs 0x0c and 0x0d
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS),0x0c);
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)+1,(vid_address&0xff00)>>8);
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS),0x0d);
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)+1,vid_address&0x00ff);
// And change the BIOS page
real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE,page);
// Display the cursor, now the page is active
INT10_SetCursorPos(cur_row,cur_col,page);
}
void INT10_SetCursorPos(Bit8u row,Bit8u col,Bit8u page) {
Bit16u address;
if(page>7) return;
// Bios cursor pos
real_writeb(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2,col);
real_writeb(BIOSMEM_SEG,BIOSMEM_CURSOR_POS+page*2+1,row);
// Set the hardware cursor
Bit8u current=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
if(page==current) {
// Get the dimensions
BIOS_NCOLS;BIOS_NROWS;
// Calculate the address knowing nbcols nbrows and page num
address=SCREEN_IO_START(ncols,nrows,page)+col+row*ncols;
// CRTC regs 0x0e and 0x0f
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS),0x0e);
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)+1,(address&0xff00)>>8);
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS),0x0f);
IO_Write(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)+1,address&0x00ff);
}
}
void INT10_ReadCharAttr(Bit16u * result,Bit8u page) {
if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
BIOS_NCOLS;BIOS_NROWS;
Bit8u cur_row=CURSOR_POS_ROW(page);
Bit8u cur_col=CURSOR_POS_COL(page);
Bit16u address=SCREEN_MEM_START(ncols,nrows,page)+(cur_col+cur_row*ncols)*2;
*result=real_readw(0xb800,address);
}
INLINE static void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit8u chr,Bit8u attr,bool useattr) {
VGAMODES * curmode=GetCurrentMode();
switch (curmode->type) {
case TEXT:
{
// Compute the address
Bit16u address=SCREEN_MEM_START(curmode->twidth,curmode->theight,page)+(col+row*curmode->twidth)*2;
// Write the char
real_writeb(0xb800,address,chr);
if (useattr) {
real_writeb(0xb800,address+1,attr);
}
}
break;
case GRAPH:
{
/* Split this up for certain graphics modes, since in PLANAR4 especially this is sooo slow */
/* Amount of lines */
Bit8u * fontdata;
Bit16u x,y;
switch (curmode->cheight) {
case 8:
// fontdata=&int10_font_08[chr*8];
fontdata=Real2Host(RealGetVec(0x43))+chr*8;
break;
case 14:
fontdata=&int10_font_14[chr*14];
break;
case 16:
fontdata=&int10_font_16[chr*16];
break;
default:
LOG_ERROR("INT10:Teletype Illegal Font Height");
return;
}
x=8*col;
y=curmode->cheight*row;
//TODO Check for out of bounds
for (Bit8u h=0;h<curmode->cheight;h++) {
Bit8u bitsel=128;
Bit8u bitline=*fontdata++;
Bit16u tx=x;
while (bitsel) {
if (bitline&bitsel) INT10_PutPixel(tx,y,page,attr);
else INT10_PutPixel(tx,y,page,0);
tx++;
bitsel>>=1;
}
y++;
}
}
break;
}
}
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);
Bit8u cur_col=CURSOR_POS_COL(page);
while (count>0) {
WriteChar(cur_col,cur_row,page,chr,attr,showattr);
count--;
}
}
void INT10_TeletypeOutput(Bit8u chr,Bit8u attr,bool showattr, Bit8u page) {
if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
BIOS_NCOLS;BIOS_NROWS;
Bit8u cur_row=CURSOR_POS_ROW(page);
Bit8u cur_col=CURSOR_POS_COL(page);
switch (chr) {
case 7:
//TODO BEEP
break;
case 8:
if(cur_col>0) cur_col--;
break;
case '\r':
cur_col=0;
break;
case '\n':
cur_col=0;
cur_row++;
break;
case '\t':
do {
INT10_TeletypeOutput(' ',attr,showattr,page);
cur_row=CURSOR_POS_ROW(page);
cur_col=CURSOR_POS_COL(page);
} while(cur_col%8==0);
break;
default:
/* Draw the actual Character */
WriteChar(cur_col,cur_row,page,chr,attr,showattr);
cur_col++;
}
if(cur_col==ncols) {
cur_col=0;
cur_row++;
}
// Do we need to scroll ?
if(cur_row==nrows) {
INT10_ScrollUpWindow(0,0,nrows-1,ncols-1,1,0x07,page);
cur_row--;
}
// Set the cursor for the page
INT10_SetCursorPos(cur_row,cur_col,page);
}
void INT10_WriteString(Bit8u row,Bit8u col,Bit8u flag,Bit8u attr,PhysPt string,Bit16u count,Bit8u page) {
if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
BIOS_NCOLS;BIOS_NROWS;
Bit8u cur_row=CURSOR_POS_ROW(page);
Bit8u cur_col=CURSOR_POS_COL(page);
// if row=0xff special case : use current cursor position
if (row==0xff) {
row=cur_row;
col=cur_col;
}
INT10_SetCursorPos(row,col,page);
while (count>0) {
Bit8u chr=mem_readb(string);
string++;
if (flag&2) {
attr=mem_readb(string);
string++;
}
INT10_TeletypeOutput(chr,attr,true,page);
count--;
}
if (flag & 1) {
INT10_SetCursorPos(cur_row,cur_col,page);
}
}

1302
src/ints/int10_memory.cpp Normal file

File diff suppressed because it is too large Load diff

135
src/ints/int10_misc.cpp Normal file
View file

@ -0,0 +1,135 @@
/*
* 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 "mem.h"
#include "inout.h"
#include "int10.h"
#pragma pack(1)
struct Dynamic_Functionality {
RealPt static_table; /* 00h DWORD address of static functionality table */
Bit8u cur_mode; /* 04h BYTE video mode in effect */
Bit16u num_cols; /* 05h WORD number of columns */
Bit16u regen_size; /* 07h WORD length of regen buffer in bytes */
Bit16u regen_start; /* 09h WORD starting address of regen buffer*/
Bit16u cursor_pos[8]; /* 0Bh WORD cursor position for page 0-7 */
Bit16u cursor_type; /* 1Bh WORD cursor type */
Bit8u active_page; /* 1Dh BYTE active display page */
Bit16u crtc_address; /* 1Eh WORD CRTC port address */
Bit8u reg_3x8; /* 20h BYTE current setting of register (3?8) */
Bit8u reg_3x9; /* 21h BYTE current setting of register (3?9) */
Bit8u num_rows; /* 22h BYTE number of rows */
Bit16u bytes_per_char; /* 23h WORD bytes/character */
Bit8u dcc; /* 25h BYTE display combination code of active display */
Bit8u dcc_alternate; /* 26h BYTE DCC of alternate display */
Bit16u num_colors; /* 27h WORD number of colors supported in current mode */
Bit8u num_pages; /* 29h BYTE number of pages supported in current mode */
Bit8u num_scanlines; /* 2Ah BYTE number of scan lines active mode (0,1,2,3) = (200,350,400,480) */
Bit8u pri_char_block; /* 2Bh BYTE primary character block */
Bit8u sec_char_block; /* 2Ch BYTE secondary character block */
Bit8u misc_flags; /* 2Dh BYTE miscellaneous flags
bit 0 all modes on all displays on
1 grey summing on
2 monochrome display attached
3 default palette loading disabled
4 cursor emulation enabled
5 0 = intensity; 1 = blinking
6 PS/2 P70 plasma display (without 9-dot wide font) active
7 reserved
*/
Bit8u reserved1[3]; /* 2Eh 3 BYTEs reserved (00h) */
Bit8u vid_mem; /* 31h BYTE video memory available 00h = 64K, 01h = 128K, 02h = 192K, 03h = 256K */
Bit8u savep_state_flag; /* 32h BYTE save pointer state flags
bit 0 512 character set active
1 dynamic save area present
2 alpha font override active
3 graphics font override active
4 palette override active
5 DCC override active
6 reserved
7 reserved
*/
Bit8u reserved2[13]; /* 33h 13 BYTEs reserved (00h) */
};
#pragma pack()
void INT10_GetFuncStateInformation(Bit16u seg,Bit16u off) {
PhysPt save=Real2Phys(RealMake(seg,off));
/* set static state pointer */
mem_writed(save,int10_romarea.static_state);
/* Copy BIOS Segment areas */
Bit16u i;
/* First area in Bios Seg */
for (i=0;i<30;i++) {
mem_writeb(save+0x4+i,real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE+i));
}
/* Second area */
for (i=0;i<3;i++) {
mem_writeb(save+0x22+i,real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS+i));
}
/* Zero out rest of block */
for (i=0x25;i<0x40;i++) mem_writeb(save+i,0);
/* DCC Index */
mem_writeb(save+0x25,real_readb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX));
VGAMODES * curmode=GetCurrentMode();
if (!curmode) return;
Bit16u col_count=0;
switch (curmode->memmodel) {
case CTEXT:
col_count=2;break;
case MTEXT:
col_count=16;break;
case CGA:
col_count=4;break;
case PLANAR1:
col_count=2;break;
case PLANAR2:
col_count=4;break;
case PLANAR4:
col_count=16;break;
case LINEAR8:
col_count=256;break;
}
/* Colour count */
mem_writew(save+0x27,col_count);
/* Page count */
mem_writeb(save+0x29,curmode->nbpages);
/* scan lines */
switch (curmode->sheight) {
case 200:
mem_writeb(save+0x2a,0);break;
case 350:
mem_writeb(save+0x2a,1);break;
case 400:
mem_writeb(save+0x2a,2);break;
case 480:
mem_writeb(save+0x2a,3);break;
};
//TODO Maybe misc flags
/* Video Memory available */
mem_writeb(save+0x31,3);
}

403
src/ints/int10_modes.cpp Normal file
View file

@ -0,0 +1,403 @@
/*
* 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 "mem.h"
#include "inout.h"
#include "int10.h"
//TODO Maybe also add PCJR Video Modes could be nice :)
//TODO include some credits to bochs/plex86 bios i used for info/tables
VGAMODES vga_modes[MODE_MAX+1]=
{//mode vesa class model pg bits sw sh tw th cw ch sstart slength misc pelm crtc actl gdc sequ dac
{0x00, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02},
{0x01, 0xFFFF, TEXT, CTEXT, 8, 4, 360, 400, 40, 25, 9, 16, 0xB800, 0x0800, 0x67, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02},
{0x02, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02},
{0x03, 0xFFFF, TEXT, CTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB800, 0x1000, 0x67, 0xFF, 0x01, 0x00, 0x00, 0x01, 0x02},
{0x04, 0xFFFF, GRAPH, CGA, 4, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01},
{0x05, 0xFFFF, GRAPH, CGA, 1, 2, 320, 200, 40, 25, 8, 8, 0xB800, 0x0800, 0x63, 0xFF, 0x02, 0x01, 0x01, 0x02, 0x01},
{0x06, 0xFFFF, GRAPH, CGA, 1, 1, 640, 200, 80, 25, 8, 8, 0xB800, 0x1000, 0x63, 0xFF, 0x03, 0x02, 0x02, 0x03, 0x01},
{0x07, 0xFFFF, TEXT, MTEXT, 4, 4, 720, 400, 80, 25, 9, 16, 0xB000, 0x1000, 0x66, 0xFF, 0x04, 0x03, 0x03, 0x01, 0x00},
{0x0D, 0xFFFF, GRAPH, PLANAR4, 8, 4, 320, 200, 40, 25, 8, 8, 0xA000, 0x0000, 0x63, 0xFF, 0x05, 0x04, 0x04, 0x04, 0x01},
{0x0E, 0xFFFF, GRAPH, PLANAR4, 4, 4, 640, 200, 80, 25, 8, 8, 0xA000, 0x0000, 0x63, 0xFF, 0x06, 0x04, 0x04, 0x05, 0x01},
{0x0F, 0xFFFF, GRAPH, PLANAR2, 2, 2, 640, 350, 80, 25, 8, 14, 0xA000, 0x0000, 0xa2, 0xFF, 0x07, 0x05, 0x04, 0x05, 0x00},
{0x10, 0xFFFF, GRAPH, PLANAR4, 2, 4, 640, 350, 80, 25, 8, 14, 0xA000, 0x0000, 0xa3, 0xFF, 0x07, 0x06, 0x04, 0x05, 0x02},
{0x11, 0xFFFF, GRAPH, PLANAR1, 1, 1, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x07, 0x04, 0x05, 0x02},
{0x12, 0xFFFF, GRAPH, PLANAR4, 1, 4, 640, 480, 80, 30, 8, 16, 0xA000, 0x0000, 0xe3, 0xFF, 0x08, 0x06, 0x04, 0x05, 0x02},
{0x13, 0xFFFF, GRAPH, LINEAR8, 1, 8, 320, 200, 40, 25, 8, 8, 0xA000, 0x0000, 0x63, 0xFF, 0x09, 0x08, 0x05, 0x06, 0x03}
};
/* CRTC */
#define CRTC_MAX_REG 0x18
#define CRTC_MAX_MODEL 0x09
static Bit8u crtc_access[CRTC_MAX_REG+1]=
{ /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
static Bit8u crtc_regs[CRTC_MAX_MODEL+1][CRTC_MAX_REG+1]=
{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 */
/* 00 */ 0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,0xff,
/* 01 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff,
/* 02 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,0xff,
/* 03 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,0xff,
/* 04 */ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,0xff,
/* 05 */ 0x2d,0x27,0x28,0x90,0x2b,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,0xff,
/* 06 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,0xff,
/* 07 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x85,0x5d,0x28,0x0f,0x63,0xba,0xe3,0xff,
/* 08 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x8c,0xdf,0x28,0x00,0xe7,0x04,0xe3,0xff,
/* 09 */ 0x5f,0x4f,0x50,0x82,0x54,0x80,0xbf,0x1f,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,0xff
};
/* Attribute Controler 0x3c0 */
#define ACTL_MAX_REG 0x14
#define ACTL_MAX_MODEL 0x08
static Bit8u actl_access[ACTL_MAX_REG+1]=
{/* 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
static Bit8u actl_regs[ACTL_MAX_MODEL+1][ACTL_MAX_REG+1]=
{/* Model 00 01 02 03 04 05 06 07 08 09 0A 0B OC OD OE OF 10 11 12 13 14 */
/* 00 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x0c,0x00,0x0f,0x08,0x00,
/* 01 */ 0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x03,0x00,0x00,
/* 02 */ 0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x01,0x00,0x01,0x00,0x00,
/* 03 */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0e,0x00,0x0f,0x08,0x00,
/* 04 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x01,0x00,0x0f,0x00,0x00,
/* 05 */ 0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x0b,0x00,0x05,0x00,0x00,
/* 06 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x01,0x00,0x0f,0x00,0x00,
/* 07 */ 0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x01,0x00,0x01,0x00,0x00,
/* 08 */ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x41,0x00,0x0f,0x00,0x00
};
/* Sequencer 0x3c4 */
#define SEQU_MAX_REG 0x04
#define SEQU_MAX_MODEL 0x06
static Bit8u sequ_access[SEQU_MAX_REG+1]=
{ /* 00 01 02 03 04 */
0x00,0x00,0x00,0x00,0x00
};
static Bit8u sequ_regs[SEQU_MAX_MODEL+1][SEQU_MAX_REG+1]=
{/* Model 00 01 02 03 04 */
/* 00 */ 0x03,0x08,0x03,0x00,0x02,
/* 01 */ 0x03,0x00,0x03,0x00,0x02,
/* 02 */ 0x03,0x09,0x03,0x00,0x02,
/* 03 */ 0x03,0x01,0x01,0x00,0x06,
/* 04 */ 0x03,0x09,0x0f,0x00,0x06,
/* 05 */ 0x03,0x01,0x0f,0x00,0x06,
/* 06 */ 0x03,0x01,0x0f,0x00,0x0e
};
/* Graphic ctl 0x3ce */
#define GRDC_MAX_REG 0x08
#define GRDC_MAX_MODEL 0x05
static Bit8u grdc_access[GRDC_MAX_REG+1]=
{ /* 00 01 02 03 04 05 06 07 08 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
static Bit8u grdc_regs[GRDC_MAX_MODEL+1][GRDC_MAX_REG+1]=
{/* Model 00 01 02 03 04 05 06 07 08 */
/* 00 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x0f,0xff,
/* 01 */ 0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x0f,0xff,
/* 02 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x0f,0xff,
/* 03 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x0f,0xff,
/* 04 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,0xff,
/* 05 */ 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,0xff
};
/* Default Palette */
#define DAC_MAX_MODEL 3
static Bit8u dac_regs[DAC_MAX_MODEL+1]=
{0x3f,0x3f,0x3f,0xff};
/* Mono */
static Bit8u palette0[63+1][3]=
{
0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f
};
static Bit8u palette1[63+1][3]=
{
0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
};
static Bit8u palette2[63+1][3]=
{
0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f, 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a, 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a,
0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f, 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f,
0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a, 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a,
0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f, 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f,
0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a, 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a,
0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
};
static Bit8u palette3[256][3]=
{
0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a, 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f, 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b, 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18,
0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28, 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f,
0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f, 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10,
0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00, 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00,
0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f, 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f,
0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f, 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27,
0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f, 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f,
0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37, 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f,
0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f, 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31,
0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d, 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d,
0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a, 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f,
0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c, 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07,
0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00, 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00,
0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15, 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c,
0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c, 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11,
0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e, 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e,
0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18, 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c,
0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c, 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16,
0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14, 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14,
0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a, 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c,
0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10, 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04,
0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00, 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00,
0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c, 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10,
0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10, 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a,
0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08, 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08,
0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e, 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10,
0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10, 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c,
0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b, 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b,
0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f, 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10,
0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00
};
static Bit8u static_functionality[0x10]=
{
/* 0 */ 0xff, // All modes supported #1
/* 1 */ 0xff, // All modes supported #2
/* 2 */ 0x0f, // All modes supported #3
/* 3 */ 0x00, 0x00, 0x00, 0x00, // reserved
/* 7 */ 0x07, // 200, 350, 400 scan lines
/* 8 */ 0xFF, // FIXME i don't know what this is
/* 9 */ 0xFF, // FIXME i don't know what this is
/* a */ 0xe3, // Change to add new functions
/* b */ 0x0c, // Change to add new functions
/* c */ 0x00, // reserved
/* d */ 0x00, // reserved
/* e */ 0x00, // Change to add new functions
/* f */ 0x00 // reserved
};
static Bit8u FindVideoMode(Bit8u mode) {
Bit8u line=0xff;
for(Bit8u i=0;i<=MODE_MAX;i++) {
if(vga_modes[i].svgamode==mode) {
line=i;
break;
}
}
return line;
}
VGAMODES * GetCurrentMode(void) {
Bit8u ret=FindVideoMode(real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)&127);
if (ret==0xff) return 0;
return &vga_modes[ret];
}
void INT10_SetVideoMode(Bit8u mode) {
bool clearmem=(mode & 128)==0;
Bit8u *palette;
Bit16u i,twidth,theight,cheight;
Bit8u modeset_ctl,video_ctl,vga_switches;
Bit16u crtc_addr;
Bit8u line;
mode&=mode & 127;
line=FindVideoMode(mode);
if (line==0xff) {
LOG_ERROR("INT10:Trying to set non supported video mode %X",mode);
return;
}
twidth=vga_modes[line].twidth;
theight=vga_modes[line].theight;
cheight=vga_modes[line].cheight;
// Read the bios vga control
video_ctl=real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL);
// Read the bios vga switches
vga_switches=real_readb(BIOSMEM_SEG,BIOSMEM_SWITCHES);
// Read the bios mode set control
modeset_ctl=real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL);
if((modeset_ctl&0x08)==0) {
// Set the PEL mask
IO_Write(VGAREG_PEL_MASK,vga_modes[line].pelmask);
// Set the whole dac always, from 0
IO_Write(VGAREG_DAC_WRITE_ADDRESS,0x00);
// From which palette
switch(vga_modes[line].dacmodel) {
case 0:
palette=(Bit8u*)&palette0;
break;
case 1:
palette=(Bit8u*)&palette1;
break;
case 2:
palette=(Bit8u*)&palette2;
break;
case 3:
palette=(Bit8u*)&palette3;
break;
default:
palette=(Bit8u*)&palette0;/*for gcc*/
E_Exit("INT10: palette error in setvidmode");
break;
}
// Set the actual palette
for (i=0;i<256;i++) {
if (i<=dac_regs[vga_modes[line].dacmodel]) {
IO_Write(VGAREG_DAC_DATA,palette[(i*3)+0]);
IO_Write(VGAREG_DAC_DATA,palette[(i*3)+1]);
IO_Write(VGAREG_DAC_DATA,palette[(i*3)+2]);
} else {
IO_Write(VGAREG_DAC_DATA,0);
IO_Write(VGAREG_DAC_DATA,0);
IO_Write(VGAREG_DAC_DATA,0);
}
}
}
/* Reset Attribute ctl into address mode just to be safe */
IO_Read(VGAREG_ACTL_RESET);
// Set Attribute Ctl
for(i=0;i<=ACTL_MAX_REG;i++) {
IO_Write(VGAREG_ACTL_ADDRESS,(Bit8u)i);
IO_Write(VGAREG_ACTL_WRITE_DATA,actl_regs[vga_modes[line].actlmodel][i]);
}
// Set Sequencer Ctl
for(i=0;i<=SEQU_MAX_REG;i++) {
IO_Write(VGAREG_SEQU_ADDRESS,(Bit8u)i);
IO_Write(VGAREG_SEQU_DATA,sequ_regs[vga_modes[line].sequmodel][i]);
}
// Set Grafx Ctl
for(i=0;i<=GRDC_MAX_REG;i++) {
IO_Write(VGAREG_GRDC_ADDRESS,(Bit8u)i);
IO_Write(VGAREG_GRDC_DATA,grdc_regs[vga_modes[line].grdcmodel][i]);
}
// Set CRTC address VGA or MDA
crtc_addr=vga_modes[line].memmodel==MTEXT?VGAREG_MDA_CRTC_ADDRESS:VGAREG_VGA_CRTC_ADDRESS;
// Set CRTC regs
for(i=0;i<=CRTC_MAX_REG;i++) {
IO_Write(crtc_addr,(Bit8u)i);
IO_Write(crtc_addr+1,crtc_regs[vga_modes[line].crtcmodel][i]);
}
// Set the misc register
IO_Write(VGAREG_WRITE_MISC_OUTPUT,vga_modes[line].miscreg);
// Enable video
IO_Write(VGAREG_ACTL_ADDRESS,0x20);
IO_Read(VGAREG_ACTL_RESET);
Bit32u tel;
if(clearmem) {
if(vga_modes[line].type==TEXT) {
PhysPt dest=real_phys(vga_modes[line].sstart,0);
for (tel=0;tel<0x4000;tel++) {
mem_writew(dest,0x0720);
dest+=2;
}
} else {
PhysPt dest=real_phys(0xb800,0);
for (tel=0;tel<0x4000;tel++) {
mem_writew(dest,0x0000);
dest+=2;
}
dest=real_phys(0xa000,0);
for (tel=0;tel<0x8000;tel++) {
mem_writew(dest,0x0000);
dest+=2;
}
// FIXME should handle gfx mode
}
}
// Set the BIOS mem
real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,mode|((!clearmem) << 7));
real_writew(BIOSMEM_SEG,BIOSMEM_NB_COLS,twidth);
real_writew(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,vga_modes[line].slength);
real_writew(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,crtc_addr);
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_MODESET_CTL,real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f);
// FIXME We nearly have the good tables. to be reworked
real_writeb(BIOSMEM_SEG,BIOSMEM_DCC_INDEX,0x08); // 8 is VGA should be ok for now
real_writew(BIOSMEM_SEG,BIOSMEM_VS_POINTER,0x00);
real_writew(BIOSMEM_SEG,BIOSMEM_VS_POINTER+2,0x00);
// FIXME
real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x00); // Unavailable on vanilla vga, but...
real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x00); // Unavailable on vanilla vga, but...
// Set cursor shape
if(vga_modes[line].type==TEXT) {
//TODO cursor shape biosfn_set_cursor_shape(0x06,0x07);
}
// Set cursor pos for page 0..7
for(i=0;i<8;i++) INT10_SetCursorPos(0,0,(Bit8u)i);
// Set active page 0
INT10_SetActivePage(0);
/* Set some interrupt vectors */
//TODO set 0x43 to the correct font height font
RealSetVec(0x43,int10_romarea.font_8_first);
RealSetVec(0x1F,int10_romarea.font_8_second);
};

126
src/ints/int10_pal.cpp Normal file
View file

@ -0,0 +1,126 @@
/*
* 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 "mem.h"
#include "inout.h"
#include "int10.h"
#define ACTL_MAX_REG 0x14
void INT10_SetSinglePaletteRegister(Bit8u reg,Bit8u val) {
if(reg<=ACTL_MAX_REG) {
IO_Read(VGAREG_ACTL_RESET);
IO_Write(VGAREG_ACTL_ADDRESS,reg);
IO_Write(VGAREG_ACTL_WRITE_DATA,val);
}
}
void INT10_SetOverscanBorderColor(Bit8u val) {
IO_Read(VGAREG_ACTL_RESET);
IO_Write(VGAREG_ACTL_ADDRESS,0x11);
IO_Write(VGAREG_ACTL_WRITE_DATA,val);
}
void INT10_SetAllPaletteRegisters(PhysPt data) {
IO_Read(VGAREG_ACTL_RESET);
// First the colors
for(Bit8u i=0;i<0x10;i++) {
IO_Write(VGAREG_ACTL_ADDRESS,i);
IO_Write(VGAREG_ACTL_WRITE_DATA,mem_readb(data));
data++;
}
// Then the border
IO_Write(VGAREG_ACTL_ADDRESS,0x11);
IO_Write(VGAREG_ACTL_WRITE_DATA,mem_readb(data));
}
void INT10_ToggleBlinkingBit(Bit8u state) {
Bit8u value;
state&=0x01;
IO_Read(VGAREG_ACTL_RESET);
IO_Write(VGAREG_ACTL_ADDRESS,0x10);
value=IO_Read(VGAREG_ACTL_READ_DATA);
value&=0xf7;
value|=state<<3;
IO_Read(VGAREG_ACTL_RESET);
IO_Write(VGAREG_ACTL_ADDRESS,0x10);
IO_Write(VGAREG_ACTL_WRITE_DATA,value);
}
void INT10_GetSinglePaletteRegister(Bit8u reg,Bit8u * val) {
if(reg<=ACTL_MAX_REG) {
IO_Read(VGAREG_ACTL_RESET);
IO_Write(VGAREG_ACTL_ADDRESS,reg);
*val=IO_Read(VGAREG_ACTL_READ_DATA);
}
}
void INT10_GetOverscanBorderColor(Bit8u * val) {
IO_Read(VGAREG_ACTL_RESET);
IO_Write(VGAREG_ACTL_ADDRESS,0x11);
*val=IO_Read(VGAREG_ACTL_READ_DATA);
}
void INT10_GetAllPaletteRegisters(PhysPt data) {
IO_Read(VGAREG_ACTL_RESET);
// First the colors
for(Bit8u i=0;i<0x10;i++) {
IO_Write(VGAREG_ACTL_ADDRESS,i);
mem_writeb(data,IO_Read(VGAREG_ACTL_READ_DATA));
data++;
}
// Then the border
IO_Write(VGAREG_ACTL_ADDRESS,0x11);
mem_writeb(data,IO_Read(VGAREG_ACTL_READ_DATA));
}
void INT10_SetSingleDacRegister(Bit8u index,Bit8u red,Bit8u green,Bit8u blue) {
IO_Write(VGAREG_DAC_WRITE_ADDRESS,(Bit8u)index);
IO_Write(VGAREG_DAC_DATA,red);
IO_Write(VGAREG_DAC_DATA,green);
IO_Write(VGAREG_DAC_DATA,blue);
}
void INT10_GetSingleDacRegister(Bit8u index,Bit8u * red,Bit8u * green,Bit8u * blue) {
IO_Write(VGAREG_DAC_READ_ADDRESS,index);
*red=IO_Read(VGAREG_DAC_DATA);
*green=IO_Read(VGAREG_DAC_DATA);
*blue=IO_Read(VGAREG_DAC_DATA);
}
void INT10_SetDACBlock(Bit16u index,Bit16u count,PhysPt data) {
IO_Write(VGAREG_DAC_WRITE_ADDRESS,(Bit8u)index);
for (;count>0;count--) {
IO_Write(VGAREG_DAC_DATA,mem_readb(data++));
IO_Write(VGAREG_DAC_DATA,mem_readb(data++));
IO_Write(VGAREG_DAC_DATA,mem_readb(data++));
}
}
void INT10_GetDACBlock(Bit16u index,Bit16u count,PhysPt data) {
IO_Write(VGAREG_DAC_WRITE_ADDRESS,(Bit8u)index);
for (;count>0;count--) {
mem_writeb(data++,IO_Read(VGAREG_DAC_DATA));
mem_writeb(data++,IO_Read(VGAREG_DAC_DATA));
mem_writeb(data++,IO_Read(VGAREG_DAC_DATA));
}
};

View file

@ -0,0 +1,91 @@
/*
* 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 "mem.h"
#include "inout.h"
#include "int10.h"
union VGA_Memory {
Bit8u linear[64*1024*4];
Bit8u paged[64*1024][4];
};
extern VGA_Memory vga_mem;
static Bit8u cga_masks[4]={~192,~48,~12,~3};
void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) {
VGAMODES * curmode=GetCurrentMode();
switch (curmode->memmodel) {
case CGA:
{
Bit16u off=(y>>1)*80+(x>>2);
if (y&1) off+=8*1024;
Bit8u old=real_readb(0xb800,off);
old=old&cga_masks[x&3]|((color&3) << (2*(3-(x&3))));
real_writeb(0xb800,off,old);
}
break;
case PLANAR4:
{
/* Set the correct bitmask for the pixel position */
IO_Write(0x3ce,0x8);Bit8u mask=128>>(x&7);IO_Write(0x3cf,mask);
/* Set the color to set/reset register */
IO_Write(0x3ce,0x0);IO_Write(0x3cf,color);
/* Enable all the set/resets */
IO_Write(0x3ce,0x1);IO_Write(0x3cf,0xf);
//Perhaps also set mode 1
/* Calculate where the pixel is in video memory */
Bit16u base_address=((((curmode->sheight*curmode->swidth)>>3)|0xff)+1)*page;
PhysPt off=0xa0000+base_address+((y*curmode->swidth+x)>>3);
/* Bitmask and set/reset should do the rest */
mem_readb(off);
mem_writeb(off,0xff);
break;
}
case CTEXT:
case MTEXT:
case PLANAR1:
case PLANAR2:
case LINEAR8:
default:
LOG_WARN("INT10:PutPixel Unhanled memory model");
break;
}
}
void INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color) {
VGAMODES * curmode=GetCurrentMode();
switch (curmode->memmodel) {
case CGA:
{
Bit16u off=(y>>1)*80+(x>>2);
if (y&1) off+=8*1024;
Bit8u val=real_readb(0xb800,off);
*color=val<<((x&3)*2);
}
break;
default:
LOG_WARN("INT10:GetPixel Unhanled memory model");
break;
}
}

294
src/ints/mouse.cpp Normal file
View file

@ -0,0 +1,294 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "callback.h"
#include "mem.h"
#include "regs.h"
#include "mouse.h"
#include "pic.h"
#include "inout.h"
static Bitu call_int33,call_int74;
struct button_event {
Bit16u type;
Bit16u buttons;
};
#define QUEUE_SIZE 32
//TODO Maybe use :)
#define MOUSE_IRQ 12
#define POS_X (Bit16s)(mouse.x*mouse.range_x)
#define POS_Y (Bit16s)(mouse.y*mouse.range_y)
static struct {
Bit16u buttons;
Bit16u times_pressed[3];
Bit16u times_released[3];
Bit16u last_released_x[3];
Bit16u last_released_y[3];
Bit16u last_pressed_x[3];
Bit16u last_pressed_y[3];
Bit16s shown;
float add_x,add_y;
Bit16u min_x,max_x,min_y,max_y;
float range_x,range_y;
float mickey_x,mickey_y;
float x,y;
button_event event_queue[QUEUE_SIZE];
Bit32u events;
Bit16u sub_seg,sub_ofs;
Bit16u sub_mask;
} mouse;
#define X_MICKEY 500
#define Y_MICKEY 500
#define MOUSE_MOVED 1
#define MOUSE_LEFT_PRESSED 2
#define MOUSE_LEFT_RELEASED 4
#define MOUSE_RIGHT_PRESSED 8
#define MOUSE_RIGHT_RELEASED 16
#define MOUSE_MIDDLE_PRESSED 32
#define MOUSE_MIDDLE_RELEASED 64
inline void Mouse_AddEvent(Bit16u type) {
if (mouse.events<QUEUE_SIZE) {
mouse.event_queue[mouse.events].type=type;
mouse.event_queue[mouse.events].buttons=mouse.buttons;
mouse.events++;
}
PIC_ActivateIRQ(12);
}
void Mouse_CursorMoved(float x,float y) {
mouse.mickey_x+=x;
mouse.mickey_y+=y;
mouse.x+=x;
if (mouse.x>1) mouse.x=1;
if (mouse.x<0) mouse.x=0;
mouse.y+=y;
if (mouse.y>1) mouse.y=1;
if (mouse.y<0) mouse.y=0;
Mouse_AddEvent(MOUSE_MOVED);
}
void Mouse_CursorSet(float x,float y) {
mouse.x=x;
mouse.y=y;
}
void Mouse_ButtonPressed(Bit8u button) {
switch (button) {
case 0:
mouse.buttons|=1;
Mouse_AddEvent(MOUSE_LEFT_PRESSED);
break;
case 1:
mouse.buttons|=2;
Mouse_AddEvent(MOUSE_RIGHT_PRESSED);
break;
case 2:
mouse.buttons|=4;
Mouse_AddEvent(MOUSE_MIDDLE_PRESSED);
break;
}
mouse.times_pressed[button]++;
mouse.last_pressed_x[button]=POS_X;
mouse.last_pressed_y[button]=POS_Y;
}
void Mouse_ButtonReleased(Bit8u button) {
switch (button) {
case 0:
mouse.buttons&=~1;
Mouse_AddEvent(MOUSE_LEFT_RELEASED);
break;
case 1:
mouse.buttons&=~2;
Mouse_AddEvent(MOUSE_RIGHT_RELEASED);
break;
case 2:
mouse.buttons&=~4;
Mouse_AddEvent(MOUSE_MIDDLE_RELEASED);
break;
}
mouse.times_released[button]++;
mouse.last_released_x[button]=POS_X;
mouse.last_released_y[button]=POS_Y;
}
static void mouse_reset(void) {
real_writed(0,(0x33<<2),CALLBACK_RealPointer(call_int33));
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.range_x=639;
mouse.range_y=199;
mouse.x=320;
mouse.y=100;
mouse.events=0;
mouse.mickey_x=0;
mouse.mickey_y=0;
mouse.sub_mask=0;
mouse.sub_seg=0;
mouse.sub_ofs=0;
};
static Bitu INT33_Handler(void) {
switch (reg_ax) {
case 0x00: /* Reset Driver and Read Status */
reg_ax=0xffff;
reg_bx=0;
mouse_reset();
break;
case 0x01: /* Show Mouse */
mouse.shown++;
if (mouse.shown>0) mouse.shown=0;
break;
case 0x02: /* Hide Mouse */
mouse.shown--;
break;
case 0x03: /* Return position and Button Status */
reg_bx=mouse.buttons;
reg_cx=POS_X;
reg_dx=POS_Y;
break;
case 0x04: /* Position Mouse */
mouse.x=((float)reg_cx)/mouse.range_x;
mouse.y=((float)reg_dx)/mouse.range_y;
break;
case 0x05: /* Return Button Press Data */
{
Bit16u but=reg_bx;
reg_ax=mouse.buttons;
reg_cx=mouse.last_pressed_x[but];
mouse.last_pressed_x[but]=0;
reg_dx=mouse.last_pressed_y[but];
mouse.last_pressed_y[but]=0;
reg_bx=mouse.times_pressed[but];
mouse.times_pressed[but]=0;
break;
}
case 0x07: /* Define horizontal cursor range */
mouse.min_x=reg_cx;
mouse.max_x=reg_dx;
mouse.range_x=mouse.max_x-mouse.min_x;
//TODO Check for range start 0
break;
case 0x08: /* Define vertical cursor range */
mouse.min_y=reg_cx;
mouse.max_y=reg_dx;
mouse.range_y=mouse.max_y-mouse.min_y;
break;
case 0x09: /* Define GFX Cursor */
LOG_WARN("MOUSE:Define gfx cursor not supported");
break;
case 0x0a: /* Define Text Cursor */
/* Don't see much need for supporting this */
break;
case 0x0c: /* Define interrupt subroutine parameters */
mouse.sub_mask=reg_cx;
mouse.sub_seg=Segs[es].value;
mouse.sub_ofs=reg_dx;
break;
case 0x0f: /* Define mickey/pixel rate */
//TODO Maybe dunno for sure might be possible */
break;
case 0x0B: /* Read Motion Data */
reg_cx=(Bit16s)(mouse.mickey_x*X_MICKEY);
reg_dx=(Bit16s)(mouse.mickey_y*Y_MICKEY);
mouse.mickey_x=0;
mouse.mickey_y=0;
break;
case 0x1c: /* Set interrupt rate */
/* Can't really set a rate this is host determined */
break;
case 0x21: /* Software Reset */
//TODO reset internal mouse software variables likes mickeys
reg_ax=0xffff;
reg_bx=2;
break;
case 0x24: /* Get Software version and mouse type */
reg_bx=0x805; //Version 8.05 woohoo
reg_ch=0xff; /* Unkown type */
reg_cl=0; /* Hmm ps2 irq dunno */
break;
default:
LOG_ERROR("Mouse Function %2X",reg_ax);
};
return CBRET_NONE;
};
static Bitu INT74_Handler(void) {
if (mouse.events>0) {
mouse.events--;
/* Check for an active Interrupt Handler that will get called */
if (mouse.sub_mask & mouse.event_queue[mouse.events].type) {
/* Save lot's of registers */
Bit16u oldax,oldbx,oldcx,olddx,oldsi,olddi;
oldax=reg_ax;oldbx=reg_bx;oldcx=reg_cx;olddx=reg_dx;oldsi=reg_si;olddi=reg_di;
reg_ax=mouse.event_queue[mouse.events].type;
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) {
mouse.mickey_x=0;
mouse.mickey_y=0;
}
CALLBACK_RunRealFar(mouse.sub_seg,mouse.sub_ofs);
reg_ax=oldax;reg_bx=oldbx;reg_cx=oldcx;reg_dx=olddx;reg_si=oldsi;reg_di=olddi;
}
}
IO_Write(0xa0,0x20);
/* Check for more Events if so reactivate IRQ */
if (mouse.events) {
PIC_ActivateIRQ(12);
}
return CBRET_NONE;
};
void MOUSE_Init(void) {
call_int33=CALLBACK_Allocate();
CALLBACK_Setup(call_int33,&INT33_Handler,CB_IRET);
real_writed(0,(0x33<<2),CALLBACK_RealPointer(call_int33));
call_int74=CALLBACK_Allocate();
CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRET);
real_writed(0,(0x74<<2),CALLBACK_RealPointer(call_int74));
memset((void *)&mouse,0,sizeof(mouse));
mouse_reset();
};

185
src/ints/xms.cpp Normal file
View file

@ -0,0 +1,185 @@
/*
* 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 <string.h>
#include "dosbox.h"
#include "callback.h"
#include "mem.h"
#include "regs.h"
#include "dos_system.h"
#define XMS_VERSION 0x0300 /* version 3.00 */
#define XMS_DRIVER_VERSION 0x0301 /* my driver version 3.01 */
#define XMS_GET_VERSION 0x00
#define XMS_ALLOCATE_HIGH_MEMORY 0x01
#define XMS_FREE_HIGH_MEMORY 0x02
#define XMS_GLOBAL_ENABLE_A20 0x03
#define XMS_GLOBAL_DISABLE_A20 0x04
#define XMS_LOCAL_ENABLE_A20 0x05
#define XMS_LOCAL_DISABLE_A20 0x06
#define XMS_QUERY_A20 0x07
#define XMS_QUERY_FREE_EXTENDED_MEMORY 0x08
#define XMS_ALLOCATE_EXTENDED_MEMORY 0x09
#define XMS_FREE_EXTENDED_MEMORY 0x0a
#define XMS_MOVE_EXTENDED_MEMORY_BLOCK 0x0b
#define XMS_LOCK_EXTENDED_MEMORY_BLOCK 0x0c
#define XMS_UNLOCK_EXTENDED_MEMORY_BLOCK 0x0d
#define XMS_GET_EMB_HANDLE_INFORMATION 0x0e
#define XMS_RESIZE_EXTENDED_MEMORY_BLOCK 0x0f
#define XMS_ALLOCATE_UMB 0x10
#define XMS_DEALLOCATE_UMB 0x11
#define HIGH_MEMORY_IN_USE 0x92
#define HIGH_MEMORY_NOT_ALLOCATED 0x93
#define XMS_OUT_OF_SPACE 0xa0
#define XMS_INVALID_HANDLE 0xa2
static Bit16u call_xms;
static RealPt xms_callback;
static bool multiplex_xms(void) {
switch (reg_ax) {
case 0x4300: /* XMS installed check */
reg_al=0x80;
return true;
case 0x4310: /* XMS handler seg:offset */
SetSegment_16(es,RealSeg(xms_callback));
reg_bx=RealOff(xms_callback);
return true;
}
return false;
};
#if defined (_MSC_VER)
#pragma pack(1)
#endif
struct XMS_MemMove{
Bit32u length;
Bit16u src_handle;
RealPt src_offset;
Bit16u dest_handle;
RealPt dest_offset;
}
#if defined (_MSC_VER)
;
#pragma pack()
#else
__attribute__ ((packed));
#endif
static void XMS_MoveBlock(PhysPt block,Bit8u * result) {
XMS_MemMove moveblock;
//TODO Will not work on other endian, probably base it on a class would be nice
MEM_BlockRead(block,(Bit8u *)&moveblock,sizeof(XMS_MemMove));
HostPt src;
PhysPt dest;
if (moveblock.src_handle) {
src=memory+EMM_Handles[moveblock.src_handle].phys_base+moveblock.src_offset;
} else {
src=Real2Host(moveblock.src_offset);
}
if (moveblock.dest_handle) {
dest=EMM_Handles[moveblock.dest_handle].phys_base+moveblock.dest_offset;
} else {
dest=Real2Phys(moveblock.dest_offset);
}
//memcpy((void *)dest,(void *)src,moveblock.length);
MEM_BlockWrite(dest,src,moveblock.length);
*result=0;
};
Bitu XMS_Handler(void) {
switch (reg_ah) {
case XMS_GET_VERSION: /* 00 */
reg_ax=XMS_VERSION;
reg_bx=XMS_DRIVER_VERSION;
reg_dx=0; //TODO HMA Maybe
break;
case XMS_ALLOCATE_HIGH_MEMORY: /* 01 */
case XMS_FREE_HIGH_MEMORY: /* 02 */
case XMS_GLOBAL_ENABLE_A20: /* 03 */
case XMS_GLOBAL_DISABLE_A20: /* 04 */
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;
case XMS_QUERY_FREE_EXTENDED_MEMORY: /* 08 */
EMM_GetFree(&reg_ax,&reg_dx);
reg_ax<<=2;reg_dx<<=2;
reg_bl=0;
break;
case XMS_ALLOCATE_EXTENDED_MEMORY: /* 09 */
EMM_Allocate(PAGES(reg_dx*1024),&reg_dx);
if (reg_dx) reg_ax=1;
else { reg_ax=0;reg_bl=0xb0; }
break;
case XMS_FREE_EXTENDED_MEMORY: /* 0a */
EMM_Free(reg_dx);
reg_ax=1;
break;
case XMS_MOVE_EXTENDED_MEMORY_BLOCK: /* 0b */
XMS_MoveBlock(real_phys(Segs[ds].value,reg_si),&reg_bl);
if (reg_bl) reg_ax=0;
else reg_ax=1;
break;
case XMS_LOCK_EXTENDED_MEMORY_BLOCK: /* 0c */
if ((!EMM_Handles[reg_dx].active) || (EMM_Handles[reg_dx].free)) {
reg_ax=0;
reg_bl=0xa2; /* Invalid block */
break;
}
reg_ax=1;
reg_bx=(Bit16u)((EMM_Handles[reg_dx].phys_base) & 0xffff);
reg_dx=(Bit16u)((EMM_Handles[reg_dx].phys_base >> 16) & 0xffff);
break;
case XMS_UNLOCK_EXTENDED_MEMORY_BLOCK: /* 0d */
reg_ax=1;
break;
case XMS_GET_EMB_HANDLE_INFORMATION: /* 0e */
LOG_WARN("XMS:Unhandled call %2X",reg_ah);break;
case XMS_RESIZE_EXTENDED_MEMORY_BLOCK: /* 0f */
LOG_WARN("XMS:Unhandled call %2X",reg_ah);break;
case XMS_ALLOCATE_UMB: /* 10 */
reg_ax=0;
reg_bl=0xb1; //No UMB Available
reg_dx=0;
break;
case XMS_DEALLOCATE_UMB: /* 11 */
default:
LOG_WARN("XMS:Unhandled call %2X",reg_ah);break;
}
return CBRET_NONE;
}
void XMS_Init(void) {
DOS_AddMultiplexHandler(multiplex_xms);
call_xms=CALLBACK_Allocate();
CALLBACK_Setup(call_xms,&XMS_Handler,CB_RETF);
xms_callback=CALLBACK_RealPointer(call_xms);
}

4
src/misc/Makefile.am Normal file
View file

@ -0,0 +1,4 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libmisc.a
libmisc_a_SOURCES = plugins.cpp programs.cpp messages.cpp support.cpp setup.cpp

107
src/misc/messages.cpp Normal file
View file

@ -0,0 +1,107 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dosbox.h"
#include "cross.h"
#include "support.h"
#include "setup.h"
#define LINE_IN_MAXLEN 1024
struct MessageBlock
{
char * name;
char * string;
MessageBlock * next;
};
static MessageBlock * first_message;
static void LoadMessageFile(char * fname) {
FILE * mfile=fopen(fname,"rb");
/* This should never happen and since other modules depend on this use a normal printf */
if (!mfile) {
E_Exit("MSG:Can't load messages",fname);
}
char linein[LINE_IN_MAXLEN];
char name[LINE_IN_MAXLEN];
char string[LINE_IN_MAXLEN*10];
/* Start out with empty strings */
name[0]=0;string[0]=0;
while(fgets(linein, LINE_IN_MAXLEN, mfile)!=0) {
/* Parse the read line */
/* First remove characters 10 and 13 from the line */
char * parser=linein;
char * writer=linein;
while (*parser) {
if (*parser!=10 && *parser!=13) {
*writer++=*parser;
}
*parser++;
}
*writer=0;
/* New string name */
if (linein[0]==':') {
string[0]=0;
strcpy(name,linein+1);
/* End of string marker */
} else if (linein[0]=='.') {
/* Save the string internally */
size_t total=sizeof(MessageBlock)+strlen(name)+1+strlen(string)+1;
MessageBlock * newblock=(MessageBlock *)malloc(total);
newblock->name=((char *)newblock)+sizeof(MessageBlock);
newblock->string=newblock->name+strlen(name)+1;
strcpy(newblock->name,name);
strcpy(newblock->string,string);
newblock->next=first_message;
first_message=newblock;
} else {
/* Normal string to be added */
strcat(string,linein);
strcat(string,"\n");
}
}
fclose(mfile);
}
char * MSG_Get(char * msg) {
MessageBlock * index=first_message;
while (index) {
if (!strcmp(msg,index->name)) return index->string;
index=index->next;
}
return "Message not found";
}
void MSG_Init(void) {
/* Load the messages from "dosbox.lang file" */
first_message=0;
char filein[CROSS_LEN];
strcpy(filein,dosbox_basedir);
strcat(filein,"dosbox.lang");
LoadMessageFile(filein);
}

159
src/misc/plugins.cpp Normal file
View file

@ -0,0 +1,159 @@
/*
* 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 <string.h>
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#endif
#include "dosbox.h"
#include "regs.h"
#include "mem.h"
#include "inout.h"
#include "pic.h"
#include "modules.h"
#include "programs.h"
#include "timer.h"
#include "dma.h"
#include "mixer.h"
struct PLUGIN_Function {
char * name;
void * function;
};
struct PLUGIN_Module {
#ifdef WIN32
HINSTANCE handle;
#endif
PLUGIN_Module * next;
};
static PLUGIN_Function functions[]={
"IO_RegisterReadHandler", (void *)IO_RegisterReadHandler,
"IO_RegisterWriteHandler", (void *)IO_RegisterWriteHandler,
"IO_FreeReadHandler", (void *)IO_FreeReadHandler,
"IO_FreeWriteHandler", (void *)IO_FreeWriteHandler,
"IRQ_RegisterEOIHandler", (void *)PIC_RegisterIRQ,
"IRQ_FreeEOIHandler", (void *)PIC_FreeIRQ,
"IRQ_Activate", (void *)PIC_ActivateIRQ,
"IRQ_Deactivate", (void *)PIC_DeActivateIRQ,
"TIMER_RegisterMicroHandler", (void *)TIMER_RegisterMicroHandler,
"TIMER_RegisterTickHandler", (void *)TIMER_RegisterTickHandler,
"DMA_8_Read", (void *)DMA_8_Read,
"DMA_16_Read", (void *)DMA_16_Read,
"DMA_8_Write", (void *)DMA_8_Write,
"DMA_16_Write", (void *)DMA_16_Write,
"MIXER_AddChannel", (void *)MIXER_AddChannel,
"MIXER_SetVolume", (void *)MIXER_SetVolume,
"MIXER_SetFreq", (void *)MIXER_SetFreq,
"MIXER_SetMode", (void *)MIXER_SetMode,
"MIXER_Enable", (void *)MIXER_Enable,
0,0
};
class PLUGIN : public Program {
public:
PLUGIN(PROGRAM_Info * program_info);
void Run(void);
};
PLUGIN::PLUGIN(PROGRAM_Info * info):Program(info) {
}
void PLUGIN::Run(void) {
}
static void PLUGIN_ProgramStart(PROGRAM_Info * info) {
PLUGIN * tempPLUGIN=new PLUGIN(info);
tempPLUGIN->Run();
delete tempPLUGIN;
}
bool PLUGIN_FindFunction(char * name,void * * function) {
/* Run through table and hope to find a match */
Bitu index=0;
while (functions[index].name) {
if (strcmp(functions[index].name,name)==0) {
*function=functions[index].function;
return true;
};
index++;
}
return false;
}
bool PLUGIN_LoadModule(char * name) {
MODULE_StartHandler starter;
#ifdef WIN32
HMODULE module;
module=LoadLibrary(name);
if (!module) return false;
/* Look for the module start functions */
FARPROC address;
address=GetProcAddress(module,MODULE_START_PROC);
starter=(MODULE_StartHandler)address;
#else
//TODO LINUX
#endif
starter(PLUGIN_FindFunction);
return false;
}
void PLUGIN_Init(void) {
PROGRAMS_MakeFile("PLUGIN.COM",PLUGIN_ProgramStart);
// PLUGIN_LoadModule("c:\\dosbox\\testmod.dll");
};

174
src/misc/programs.cpp Normal file
View file

@ -0,0 +1,174 @@
/*
* 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 <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "programs.h"
#include "callback.h"
#include "regs.h"
#include "support.h"
#include "cross.h"
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
0xb4,0x4a, //MOV AH,0x4A Resize memory block
0xcd,0x21, //INT 0x21
//pos 12 is callback number
0xFE,0x38,0x00,0x00, //CALLBack number
0xb8,0x00,0x4c, //Mov ax,4c00
0xcd,0x21, //INT 0x21
};
#define CB_POS 12
void PROGRAMS_MakeFile(char * name,PROGRAMS_Main * main) {
Bit8u * comdata=(Bit8u *)malloc(128);
memcpy(comdata,&exe_block,sizeof(exe_block));
comdata[CB_POS]=call_program&0xff;
comdata[CB_POS+1]=(call_program>>8)&0xff;
/* Copy the pointer this should preserve endianes */
memcpy(&comdata[sizeof(exe_block)],&main,sizeof(main));
Bit32u size=sizeof(exe_block)+sizeof(main);
VFILE_Register(name,comdata,size);
}
static Bitu PROGRAMS_Handler(void) {
/* This sets up everything for a program start up call */
/* First get the current psp */
PROGRAM_Info * info=new PROGRAM_Info;
info->psp_seg=dos.psp;
MEM_BlockRead(real_phys(dos.psp,0),&info->psp_copy,sizeof(PSP));
/* Get the file name cmd_line 0 */
PhysPt envblock=real_phys(info->psp_copy.environment,0);
do {} while (mem_readw(envblock++));
envblock+=3;
MEM_StrCopy(envblock,info->full_name,32);
info->psp_copy.cmdtail.buffer[info->psp_copy.cmdtail.count]=0;
info->cmd_line=info->psp_copy.cmdtail.buffer;
/* Find the program handler somewhere reference in the file */
Bit16u handle;
DOS_OpenFile(info->full_name,0,&handle);
Bit32u pos=sizeof(PROGRAMS_Main *);
DOS_SeekFile(handle,&pos,DOS_SEEK_END);
PROGRAMS_Main * handler;
Bit16u size=sizeof(PROGRAMS_Main *);
DOS_ReadFile(handle,(Bit8u *)&handler,&size);
DOS_CloseFile(handle);
(*handler)(info);
free(info);
return CBRET_NONE;
};
/* Main functions used in all program */
Program::Program(PROGRAM_Info * program_info) {
prog_info=program_info;
}
void Program::WriteOut(char * format,...) {
char buf[1024];
va_list msg;
va_start(msg,format);
vsprintf(buf,format,msg);
va_end(msg);
Bit16u size=strlen(buf);
DOS_WriteFile(STDOUT,(Bit8u *)buf,&size);
}
char * Program::GetEnvStr(char * env_str) {
/* Walk through the internal environment and see for a match */
/* Taking some short cuts here to not fuck around with memory structure */
char * envstart=(char *)real_host(prog_info->psp_copy.environment,0);
size_t len=strlen(env_str);
while (*envstart) {
if (strncasecmp(env_str,envstart,len)==0 && envstart[len]=='=') {
return envstart;
}
envstart+=strlen(envstart)+1;
}
return 0;
};
char * Program::GetEnvNum(Bit32u num) {
char * envstart=(char *)real_host(prog_info->psp_copy.environment,0);
while (*envstart) {
if (!num) return envstart;
envstart+=strlen(envstart)+1;
num--;
}
return 0;
}
Bit32u Program::GetEnvCount(void) {
char * envstart=(char *)real_host(prog_info->psp_copy.environment,0);
Bit32u num=0;
while (*envstart) {
envstart+=strlen(envstart)+1;
num++;
}
return num;
}
bool Program::SetEnv(char * env_entry,char * new_string) {
MCB * env_mcb=(MCB *)real_host(prog_info->psp_copy.environment-1,0);
upcase(env_entry);
Bit32u env_size=env_mcb->size*16;
if (!env_size) E_Exit("SHELL:Illegal environment size");
/* First try to find the old entry */
size_t len=strlen(env_entry);
char * envstart=(char *)real_host(prog_info->psp_copy.environment,0);
while (*envstart) {
if (strncasecmp(env_entry,envstart,len)==0 && envstart[len]=='=') {
/* Now remove this entry */
memmove(envstart,envstart+strlen(envstart)+1,env_size);
} else {
envstart+=strlen(envstart)+1;
env_size-=(strlen(envstart)+1);
}
}
/* Now add the string if there is space available */
if (env_size<(strlen(env_entry)+strlen(new_string)+2)) return false;
if (!*new_string) return true;
sprintf(envstart,"%s=%s",env_entry,new_string);
envstart+=strlen(envstart)+1;
*envstart++=0;*envstart++=0;*envstart++=0;
return true;
}
//TODO Hash table :)
void PROGRAMS_Init(void) {
/* Setup a special callback to start virtual programs */
call_program=CALLBACK_Allocate();
CALLBACK_Setup(call_program,&PROGRAMS_Handler,CB_RETF);
}

29
src/misc/setup.cpp Normal file
View file

@ -0,0 +1,29 @@
/*
* 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 "cross.h"
#include "setup.h"
void SETUP_AddBoolHandler() {
};

Some files were not shown because too many files have changed in this diff Show more