From ce09efba3611ae8f2ef0c885d6865db74c45ed8e Mon Sep 17 00:00:00 2001 From: dborth Date: Wed, 11 Aug 2010 04:08:22 +0000 Subject: [PATCH] sync to dosbox 3635 --- configure.in | 2 +- include/dos_system.h | 7 +- include/vga.h | 4 +- src/cpu/callback.cpp | 18 +- src/dos/cdrom.h | 15 ++ src/dos/cdrom_image.cpp | 18 +- src/dos/cdrom_ioctl_win32.cpp | 18 +- src/dos/dos.cpp | 11 +- src/dos/dos_files.cpp | 7 + src/dos/dos_memory.cpp | 2 +- src/dos/dos_mscdex.cpp | 66 +++++- src/dos/drive_cache.cpp | 67 ++++-- src/dos/drive_iso.cpp | 4 +- src/dos/drive_local.cpp | 24 +++ src/dos/drives.h | 2 + src/hardware/sblaster.cpp | 7 +- src/hardware/vga_attr.cpp | 52 +++-- src/hardware/vga_draw.cpp | 369 +++++++++++++++++----------------- src/hardware/vga_other.cpp | 7 +- src/ints/bios.cpp | 2 +- src/ints/int10.cpp | 12 +- src/ints/int10_memory.cpp | 16 +- src/ints/int10_pal.cpp | 51 +++-- src/shell/shell.cpp | 2 +- src/shell/shell_cmds.cpp | 11 +- 25 files changed, 510 insertions(+), 284 deletions(-) diff --git a/configure.in b/configure.in index 016ea95..3e2a878 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Init. -AC_INIT(dosbox,0.74) +AC_INIT(dosbox,SVN) AC_PREREQ(2.50) AC_CONFIG_SRCDIR(README) diff --git a/include/dos_system.h b/include/dos_system.h index 5edb048..eab510e 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -156,8 +156,9 @@ public: public: CFileInfo(void) { orgname[0] = shortname[0] = 0; - nextEntry = shortNr = 0; isDir = false; + id = MAX_OPENDIRS; + nextEntry = shortNr = 0; } ~CFileInfo(void) { for (Bit32u i=0; iAddSamples_s16_nonnative(len/4,(Bit16s *)player.buffer); #else diff --git a/src/dos/cdrom_ioctl_win32.cpp b/src/dos/cdrom_ioctl_win32.cpp index 9044e54..c12f752 100644 --- a/src/dos/cdrom_ioctl_win32.cpp +++ b/src/dos/cdrom_ioctl_win32.cpp @@ -175,7 +175,7 @@ bool CDROM_Interface_Ioctl::mci_CDPosition(int *position) { CDROM_Interface_Ioctl::dxPlayer CDROM_Interface_Ioctl::player = { - NULL, NULL, NULL, 0, 0, 0, 0, 0, false, false }; + NULL, NULL, NULL, {0}, 0, 0, 0, false, false, false, {0} }; CDROM_Interface_Ioctl::CDROM_Interface_Ioctl(cdioctl_cdatype ioctl_cda) { pathname[0] = 0; @@ -462,6 +462,12 @@ bool CDROM_Interface_Ioctl::StopAudio(void) { return bStat>0; } +void CDROM_Interface_Ioctl::ChannelControl(TCtrl ctrl) +{ + player.ctrlUsed = (ctrl.out[0]!=0 || ctrl.out[1]!=1 || ctrl.vol[0]<0xfe || ctrl.vol[1]<0xfe); + player.ctrlData = ctrl; +} + bool CDROM_Interface_Ioctl::LoadUnloadMedia(bool unload) { BOOL bStat; DWORD byteCount; @@ -553,6 +559,16 @@ void CDROM_Interface_Ioctl::dx_CDAudioCallBack(Bitu len) { } } SDL_mutexV(player.mutex); + if (player.ctrlUsed) { + Bit16s sample0,sample1; + Bit16s * samples=(Bit16s *)&player.buffer; + for (Bitu pos=0;posAddSamples_s16(len/4,(Bit16s *)player.buffer); memmove(player.buffer, &player.buffer[len], player.bufLen - len); player.bufLen -= len; diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index 35eb73e..a3ec0a7 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -227,10 +227,13 @@ static Bitu DOS_21Handler(void) { break; case 0x0c: /* Flush Buffer and read STDIN call */ { - /* flush STDIN-buffer */ - Bit8u c;Bit16u n; - while (DOS_GetSTDINStatus()) { - n=1; DOS_ReadFile(STDIN,&c,&n); + /* flush buffer if STDIN is CON */ + Bit8u handle=RealHandle(STDIN); + if (handle!=0xFF && Files[handle] && Files[handle]->IsName("CON")) { + Bit8u c;Bit16u n; + while (DOS_GetSTDINStatus()) { + n=1; DOS_ReadFile(STDIN,&c,&n); + } } switch (reg_al) { case 0x1: diff --git a/src/dos/dos_files.cpp b/src/dos/dos_files.cpp index c720fd9..1734035 100644 --- a/src/dos/dos_files.cpp +++ b/src/dos/dos_files.cpp @@ -203,6 +203,13 @@ bool DOS_GetCurrentDir(Bit8u drive,char * const buffer) { bool DOS_ChangeDir(char const * const dir) { Bit8u drive;char fulldir[DOS_PATHLENGTH]; + const char * testdir=dir; + if (strlen(testdir) && testdir[1]==':') testdir+=2; + size_t len=strlen(testdir); + if (!len || (len>1 && testdir[len-1]=='\\')) { + DOS_SetError(DOSERR_PATH_NOT_FOUND); + return false; + } if (!DOS_MakeName(dir,fulldir,&drive)) return false; if (Drives[drive]->TestDir(fulldir)) { diff --git a/src/dos/dos_memory.cpp b/src/dos/dos_memory.cpp index 7bdd514..e4c3627 100644 --- a/src/dos/dos_memory.cpp +++ b/src/dos/dos_memory.cpp @@ -436,7 +436,7 @@ void DOS_SetupMemory(void) { if (machine==MCH_TANDY) { /* memory up to 608k available, the rest (to 640k) is used by the tandy graphics system's variable mapping of 0xb800 */ - mcb.SetSize(0x97FF - DOS_MEM_START - mcb_sizes); + mcb.SetSize(0x9BFF - DOS_MEM_START - mcb_sizes); } else if (machine==MCH_PCJR) { /* memory from 128k to 640k is available */ mcb_devicedummy.SetPt((Bit16u)0x2000); diff --git a/src/dos/dos_mscdex.cpp b/src/dos/dos_mscdex.cpp index 65ab123..9423987 100644 --- a/src/dos/dos_mscdex.cpp +++ b/src/dos/dos_mscdex.cpp @@ -152,6 +152,7 @@ private: bool locked; // drive locked ? bool lastResult; // last operation success ? Bit32u volumeSize; // for media change + TCtrl audioCtrl; // audio channel control } TDriveInfo; Bit16u defaultBufSeg; @@ -160,6 +161,9 @@ private: public: Bit16u rootDriverHeaderSeg; + + bool ChannelControl (Bit8u subUnit, TCtrl ctrl); + bool GetChannelControl (Bit8u subUnit, TCtrl& ctrl); }; CMscdex::CMscdex(void) { @@ -368,25 +372,34 @@ int CMscdex::AddDrive(Bit16u _drive, char* physicalPath, Bit8u& subUnit) devHeader.SetInterrupt(off+5); } - subUnit = (Bit8u)numDrives; // Set drive DOS_DeviceHeader devHeader(PhysMake(rootDriverHeaderSeg,0)); devHeader.SetNumSubUnits(devHeader.GetNumSubUnits()+1); if (dinfo[0].drive-1==_drive) { CDROM_Interface *_cdrom = cdrom[numDrives]; + CDROM_Interface_Image *_cdimg = CDROM_Interface_Image::images[numDrives]; for (Bit16u i=GetNumDrives(); i>0; i--) { dinfo[i] = dinfo[i-1]; cdrom[i] = cdrom[i-1]; + CDROM_Interface_Image::images[i] = CDROM_Interface_Image::images[i-1]; } cdrom[0] = _cdrom; + CDROM_Interface_Image::images[0] = _cdimg; dinfo[0].drive = (Bit8u)_drive; dinfo[0].physDrive = (Bit8u)toupper(physicalPath[0]); + subUnit = 0; } else { dinfo[numDrives].drive = (Bit8u)_drive; dinfo[numDrives].physDrive = (Bit8u)toupper(physicalPath[0]); + subUnit = (Bit8u)numDrives; } numDrives++; + // init channel control + for (Bit8u chan=0;chan<4;chan++) { + dinfo[subUnit].audioCtrl.out[chan]=chan; + dinfo[subUnit].audioCtrl.vol[chan]=0xff; + } // stop audio StopAudio(subUnit); return result; @@ -459,7 +472,7 @@ bool CMscdex::PlayAudioSector(Bit8u subUnit, Bit32u sector, Bit32u length) if (subUnit>=numDrives) return false; // If value from last stop is used, this is meant as a resume // better start using resume command - if (dinfo[subUnit].audioPaused && (sector==dinfo[subUnit].audioStart)) { + if (dinfo[subUnit].audioPaused && (sector==dinfo[subUnit].audioStart) && (dinfo[subUnit].audioEnd!=0)) { dinfo[subUnit].lastResult = cdrom[subUnit]->PauseAudio(true); } else dinfo[subUnit].lastResult = cdrom[subUnit]->PlayAudioSector(sector,length); @@ -665,6 +678,7 @@ bool CMscdex::GetDirectoryEntry(Bit16u drive, bool copyFlag, PhysPt pathname, Ph char entryName[256]; bool foundComplete = false; bool foundName; + bool nextPart = true; char* useName = 0; Bitu entryLength,nameLength; // clear error @@ -695,14 +709,15 @@ bool CMscdex::GetDirectoryEntry(Bit16u drive, bool copyFlag, PhysPt pathname, Ph if (!ReadSectors(GetSubUnit(drive),false,dirEntrySector,1,defBuffer)) return false; // Get string part foundName = false; - if (searchPos) { - useName = searchPos; - searchPos = strchr(searchPos,'\\'); + if (nextPart) { + if (searchPos) { + useName = searchPos; + searchPos = strchr(searchPos,'\\'); + } + if (searchPos) { *searchPos = 0; searchPos++; } + else foundComplete = true; } - if (searchPos) { *searchPos = 0; searchPos++; } - else foundComplete = true; - do { entryLength = mem_readb(defBuffer+index); if (entryLength==0) break; @@ -759,10 +774,12 @@ bool CMscdex::GetDirectoryEntry(Bit16u drive, bool copyFlag, PhysPt pathname, Ph // change directory dirEntrySector = mem_readd(defBuffer+index+2); dirSize = mem_readd(defBuffer+index+10); + nextPart = true; } else { // continue search in next sector dirSize -= 2048; dirEntrySector++; + nextPart = false; } }; error = 2; // file not found @@ -796,6 +813,7 @@ Bit32u CMscdex::GetDeviceStatus(Bit8u subUnit) (dinfo[subUnit].locked << 1) | // Drive is locked ? (1<<2) | // raw + cooked sectors (1<<4) | // Can read sudio + (1<<8) | // Can control audio (1<<9) | // Red book & HSG ((!media) << 11); // Drive is empty ? return status; @@ -860,6 +878,22 @@ void CMscdex::InitNewMedia(Bit8u subUnit) { } } +bool CMscdex::ChannelControl(Bit8u subUnit, TCtrl ctrl) { + if (subUnit>=numDrives) return false; + // adjust strange channel mapping + if (ctrl.out[0]>1) ctrl.out[0]=0; + if (ctrl.out[1]>1) ctrl.out[1]=1; + dinfo[subUnit].audioCtrl=ctrl; + cdrom[subUnit]->ChannelControl(ctrl); + return true; +} + +bool CMscdex::GetChannelControl(Bit8u subUnit, TCtrl& ctrl) { + if (subUnit>=numDrives) return false; + ctrl=dinfo[subUnit].audioCtrl; + return true; +} + static CMscdex* mscdex = 0; static PhysPt curReqheaderPtr = 0; @@ -889,6 +923,14 @@ static Bit16u MSCDEX_IOCTL_Input(PhysPt buffer,Bit8u drive_unit) { return 0x03; // invalid function } }break; + case 0x04 : /* Audio Channel control */ + TCtrl ctrl; + if (!mscdex->GetChannelControl(drive_unit,ctrl)) return 0x01; + for (Bit8u chan=0;chan<4;chan++) { + mem_writeb(buffer+chan*2+1,ctrl.out[chan]); + mem_writeb(buffer+chan*2+2,ctrl.vol[chan]); + } + break; case 0x06 : /* Get Device status */ mem_writed(buffer+1,mscdex->GetDeviceStatus(drive_unit)); break; @@ -980,7 +1022,13 @@ static Bit16u MSCDEX_IOCTL_Optput(PhysPt buffer,Bit8u drive_unit) { if (!mscdex->LoadUnloadMedia(drive_unit,true)) return 0x02; break; case 0x03: //Audio Channel control - MSCDEX_LOG("MSCDEX: Audio Channel Control used. Not handled. Faking succes!"); + TCtrl ctrl; + for (Bit8u chan=0;chan<4;chan++) { + ctrl.out[chan]=mem_readb(buffer+chan*2+1); + ctrl.vol[chan]=mem_readb(buffer+chan*2+2); + } + if (!mscdex->ChannelControl(drive_unit,ctrl)) return 0x01; + break; case 0x01 : // (un)Lock door // do nothing -> report as success break; diff --git a/src/dos/drive_cache.cpp b/src/dos/drive_cache.cpp index 37f3098..003b82c 100644 --- a/src/dos/drive_cache.cpp +++ b/src/dos/drive_cache.cpp @@ -67,7 +67,7 @@ DOS_Drive_Cache::DOS_Drive_Cache(void) { srchNr = 0; label[0] = 0; nextFreeFindFirst = 0; - for (Bit32u i=0; iid != MAX_OPENDIRS) + return dir->id; + for (Bit16u i=0; iid = i; + return i; + } + } LOG(LOG_FILES,LOG_NORMAL)("DIRCACHE: Too many open directories!"); + dir->id=0; return 0; } @@ -264,7 +271,7 @@ void DOS_Drive_Cache::CacheOut(const char* path, bool ignoreLastDir) { // delete file objects... for(Bit32u i=0; ifileList.size(); i++) { if (dirSearch[srchNr]==dir->fileList[i]) dirSearch[srchNr] = 0; - delete dir->fileList[i]; dir->fileList[i] = 0; + DeleteFileInfo(dir->fileList[i]); dir->fileList[i] = 0; } // clear lists dir->fileList.clear(); @@ -526,7 +533,10 @@ DOS_Drive_Cache::CFileInfo* DOS_Drive_Cache::FindDirInfo(const char* path, char* strcpy(buffer,dirPath); ReadDir(id,result); strcpy(dirPath,buffer); - free[id] = true; + if (dirSearch[id]) { + dirSearch[id]->id = MAX_OPENDIRS; + dirSearch[id] = 0; + } }; }; @@ -556,7 +566,10 @@ DOS_Drive_Cache::CFileInfo* DOS_Drive_Cache::FindDirInfo(const char* path, char* strcpy(buffer,dirPath); ReadDir(id,result); strcpy(dirPath,buffer); - free[id] = true; + if (dirSearch[id]) { + dirSearch[id]->id = MAX_OPENDIRS; + dirSearch[id] = 0; + } }; } }; @@ -600,9 +613,12 @@ bool DOS_Drive_Cache::OpenDir(CFileInfo* dir, const char* expand, Bit16u& id) { // Reset it.. close_directory(dirp); strcpy(dirPath,expandcopy); - free[id] = false; return true; } + if (dirSearch[id]) { + dirSearch[id]->id = MAX_OPENDIRS; + dirSearch[id] = 0; + } }; return false; } @@ -661,7 +677,10 @@ bool DOS_Drive_Cache::ReadDir(Bit16u id, char* &result) { // Try to open directory dir_information* dirp = open_directory(dirPath); if (!dirp) { - free[id] = true; + if (dirSearch[id]) { + dirSearch[id]->id = MAX_OPENDIRS; + dirSearch[id] = 0; + } return false; } // Read complete directory @@ -688,7 +707,10 @@ bool DOS_Drive_Cache::ReadDir(Bit16u id, char* &result) { };*/ }; if (SetResult(dirSearch[id], result, dirSearch[id]->nextEntry)) return true; - free[id] = true; + if (dirSearch[id]) { + dirSearch[id]->id = MAX_OPENDIRS; + dirSearch[id] = 0; + } return false; } @@ -732,7 +754,7 @@ bool DOS_Drive_Cache::FindFirst(char* path, Bit16u& id) { this->nextFreeFindFirst = 1; //the next free one after this search for(Bitu n=0; nnextEntry)) { // free slot - delete dirFindFirst[id]; dirFindFirst[id] = 0; + DeleteFileInfo(dirFindFirst[id]); dirFindFirst[id] = 0; return false; } return true; } + +void DOS_Drive_Cache::ClearFileInfo(CFileInfo *dir) { + for(Bit32u i=0; ifileList.size(); i++) { + if (CFileInfo *info = dir->fileList[i]) + ClearFileInfo(info); + } + if (dir->id != MAX_OPENDIRS) { + dirSearch[dir->id] = 0; + dir->id = MAX_OPENDIRS; + } +} + +void DOS_Drive_Cache::DeleteFileInfo(CFileInfo *dir) { + if (dir) + ClearFileInfo(dir); + delete dir; +} diff --git a/src/dos/drive_iso.cpp b/src/dos/drive_iso.cpp index 5150850..6be8889 100644 --- a/src/dos/drive_iso.cpp +++ b/src/dos/drive_iso.cpp @@ -289,7 +289,7 @@ bool isoDrive::FindNext(DOS_DTA &dta) { else findAttr |= DOS_ATTR_ARCHIVE; if (IS_HIDDEN(de.fileFlags)) findAttr |= DOS_ATTR_HIDDEN; - if (!(isRoot && de.ident[0]=='.') && WildFileCmp((char*)de.ident, pattern) + if (!IS_ASSOC(de.fileFlags) && !(isRoot && de.ident[0]=='.') && WildFileCmp((char*)de.ident, pattern) && !(~attr & findAttr & (DOS_ATTR_DIRECTORY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM))) { /* file is okay, setup everything to be copied in DTA Block */ @@ -541,7 +541,7 @@ bool isoDrive :: lookup(isoDirEntry *de, const char *path) { // look for the current path element int dirIterator = GetDirIterator(de); while (!found && GetNextDirEntry(dirIterator, de)) { - if (0 == strncasecmp((char*) de->ident, name, ISO_MAX_FILENAME_LENGTH)) { + if (!IS_ASSOC(de->fileFlags) && (0 == strncasecmp((char*) de->ident, name, ISO_MAX_FILENAME_LENGTH))) { found = true; } } diff --git a/src/dos/drive_local.cpp b/src/dos/drive_local.cpp index f92e666..1af3ddc 100644 --- a/src/dos/drive_local.cpp +++ b/src/dos/drive_local.cpp @@ -41,6 +41,7 @@ public: Bit16u GetInformation(void); bool UpdateDateTimeFromHost(void); void FlagReadOnlyMedium(void); + void Flush(void); private: FILE * fhandle; bool read_only_medium; @@ -95,6 +96,22 @@ bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) { CROSS_FILENAME(newname); dirCache.ExpandName(newname); + //Flush the buffer of handles for the same file. (Betrayal in Antara) + Bit8u i,drive=DOS_DRIVES; + localFile *lfp; + for (i=0;iIsOpen() && Files[i]->GetDrive()==drive && Files[i]->IsName(name)) { + lfp=dynamic_cast(Files[i]); + if (lfp) lfp->Flush(); + } + } + FILE * hand=fopen(newname,type); // Bit32u err=errno; if (!hand) { @@ -541,6 +558,13 @@ bool localFile::UpdateDateTimeFromHost(void) { return true; } +void localFile::Flush(void) { + if (last_action==WRITE) { + fseek(fhandle,ftell(fhandle),SEEK_SET); + last_action=NONE; + } +} + // ******************************************** // CDROM DRIVE diff --git a/src/dos/drives.h b/src/dos/drives.h index aa629fc..431f3f1 100644 --- a/src/dos/drives.h +++ b/src/dos/drives.h @@ -298,11 +298,13 @@ struct isoDirEntry { #endif #define ISO_FRAMESIZE 2048 +#define ISO_ASSOCIATED 4 #define ISO_DIRECTORY 2 #define ISO_HIDDEN 1 #define ISO_MAX_FILENAME_LENGTH 37 #define ISO_MAXPATHNAME 256 #define ISO_FIRST_VD 16 +#define IS_ASSOC(fileFlags) (fileFlags & ISO_ASSOCIATED) #define IS_DIR(fileFlags) (fileFlags & ISO_DIRECTORY) #define IS_HIDDEN(fileFlags) (fileFlags & ISO_HIDDEN) #define ISO_MAX_HASH_TABLE_SIZE 100 diff --git a/src/hardware/sblaster.cpp b/src/hardware/sblaster.cpp index e0427e9..8dbd479 100644 --- a/src/hardware/sblaster.cpp +++ b/src/hardware/sblaster.cpp @@ -504,6 +504,8 @@ static void GenerateDMASound(Bitu size) { sb.dma.left-=read; if (!sb.dma.left) { PIC_RemoveEvents(END_DMA_Event); + if (sb.dma.mode >= DSP_DMA_16) SB_RaiseIRQ(SB_IRQ_16); + else SB_RaiseIRQ(SB_IRQ_8); if (!sb.dma.autoinit) { LOG(LOG_SB,LOG_NORMAL)("Single cycle transfer ended"); sb.mode=MODE_NONE; @@ -515,8 +517,6 @@ static void GenerateDMASound(Bitu size) { sb.mode=MODE_NONE; } } - if (sb.dma.mode >= DSP_DMA_16) SB_RaiseIRQ(SB_IRQ_16); - else SB_RaiseIRQ(SB_IRQ_8); } } @@ -1345,7 +1345,8 @@ static Bit8u CTMIXER_Read(void) { return ret; case 0x82: /* IRQ Status */ return (sb.irq.pending_8bit ? 0x1 : 0) | - (sb.irq.pending_16bit ? 0x2 : 0); + (sb.irq.pending_16bit ? 0x2 : 0) | + ((sb.type == SBT_16) ? 0x20 : 0); default: if ( ((sb.type == SBT_PRO1 || sb.type == SBT_PRO2) && sb.mixer.index==0x0c) || /* Input control on SBPro */ (sb.type == SBT_16 && sb.mixer.index >= 0x3b && sb.mixer.index <= 0x47)) /* New SB16 registers */ diff --git a/src/hardware/vga_attr.cpp b/src/hardware/vga_attr.cpp index 9f23b50..e8b8960 100644 --- a/src/hardware/vga_attr.cpp +++ b/src/hardware/vga_attr.cpp @@ -76,26 +76,33 @@ void write_p3c0(Bitu /*port*/,Bitu val,Bitu iolen) { 10h and 14h. */ break; - case 0x10: /* Mode Control Register */ + case 0x10: { /* Mode Control Register */ if (!IS_VGA_ARCH) val&=0x1f; // not really correct, but should do it - if ((attr(mode_control) ^ val) & 0x80) { - attr(mode_control)^=0x80; - for (Bit8u i=0;i<0x10;i++) { + Bitu difference = attr(mode_control)^val; + attr(mode_control)=(Bit8u)val; + + if (difference & 0x80) { + for (Bit8u i=0;i<0x10;i++) VGA_ATTR_SetPalette(i,vga.attr.palette[i]); + } + if (difference & 0x08) + VGA_SetBlinking(val & 0x8); + + if (difference & 0x41) + VGA_DetermineMode(); + + if (difference & 0x04) { + // recompute the panning value + if(vga.mode==M_TEXT) { + Bit8u pan_reg = attr(horizontal_pel_panning); + if (pan_reg > 7) + vga.config.pel_panning=0; + else if (val&0x4) // 9-dot wide characters + vga.config.pel_panning=(Bit8u)(pan_reg+1); + else // 8-dot characters + vga.config.pel_panning=(Bit8u)pan_reg; } } - if ((attr(mode_control) ^ val) & 0x08) { - VGA_SetBlinking(val & 0x8); - } - if ((attr(mode_control) ^ val) & 0x04) { - attr(mode_control)=(Bit8u)val; - VGA_DetermineMode(); - if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) VGA_StartResize(); - } else { - attr(mode_control)=(Bit8u)val; - VGA_DetermineMode(); - } - /* 0 Graphics mode if set, Alphanumeric mode else. 1 Monochrome mode if set, color mode else. @@ -113,6 +120,7 @@ void write_p3c0(Bitu /*port*/,Bitu val,Bitu iolen) { used. */ break; + } case 0x11: /* Overscan Color Register */ attr(overscan_color)=(Bit8u)val; /* 0-5 Color of screen border. Color is defined as in the palette registers. */ @@ -134,9 +142,12 @@ void write_p3c0(Bitu /*port*/,Bitu val,Bitu iolen) { attr(horizontal_pel_panning)=val & 0xF; switch (vga.mode) { case M_TEXT: - if ((val==0x7) && (svgaCard==SVGA_None)) vga.config.pel_panning=7; - if (val>0x7) vga.config.pel_panning=0; - else vga.config.pel_panning=(Bit8u)(val+1); + if (val > 7) + vga.config.pel_panning=0; + else if (vga.attr.mode_control&0x4) // 9-dot wide characters + vga.config.pel_panning=(Bit8u)(val+1); + else // 8-dot characters + vga.config.pel_panning=(Bit8u)val; break; case M_VGA: case M_LIN8: @@ -146,6 +157,9 @@ void write_p3c0(Bitu /*port*/,Bitu val,Bitu iolen) { default: vga.config.pel_panning=(val & 0x7); } + if (machine==MCH_EGA) + // On the EGA panning can be programmed for every scanline: + vga.draw.panning = vga.config.pel_panning; /* 0-3 Indicates number of pixels to shift the display left Value 9bit textmode 256color mode Other modes diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index 459e768..c533042 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -155,7 +155,7 @@ static Bit8u * VGA_Draw_Changes_Line(Bitu vidstart, Bitu line) { for (; start <= end;start++) { if ( map[start] & checkMask ) { Bitu offset = vidstart & vga.draw.linear_mask; - if(vga.draw.linear_mask-offset < vga.draw.line_length) + if (vga.draw.linear_mask-offset < vga.draw.line_length) memcpy(vga.draw.linear_base+vga.draw.linear_mask+1, vga.draw.linear_base, vga.draw.line_length); Bit8u *ret = &vga.draw.linear_base[ offset ]; #if !defined(C_UNALIGNED_MEMORY) @@ -197,14 +197,6 @@ static Bit8u * VGA_Draw_Xlat16_Linear_Line(Bitu vidstart, Bitu /*line*/) { temps[i]=vga.dac.xlat16[ret[i]]; } return TempLine; - /* -#if !defined(C_UNALIGNED_MEMORY) - if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) { - memcpy( TempLine, ret, vga.draw.line_length ); - return TempLine; - } -#endif - return ret;*/ } //Test version, might as well keep it @@ -446,167 +438,121 @@ static Bit8u * VGA_TEXT_Herc_Draw_Line(Bitu vidstart, Bitu line) { skip_cursor: return TempLine; } - -static Bit8u * VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart, Bitu line) { - Bits font_addr; - Bit16u * draw=(Bit16u *)TempLine; - const Bit8u* vidmem = VGA_Text_Memwrap(vidstart); - for (Bitu cx=0;cx> 3)&1][chr*32+line]; - Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7]; - Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7]; - Bit32u fg=TXT_FG_Table[col&0xf]; - Bit32u bg=TXT_BG_Table[col>>4]; - - mask1=(fg&mask1) | (bg&~mask1); - mask2=(fg&mask2) | (bg&~mask2); - - for(int i = 0; i < 4; i++) { - *draw++ = vga.dac.xlat16[(mask1>>8*i)&0xff]; - } - for(int i = 0; i < 4; i++) { - *draw++ = vga.dac.xlat16[(mask2>>8*i)&0xff]; - } - } - if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor; - font_addr = (vga.draw.cursor.address-vidstart) >> 1; - if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) { - if (linevga.draw.cursor.eline) goto skip_cursor; - draw=(Bit16u *)&TempLine[font_addr*16]; - Bit8u att=(Bit8u)(TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf]&0xff); - for(int i = 0; i < 8; i++) { - *draw++ = vga.dac.xlat16[att]; - } - } -skip_cursor: - return TempLine; -} - /* -static Bit8u * VGA_TEXT_Draw_Line_9(Bitu vidstart, Bitu line) { - Bits font_addr; - Bit8u * draw=(Bit8u *)TempLine; - bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line; - Bit8u pel_pan=(Bit8u)vga.draw.panning; - if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0; - const Bit8u* vidmem = VGA_Text_Memwrap(vidstart); - Bit8u chr=vidmem[0]; - Bit8u col=vidmem[1]; - Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<>4]&0xff); - Bitu draw_blocks=vga.draw.blocks; - draw_blocks++; - for (Bitu cx=1;cx>(8-pel_pan); - else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan); - fg=col&0xf; - bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff); +// combined 8/9-dot wide text mode 8bpp line drawing function +static Bit8u* VGA_TEXT_Draw_Line(Bitu vidstart, Bitu line) { + // keep it aligned: + Bit8u* draw = ((Bit8u*)TempLine) + 16 - vga.draw.panning; + const Bit8u* vidmem = VGA_Text_Memwrap(vidstart); // pointer to chars+attribs + Bitu blocks = vga.draw.blocks; + if (vga.draw.panning) blocks++; // if the text is panned part of an + // additional character becomes visible + while (blocks--) { // for each character in the line + Bitu chr = *vidmem++; + Bitu attr = *vidmem++; + // the font pattern + Bitu font = vga.draw.font_tables[(attr >> 3)&1][(chr<<5)+line]; + + Bitu background = attr >> 4; + // if blinking is enabled bit7 is not mapped to attributes + if (vga.draw.blinking) background &= ~0x8; + // choose foreground color if blinking not set for this cell or blink on + Bitu foreground = (vga.draw.blink || (!(attr&0x80)))? + (attr&0xf):background; + // underline: all foreground [freevga: 0x77, previous 0x7] + if (GCC_UNLIKELY(((attr&0x77) == 0x01) && + (vga.crtc.underline_location&0x1f)==line)) + background = foreground; + if (vga.draw.char9dot) { + font <<=1; // 9 pixels + // extend to the 9th pixel if needed + if ((font&0x2) && (vga.attr.mode_control&0x04) && + (chr>=0xc0) && (chr<=0xdf)) font |= 1; + for (Bitu n = 0; n < 9; n++) { + *draw++ = (font&0x100)? foreground:background; + font <<= 1; + } } else { - chr=vidmem[(cx-1)*2]; - col=vidmem[(cx-1)*2+1]; - if (underline && ((col&0x07) == 0x01)) font=0xff; - else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line]; - fg=col&0xf; - bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff); - } - if (FontMask[col>>7]==0) font=0; - *draw++=(font&0x80)?fg:bg; *draw++=(font&0x40)?fg:bg; - *draw++=(font&0x20)?fg:bg; *draw++=(font&0x10)?fg:bg; - *draw++=(font&0x08)?fg:bg; *draw++=(font&0x04)?fg:bg; - *draw++=(font&0x02)?fg:bg; - Bit8u last=(font&0x01)?fg:bg; - *draw++=last; - *draw++=((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) ? bg : last; - if (pel_pan) { - if (underline && ((col&0x07) == 0x01)) font=0xff; - else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<> 1; - if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) { - if (linevga.draw.cursor.eline) goto skip_cursor; - draw=&TempLine[font_addr*9]; - Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf; - *draw++=fg; *draw++=fg; *draw++=fg; *draw++=fg; - *draw++=fg; *draw++=fg; *draw++=fg; *draw++=fg; + // draw the text mode cursor if needed + if ((vga.draw.cursor.count&0x8) && (line >= vga.draw.cursor.sline) && + (line <= vga.draw.cursor.eline) && vga.draw.cursor.enabled) { + // the adress of the attribute that makes up the cell the cursor is in + Bits attr_addr = (vga.draw.cursor.address-vidstart) >> 1; + if (attr_addr >= 0 && attr_addr < (Bits)vga.draw.blocks) { + Bitu index = attr_addr * (vga.draw.char9dot? 9:8); + draw = (Bit8u*)(&TempLine[index]) + 16 - vga.draw.panning; + + Bitu foreground = vga.tandy.draw_base[vga.draw.cursor.address+1] & 0xf; + for (Bitu i = 0; i < 8; i++) { + *draw++ = foreground; + } + } } -skip_cursor: - return TempLine; + return TempLine+16; } */ - -static Bit8u * VGA_TEXT_Xlat16_Draw_Line_9(Bitu vidstart, Bitu line) { - Bits font_addr; - Bit16u * draw=(Bit16u *)TempLine; - bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line; - Bit8u pel_pan=(Bit8u)vga.draw.panning; - if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0; - const Bit8u* vidmem = VGA_Text_Memwrap(vidstart); - Bit8u chr=vidmem[0]; - Bit8u col=vidmem[1]; - Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<>4]&0xff); - Bitu draw_blocks=vga.draw.blocks; - draw_blocks++; - for (Bitu cx=1;cx>(8-pel_pan); - else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan); - fg=col&0xf; - bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff); +// combined 8/9-dot wide text mode 16bpp line drawing function +static Bit8u* VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart, Bitu line) { + // keep it aligned: + Bit16u* draw = ((Bit16u*)TempLine) + 16 - vga.draw.panning; + const Bit8u* vidmem = VGA_Text_Memwrap(vidstart); // pointer to chars+attribs + Bitu blocks = vga.draw.blocks; + if (vga.draw.panning) blocks++; // if the text is panned part of an + // additional character becomes visible + while (blocks--) { // for each character in the line + Bitu chr = *vidmem++; + Bitu attr = *vidmem++; + // the font pattern + Bitu font = vga.draw.font_tables[(attr >> 3)&1][(chr<<5)+line]; + + Bitu background = attr >> 4; + // if blinking is enabled bit7 is not mapped to attributes + if (vga.draw.blinking) background &= ~0x8; + // choose foreground color if blinking not set for this cell or blink on + Bitu foreground = (vga.draw.blink || (!(attr&0x80)))? + (attr&0xf):background; + // underline: all foreground [freevga: 0x77, previous 0x7] + if (GCC_UNLIKELY(((attr&0x77) == 0x01) && + (vga.crtc.underline_location&0x1f)==line)) + background = foreground; + if (vga.draw.char9dot) { + font <<=1; // 9 pixels + // extend to the 9th pixel if needed + if ((font&0x2) && (vga.attr.mode_control&0x04) && + (chr>=0xc0) && (chr<=0xdf)) font |= 1; + for (Bitu n = 0; n < 9; n++) { + *draw++ = vga.dac.xlat16[(font&0x100)? foreground:background]; + font <<= 1; + } } else { - chr=vidmem[(cx-1)*2]; - col=vidmem[(cx-1)*2+1]; - if (underline && ((col&0x07) == 0x01)) font=0xff; - else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line]; - fg=col&0xf; - bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff); - } - if (FontMask[col>>7]==0) font=0; - Bit8u mask=0x80; - for (int i = 0; i < 7; i++) { - *draw++=vga.dac.xlat16[font&mask?fg:bg]; - mask>>=1; - } - Bit16u lastval=vga.dac.xlat16[font&mask?fg:bg]; - *draw++=lastval; - *draw++=(((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) && - !(underline && ((col&0x07) == 0x01))) ? - (vga.dac.xlat16[bg]) : lastval; - if (pel_pan) { - if (underline && ((col&0x07) == 0x01)) font=0xff; - else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<> 1; - if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) { - if (linevga.draw.cursor.eline) goto skip_cursor; - draw=(Bit16u*)&TempLine[font_addr*18]; - Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf; - for(int i = 0; i < 8; i++) { - *draw++ = vga.dac.xlat16[fg]; + // draw the text mode cursor if needed + if ((vga.draw.cursor.count&0x8) && (line >= vga.draw.cursor.sline) && + (line <= vga.draw.cursor.eline) && vga.draw.cursor.enabled) { + // the adress of the attribute that makes up the cell the cursor is in + Bits attr_addr = (vga.draw.cursor.address-vidstart) >> 1; + if (attr_addr >= 0 && attr_addr < (Bits)vga.draw.blocks) { + Bitu index = attr_addr * (vga.draw.char9dot? 18:16); + draw = (Bit16u*)(&TempLine[index]) + 16 - vga.draw.panning; + + Bitu foreground = vga.tandy.draw_base[vga.draw.cursor.address+1] & 0xf; + for (Bitu i = 0; i < 8; i++) { + *draw++ = vga.dac.xlat16[foreground]; + } } - //if(underline && ((col&0x07) == 0x01)) - // *draw = vga.dac.xlat16[fg]; } -skip_cursor: - return TempLine; + return TempLine+32; } #ifdef VGA_KEEP_CHANGES @@ -628,14 +574,17 @@ static INLINE void VGA_ChangesEnd(void ) { static void VGA_ProcessSplit() { - // On the EGA the address is always reset to 0. - if ((vga.attr.mode_control&0x20) || (machine==MCH_EGA)) { + if (vga.attr.mode_control&0x20) { vga.draw.address=0; + // reset panning to 0 here so we don't have to check for + // it in the character draw functions. It will be set back + // to its proper value in v-retrace + vga.draw.panning=0; } else { // In text mode only the characters are shifted by panning, not the address; // this is done in the text line draw function. vga.draw.address = vga.draw.byte_panning_shift*vga.draw.bytes_skip; - if (!(vga.mode==M_TEXT)) vga.draw.address += vga.draw.panning; + if ((vga.mode!=M_TEXT)&&(machine!=MCH_EGA)) vga.draw.address += vga.draw.panning; } vga.draw.address_line=0; } @@ -662,6 +611,29 @@ static void VGA_DrawSingleLine(Bitu /*blah*/) { } else RENDER_EndUpdate(false); } +static void VGA_DrawEGASingleLine(Bitu /*blah*/) { + if (GCC_UNLIKELY(vga.attr.disabled)) { + memset(TempLine, 0, sizeof(TempLine)); + RENDER_DrawLine(TempLine); + } else { + Bitu address = vga.draw.address; + if (vga.mode!=M_TEXT) address += vga.draw.panning; + Bit8u * data=VGA_DrawLine(address, vga.draw.address_line ); + RENDER_DrawLine(data); + } + + vga.draw.address_line++; + if (vga.draw.address_line>=vga.draw.address_line_total) { + vga.draw.address_line=0; + vga.draw.address+=vga.draw.address_add; + } + vga.draw.lines_done++; + if (vga.draw.split_line==vga.draw.lines_done) VGA_ProcessSplit(); + if (vga.draw.lines_done < vga.draw.lines_total) { + PIC_AddEvent(VGA_DrawEGASingleLine,(float)vga.draw.delay.htotal); + } else RENDER_EndUpdate(false); +} + static void VGA_DrawPart(Bitu lines) { while (lines--) { Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line ); @@ -771,7 +743,6 @@ static void VGA_VerticalTimer(Bitu /*val*/) { VGA_DisplayStartLatch(0); break; case MCH_VGA: - case MCH_EGA: PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrstart); PIC_AddEvent(VGA_PanningLatch, (float)vga.draw.delay.vrend); // EGA: 82c435 datasheet: interrupt happens at display end @@ -779,6 +750,10 @@ static void VGA_VerticalTimer(Bitu /*val*/) { // add a little amount of time to make sure the last drawpart has already fired PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005)); break; + case MCH_EGA: + PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrend); + PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005)); + break; default: E_Exit("This new machine needs implementation in VGA_VerticalTimer too."); break; @@ -798,7 +773,11 @@ static void VGA_VerticalTimer(Bitu /*val*/) { vga.draw.address = vga.config.real_start; vga.draw.byte_panning_shift = 0; // go figure... - if (machine==MCH_EGA) vga.draw.split_line*=2; + if (machine==MCH_EGA) { + if (vga.draw.doubleheight) // Spacepigs EGA Megademo + vga.draw.split_line*=2; + vga.draw.split_line++; // EGA adds one buggy scanline + } // if (machine==MCH_EGA) vga.draw.split_line = ((((vga.config.line_compare&0x5ff)+1)*2-1)/vga.draw.lines_scaled); #ifdef VGA_KEEP_CHANGES bool startaddr_changed=false; @@ -811,13 +790,13 @@ static void VGA_VerticalTimer(Bitu /*val*/) { vga.draw.byte_panning_shift = 8; vga.draw.address += vga.draw.bytes_skip; vga.draw.address *= vga.draw.byte_panning_shift; - vga.draw.address += vga.draw.panning; + if (machine!=MCH_EGA) vga.draw.address += vga.draw.panning; #ifdef VGA_KEEP_CHANGES startaddr_changed=true; #endif break; case M_VGA: - if(vga.config.compatible_chain4 && (vga.crtc.underline_location & 0x40)) { + if (vga.config.compatible_chain4 && (vga.crtc.underline_location & 0x40)) { vga.draw.linear_base = vga.fastmem; vga.draw.linear_mask = 0xffff; } else { @@ -851,6 +830,10 @@ static void VGA_VerticalTimer(Bitu /*val*/) { /* check for blinking and blinking change delay */ FontMask[1]=(vga.draw.blinking & (vga.draw.cursor.count >> 4)) ? 0 : 0xffffffff; + /* if blinking is enabled, 'blink' will toggle between true + * and false. Otherwise it's true */ + vga.draw.blink = ((vga.draw.blinking & (vga.draw.cursor.count >> 4)) + || !vga.draw.blinking) ? true:false; break; case M_HERC_GFX: break; @@ -889,16 +872,19 @@ static void VGA_VerticalTimer(Bitu /*val*/) { PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts + draw_skip,vga.draw.parts_lines); break; case LINE: + case EGALINE: if (GCC_UNLIKELY(vga.draw.lines_done < vga.draw.lines_total)) { LOG(LOG_VGAMISC,LOG_NORMAL)( "Lines left: %d", vga.draw.lines_total-vga.draw.lines_done); - PIC_RemoveEvents(VGA_DrawSingleLine); + if (vga.draw.mode==EGALINE) PIC_RemoveEvents(VGA_DrawEGASingleLine); + else PIC_RemoveEvents(VGA_DrawSingleLine); RENDER_EndUpdate(true); } vga.draw.lines_done = 0; - PIC_AddEvent(VGA_DrawSingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip)); + if (vga.draw.mode==EGALINE) + PIC_AddEvent(VGA_DrawEGASingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip)); + else PIC_AddEvent(VGA_DrawSingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip)); break; - //case EGALINE: } } @@ -982,6 +968,10 @@ void VGA_SetupDrawing(Bitu /*val*/) { case MCH_PCJR: vga.draw.mode = LINE; break; + case MCH_EGA: + // Note: The Paradise SVGA uses the same panning mechanism as EGA + vga.draw.mode = EGALINE; + break; case MCH_VGA: if (svgaCard==SVGA_None) { vga.draw.mode = LINE; @@ -1077,13 +1067,13 @@ void VGA_SetupDrawing(Bitu /*val*/) { htotal*=2; } vga.draw.address_line_total=(vga.crtc.maximum_scan_line&0x1f)+1; - if(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA)) { + if (IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA)) { // vgaonly; can't use with CGA because these use address_line for their // own purposes. // Set the low resolution modes to have as many lines as are scanned - // Quite a few demos change the max_scanline register at display time // to get SFX: Majic12 show, Magic circle, Copper, GBU, Party91 - if( vga.crtc.maximum_scan_line&0x80) vga.draw.address_line_total*=2; + if ( vga.crtc.maximum_scan_line&0x80) vga.draw.address_line_total*=2; vga.draw.double_scan=false; } else if (IS_VGA_ARCH) vga.draw.double_scan=(vga.crtc.maximum_scan_line&0x80)>0; @@ -1155,10 +1145,10 @@ void VGA_SetupDrawing(Bitu /*val*/) { // on blanking wrap to 0, the first line is not blanked // this is used by the S3 BIOS and other S3 drivers in some SVGA modes - if((vbend&0x7f)==1) vblank_skip = 0; + if ((vbend&0x7f)==1) vblank_skip = 0; // it might also cut some lines off the bottom - if(vbstart < vdend) { + if (vbstart < vdend) { vdend = vbstart; } LOG(LOG_VGA,LOG_WARN)("Blanking wrap to line %d", vblank_skip); @@ -1167,7 +1157,7 @@ void VGA_SetupDrawing(Bitu /*val*/) { vblank_skip = vbend; LOG(LOG_VGA,LOG_WARN)("Upper %d lines of the screen blanked", vblank_skip); } else if (vbstart < vdend) { - if(vbend < vdend) { + if (vbend < vdend) { // the game wants a black bar somewhere on the screen LOG(LOG_VGA,LOG_WARN)("Unsupported blanking: line %d-%d",vbstart,vbend); } else { @@ -1266,7 +1256,7 @@ void VGA_SetupDrawing(Bitu /*val*/) { case M_LIN8: if (vga.crtc.mode_control & 0x8) width >>=1; - else if(svgaCard == SVGA_S3Trio && !(vga.s3.reg_3a&0x10)) { + else if (svgaCard == SVGA_S3Trio && !(vga.s3.reg_3a&0x10)) { doublewidth=true; width >>=1; } @@ -1300,6 +1290,7 @@ void VGA_SetupDrawing(Bitu /*val*/) { vga.draw.blocks = width; width<<=3; if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) { + // This would also be required for EGA in Spacepigs Megademo bpp=16; VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line; } else VGA_DrawLine=VGA_Draw_Linear_Line; @@ -1329,17 +1320,22 @@ void VGA_SetupDrawing(Bitu /*val*/) { aspect_ratio=1.0; vga.draw.blocks=width; doublewidth=(vga.seq.clocking_mode & 0x8) > 0; - if ((IS_VGA_ARCH) && (svgaCard==SVGA_None) && !(vga.seq.clocking_mode&0x01)) { - width*=9; /* 9 bit wide text font */ - VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line_9; + if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) { + // vgaonly: allow 9-pixel wide fonts + if (vga.seq.clocking_mode&0x01) { + vga.draw.char9dot = false; + width*=8; + } else { + vga.draw.char9dot = true; + width*=9; + } + VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line; bpp=16; -// VGA_DrawLine=VGA_TEXT_Draw_Line_9; } else { - width<<=3; /* 8 bit wide text font */ - if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) { - VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line; - bpp=16; - } else VGA_DrawLine=VGA_TEXT_Draw_Line; + // not vgaonly: force 8-pixel wide fonts + width*=8; // 8 bit wide text font + vga.draw.char9dot = false; + VGA_DrawLine=VGA_TEXT_Draw_Line; } break; case M_HERC_GFX: @@ -1417,7 +1413,7 @@ void VGA_SetupDrawing(Bitu /*val*/) { } vga.draw.vblank_skip = vblank_skip; - if(!(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA))) { + if (!(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA))) { //Only check for extra double height in vga modes //(line multiplying by address_line_total) if (!doubleheight && (vga.mode 0.0001) { + fps_changed = true; vga.draw.delay.vtotal = 1000.0 / fps; VGA_KillDrawing(); PIC_RemoveEvents(VGA_Other_VertInterrupt); @@ -1470,7 +1468,7 @@ void VGA_SetupDrawing(Bitu /*val*/) { (vga.draw.doublewidth != doublewidth) || (vga.draw.doubleheight != doubleheight) || (fabs(aspect_ratio - vga.draw.aspect_ratio) > 0.0001) || - (vga.draw.bpp != bpp)) { + (vga.draw.bpp != bpp) || fps_changed) { VGA_KillDrawing(); @@ -1494,6 +1492,7 @@ void VGA_SetupDrawing(Bitu /*val*/) { void VGA_KillDrawing(void) { PIC_RemoveEvents(VGA_DrawPart); PIC_RemoveEvents(VGA_DrawSingleLine); + PIC_RemoveEvents(VGA_DrawEGASingleLine); vga.draw.parts_left = 0; vga.draw.lines_done = ~0; RENDER_EndUpdate(true); diff --git a/src/hardware/vga_other.cpp b/src/hardware/vga_other.cpp index 710b6c0..7fd1829 100644 --- a/src/hardware/vga_other.cpp +++ b/src/hardware/vga_other.cpp @@ -516,7 +516,12 @@ static void write_hercules(Bitu port,Bitu val,Bitu /*iolen*/) { break; } case 0x3bf: - vga.herc.enable_bits=(Bit8u)val; + if ( vga.herc.enable_bits ^ val) { + vga.herc.enable_bits=val; + // Bit 1 enables the upper 32k of video memory, + // so update the handlers + VGA_SetupHandlers(); + } break; } } diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index a61bfe5..d1e6233 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -869,7 +869,7 @@ public: if (IS_TANDY_ARCH) { /* reduce reported memory size for the Tandy (32k graphics memory at the end of the conventional 640k) */ - if (machine==MCH_TANDY) mem_writew(BIOS_MEMORY_SIZE,608); + if (machine==MCH_TANDY) mem_writew(BIOS_MEMORY_SIZE,624); else mem_writew(BIOS_MEMORY_SIZE,640); mem_writew(BIOS_TRUE_MEMORY_SIZE,640); } else mem_writew(BIOS_MEMORY_SIZE,640); diff --git a/src/ints/int10.cpp b/src/ints/int10.cpp index b5b3abe..fed4a7d 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -138,8 +138,7 @@ static Bitu INT10_Handler(void) { reg_ah=(Bit8u)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); break; case 0x10: /* Palette functions */ - if ((machine==MCH_CGA) || ((!IS_VGA_ARCH) && (reg_al>0x02))) break; - //TODO: subfunction 0x03 for ega + if ((machine==MCH_CGA) || ((!IS_VGA_ARCH) && (reg_al>0x03))) break; switch (reg_al) { case 0x00: /* SET SINGLE PALETTE REGISTER */ INT10_SetSinglePaletteRegister(reg_bl,reg_bh); @@ -302,13 +301,8 @@ graphics_chars: break; } if ((reg_bh<=7) || (svgaCard==SVGA_TsengET4K)) { - if (machine==MCH_EGA) { - reg_cx=0x0e; - reg_dl=0x18; - } else { - reg_cx=real_readw(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); - reg_dl=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS); - } + reg_cx=real_readw(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); + reg_dl=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS); } break; default: diff --git a/src/ints/int10_memory.cpp b/src/ints/int10_memory.cpp index 789d52a..646894f 100644 --- a/src/ints/int10_memory.cpp +++ b/src/ints/int10_memory.cpp @@ -66,9 +66,21 @@ void INT10_LoadFont(PhysPt font,bool reload,Bitu count,Bitu offset,Bitu map,Bitu Bit16u base=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); IO_Write(base,0x9); IO_Write(base+1,(IO_Read(base+1) & 0xe0)|(height-1)); - //Vertical display end bios says, but should stay the same? + // Vertical display end bios says, but should stay the same? + // Not on EGA. + Bitu rows = CurMode->sheight/height; + if (machine==MCH_EGA) { + Bitu displayend = rows*height - 1; + IO_Write(base,0x12); + IO_Write(base+1,(Bit8u)(displayend & 0xff)); + IO_Write(base,0x7); + // Note: IBM EGA registers can't be read + Bitu v_overflow = IO_Read(base+1) & ~0x2; + if (displayend & 0x100) v_overflow |= 0x2; + IO_Write(base+1,(Bit8u)v_overflow); + } //Rows setting in bios segment - real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,(CurMode->sheight/height)-1); + real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,rows-1); real_writeb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,(Bit8u)height); //TODO Reprogram cursor size? } diff --git a/src/ints/int10_pal.cpp b/src/ints/int10_pal.cpp index e9ff967..266ac26 100644 --- a/src/ints/int10_pal.cpp +++ b/src/ints/int10_pal.cpp @@ -96,25 +96,42 @@ void INT10_SetAllPaletteRegisters(PhysPt data) { } void INT10_ToggleBlinkingBit(Bit8u state) { - Bit8u value; -// state&=0x01; - if ((state>1) && (svgaCard==SVGA_S3Trio)) return; - ResetACTL(); - - IO_Write(VGAREG_ACTL_ADDRESS,0x10); - value=IO_Read(VGAREG_ACTL_READ_DATA); - if (state<=1) { - value&=0xf7; - value|=state<<3; - } + if(IS_VGA_ARCH) { + Bit8u value; + // state&=0x01; + if ((state>1) && (svgaCard==SVGA_S3Trio)) return; + ResetACTL(); + + IO_Write(VGAREG_ACTL_ADDRESS,0x10); + value=IO_Read(VGAREG_ACTL_READ_DATA); + if (state<=1) { + value&=0xf7; + value|=state<<3; + } - ResetACTL(); - IO_Write(VGAREG_ACTL_ADDRESS,0x10); - IO_Write(VGAREG_ACTL_WRITE_DATA,value); - IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette + ResetACTL(); + IO_Write(VGAREG_ACTL_ADDRESS,0x10); + IO_Write(VGAREG_ACTL_WRITE_DATA,value); + IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette - if (state<=1) { - Bit8u msrval=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR)&0xdf; + if (state<=1) { + Bit8u msrval=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR)&0xdf; + if (state) msrval|=0x20; + real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,msrval); + } + } else { // EGA + // Usually it reads this from the mode list in ROM + if (CurMode->type!=M_TEXT) return; + + Bit8u value = (CurMode->cwidth==9)? 0x4:0x0; + if (state) value |= 0x8; + + ResetACTL(); + IO_Write(VGAREG_ACTL_ADDRESS,0x10); + IO_Write(VGAREG_ACTL_WRITE_DATA,value); + IO_Write(VGAREG_ACTL_ADDRESS,0x20); + + Bit8u msrval=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR)& ~0x20; if (state) msrval|=0x20; real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,msrval); } diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index 1fe2c16..616d1b1 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -490,7 +490,7 @@ void SHELL_Init() { MSG_Add("SHELL_CMD_PAUSE_HELP","Waits for 1 keystroke to continue.\n"); MSG_Add("SHELL_CMD_COPY_FAILURE","Copy failure : %s.\n"); MSG_Add("SHELL_CMD_COPY_SUCCESS"," %d File(s) copied.\n"); - MSG_Add("SHELL_CMD_SUBST_NO_REMOVE","Removing drive not supported. Doing nothing.\n"); + MSG_Add("SHELL_CMD_SUBST_NO_REMOVE","Unable to remove, drive not in use.\n"); MSG_Add("SHELL_CMD_SUBST_FAILURE","SUBST failed. You either made an error in your commandline or the target drive is already used.\nIt's only possible to use SUBST on Local drives"); #ifdef HW_RVL diff --git a/src/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index 49ff827..8a0a9c0 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -945,17 +945,22 @@ void DOS_Shell::CMD_SUBST (char * args) { CommandLine command(0,args); if (command.GetCount() != 2) throw 0 ; - command.FindCommand(2,arg); - if((arg=="/D" ) || (arg=="/d")) throw 1; //No removal (one day) command.FindCommand(1,arg); if( (arg.size()>1) && arg[1] !=':') throw(0); temp_str[0]=(char)toupper(args[0]); + command.FindCommand(2,arg); + if((arg=="/D") || (arg=="/d")) { + if(!Drives[temp_str[0]-'A'] ) throw 1; //targetdrive not in use + strcat(mountstring,"-u "); + strcat(mountstring,temp_str); + this->ParseLine(mountstring); + return; + } if(Drives[temp_str[0]-'A'] ) throw 0; //targetdrive in use strcat(mountstring,temp_str); strcat(mountstring," "); - command.FindCommand(2,arg); Bit8u drive;char fulldir[DOS_PATHLENGTH]; if (!DOS_MakeName(const_cast(arg.c_str()),fulldir,&drive)) throw 0;