diff --git a/README b/README index e5eb85c..bd3fcbb 100644 --- a/README +++ b/README @@ -139,7 +139,7 @@ Type INTRO in DOSBox for a quick tour. It is essential that you get familiar with the idea of mounting, DOSBox does not automatically make any drive (or a part of it) accessible to the emulation. See the FAQ entry "How to start?" as well as the description of the MOUNT command -(section 4: "Internal Programs"). If you have your game on a cdrom you may try +(Section 4: "Internal Programs"). If you have your game on a cdrom you may try this guide: http://vogons.zetafleet.com/viewtopic.php?t=8933 @@ -185,7 +185,7 @@ START: How to start? AUTOMATION: Do I always have to type these commands? In the DOSBox configuration file is an [autoexec] section. The commands present there are run when DOSBox starts, so you can use this section - for the mounting. Look at Section 13: The configuration (options) file + for the mounting. Look at Section 13: "The configuration (options) file". FULLSCREEN: How do I change to fullscreen? @@ -313,11 +313,12 @@ SOUND: What sound hardware does DOSBox presently emulate? SOUND: The sound stutters or sounds stretched/weird. You may be using too much CPU power to keep DOSBox running at the current speed. You can lower the cycles, skip frames, reduce the sampling rate of - the respective sound device, increase the prebuffer. See section 13: "The - configuration (options) file" - If you are using cycles=max or =auto, then make sure that there is no - background processes interfering! (especially if they access the harddisk) - Also look at Section 10. "How to speed up/slow down DOSBox" + the respective sound device, increase the prebuffer. See Section 13: "The + configuration (options) file". + If you are using 'cycles=max' or 'cycles=auto', then make sure that there is + no background processes interfering! (especially if they access the harddisk) + Also look at Section 10: "How to speed up/slow down DOSBox" as well as + Section 11: "Troubleshooting". KEYBOARD: I can't type \ or : in DOSBox. @@ -326,7 +327,7 @@ KEYBOARD: I can't type \ or : in DOSBox. detected), or the key mapping is wrong. Some possible fixes: 1. Use / instead, or ALT-58 for : and ALT-92 for \. - 2. Change the DOS keyboard layout (see Section 8: Keyboard Layout). + 2. Change the DOS keyboard layout (see Section 8: "Keyboard Layout"). 3. Add the commands you want to execute to the [autoexec] section of the DOSBox configuration file. 4. Open the DOSBox configuration file and change the usescancodes entry. @@ -367,16 +368,16 @@ CONTROL: The character/cursor/mouse pointer always moves into one direction! SPEED: The game/application runs much too slow/too fast! - Look at the section 10: "How to speed up/slow down DOSBox" for more + Look at Section 10: "How to speed up/slow down DOSBox" for more information. CRASH: The game/application does not run at all/crashes! - Look at Section 11: Troubleshooting + Look at Section 11: "Troubleshooting". CRASH: DOSBox crashes on startup!. - Look at Section 11: Troubleshooting + Look at Section 11: "Troubleshooting". GAME: My Build game(Duke3D/Blood/Shadow Warrior) has problems. @@ -395,7 +396,7 @@ SAFETY: Can DOSBox harm my computer? OPTIONS: I would like to change DOSBox's options. - Look at Section 13. "The configuration (options) file" + Look at Section 13: "The configuration (options) file". HELP: Great Manual, but I still don't get it. @@ -412,7 +413,7 @@ HELP: Great Manual, but I still don't get it. An overview of the command line options you can give to DOSBox. Although in most cases it is easier to use DOSBox's configuration file instead. -See: Section 13. "The configuration (options) file" +See Section 13: "The configuration (options) file". To be able to use Command Line Parameters: (Windows) open cmd.exe or command.com or edit the shortcut to dosbox.exe @@ -461,11 +462,11 @@ dosbox -erasemapper -conf configfilelocation Start DOSBox with the options specified in "configfilelocation". Multiple -conf options may be present. - See Section 13 for more details. + See Section 13: "The configuration (options) file" for more details. -lang languagefilelocation Start DOSBox using the language specified in "languagefilelocation". - See Section 14 for more details. + See Section 14: "The Language File" for more details. -machine machinetype Setup DOSBox to emulate a specific type of machine. Valid choices are: @@ -763,8 +764,8 @@ CONFIG -get "section property" config -writeconf c:\dosgames\dosbox.conf 2. To set the cpu cycles to 10000: config -set "cpu cycles=10000" - 3. To turn ems memory emulation off: - config -set "dos ems=off" + 3. To turn EMS memory emulation off: + config -set "dos ems=false" 4. To check which cpu core is being used. config -get "cpu core" @@ -1015,7 +1016,7 @@ IPX KEYB [keyboardlayoutcode [codepage [codepagefile]]] Change the keyboard layout. For detailed information about keyboard layouts - please see Section 8: "Keyboard Layout" + please see Section 8: "Keyboard Layout". [keyboardlayoutcode] is a string consisting of five or less characters, examples are PL214 (Polish typists) or PL457 (Polish programmers). @@ -1092,7 +1093,7 @@ F11 (machine=hercules) cycle through amber, green, white colouring*** a different machine type. So either reassign them or reset the mapper. These are the default keybindings. They can be changed in the keymapper -(see Section 7: KeyMapper). +(see Section 7: "KeyMapper"). In MAC OS you can try using cmd(applekey) together with Ctrl if the key doesn't work eg. cmd-ctrl-F1, but some keys may still need remapping (in Linux too). @@ -1146,8 +1147,8 @@ inside DOSBox, try different 'timed' setting in DOSBox's configuration file. 7. KeyMapper: ============= -You start the DOSBox mapper either with CTRL-F1 (see section 5. Special Keys) -or -startmapper (see Section 3. Command Line Parameters). +You start the DOSBox mapper either with CTRL-F1 (see Section 5: "Special Keys") +or -startmapper (see Section 3: "Command Line Parameters"). You are presented with a virtual keyboard and a virtual joystick. These virtual devices correspond to the keys and events DOSBox will @@ -1241,9 +1242,9 @@ your mapperfile, if it is present in the DOSBox configuration file. To switch to a different keyboard layout, either the entry "keyboardlayout" in the [dos] section of the DOSBox configuration file can be used, or the -internal DOSBox program keyb.com (Section 4: Internal Programs) -Both accept DOS conforming language codes (see below), -but only by using keyb.com a custom codepage can be specified. +internal DOSBox program keyb.com (Section 4: "Internal Programs"). Both accept +DOS conforming language codes (see below), but only by using keyb.com a +custom codepage can be specified. The default keyboardlayout=auto currently works under windows only. The language is chosen according to the OS language, but the keyboard layout is not detected. @@ -1357,8 +1358,8 @@ CPU Cycles (speed up/slow down) a different setting in the DOSBox's configuration file. You can force the slow or fast behavior by setting a fixed amount of cycles - in the DOSBox's configuration file. If you for example set cycles=10000, then - DOSBox window will display a line "Cpu Speed: fixed 10000 cycles" at the top. + in the DOSBox's configuration file. If you set for example cycles=10000, the + DOSBox window will display a line "CPU speed: fixed 10000 cycles" at the top. In this mode you can reduce the amount of cycles even more by hitting CTRL-F11 (you can go as low as you want) or raise it by hitting CTRL-F12 as much as you want, but you will be limited by the power of one core of your computer's CPU. @@ -1373,8 +1374,8 @@ CPU Cycles (speed up/slow down) You can also force the fast behavior by setting cycles=max in the DOSBox configuration file. The DOSBox window will display a line - "Cpu Speed: max 100% cycles" at the top then. This time you won't have to care - how much free time your real CPU's cores have, because DOSBox will always use + "CPU speed: max 100% cycles" at the top then. This time you won't have to care + how much free time your real CPU cores have, because DOSBox will always use 100% of your real CPU's one core. In this mode you can reduce the amount of your real CPU's core usage by CTRL-F11 or raise it with CTRL-F12. @@ -1424,7 +1425,7 @@ Example: ==================== General tip: - Check messages in DOSBox Status Window. See section 12. "DOSBox Status Window" + Check messages in DOSBox Status Window. See Section 12: "DOSBox Status Window". DOSBox crashes right after starting it: - use different values for the output= entry in your DOSBox diff --git a/include/dma.h b/include/dma.h index a12615d..acf724e 100644 --- a/include/dma.h +++ b/include/dma.h @@ -114,6 +114,8 @@ DmaChannel * GetDMAChannel(Bit8u chan); void CloseSecondDMAController(void); bool SecondDMAControllerAvailable(void); +void DMA_SetWrapping(Bitu wrap); + static Bit32u dma_wrapping = 0xffff; #endif diff --git a/src/dosbox.cpp b/src/dosbox.cpp index b0b07aa..998a382 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -338,7 +338,7 @@ void DOSBOX_Init(void) { const char* machines[] = { "hercules", "cga", "tandy", "pcjr", "ega", "vgaonly", "svga_s3", "svga_et3000", "svga_et4000", - "svga_paradise", "vesa_nolfb", "vesa_oldvbe", 0 }; + "svga_paradise", "vesa_nolfb", "vesa_oldvbe", 0 }; secprop=control->AddSection_prop("dosbox",&DOSBOX_RealInit); Pstring = secprop->Add_path("language",Property::Changeable::Always,""); Pstring->Set_help("Select another language file."); @@ -681,8 +681,13 @@ void DOSBOX_Init(void) { Pbool->Set_help("Enable XMS support."); secprop->AddInitFunction(&EMS_Init,true);//done - Pbool = secprop->Add_bool("ems",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Enable EMS support."); + const char* ems_settings[] = { "true", "emsboard", "emm386", "false", 0}; + Pstring = secprop->Add_string("ems",Property::Changeable::WhenIdle,"true"); + Pstring->Set_values(ems_settings); + Pstring->Set_help("Enable EMS support. The default (=true) provides the best\n" + "compatibility but certain applications may run better with\n" + "other choices, or require EMS support to be disabled (=false)\n" + "to work at all."); Pbool = secprop->Add_bool("umb",Property::Changeable::WhenIdle,true); Pbool->Set_help("Enable UMB support."); diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 1188837..9e3ddf9 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -239,9 +239,9 @@ void GFX_SetTitle(Bit32s cycles,Bits frameskip,bool paused){ if(cycles != -1) internal_cycles = cycles; if(frameskip != -1) internal_frameskip = frameskip; if(CPU_CycleAutoAdjust) { - sprintf(title,"DOSBox %s, Cpu speed: max %3d%% cycles, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram); + sprintf(title,"DOSBox %s, CPU speed: max %3d%% cycles, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram); } else { - sprintf(title,"DOSBox %s, Cpu speed: %8d cycles, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram); + sprintf(title,"DOSBox %s, CPU speed: %8d cycles, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram); } if(paused) strcat(title," PAUSED"); diff --git a/src/hardware/dma.cpp b/src/hardware/dma.cpp index 542f596..9bc041e 100644 --- a/src/hardware/dma.cpp +++ b/src/hardware/dma.cpp @@ -48,7 +48,9 @@ static void DMA_BlockRead(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8u offset <<= dma16; Bit32u dma_wrap = ((0xffff<(dma_wrapping<(dma_wrapping<> 12); /* care for EMS pageframe etc. */ @@ -67,7 +69,9 @@ static void DMA_BlockWrite(PhysPt spage,PhysPt offset,void * data,Bitu size,Bit8 offset <<= dma16; Bit32u dma_wrap = ((0xffff<(dma_wrapping<(dma_wrapping<> 12); /* care for EMS pageframe etc. */ diff --git a/src/hardware/hardware.cpp b/src/hardware/hardware.cpp index 42570b2..e739bef 100644 --- a/src/hardware/hardware.cpp +++ b/src/hardware/hardware.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: hardware.cpp,v 1.23 2009-10-11 18:09:22 qbix79 Exp $ */ +/* $Id: hardware.cpp,v 1.22 2009-04-26 18:24:36 qbix79 Exp $ */ #include #include @@ -161,13 +161,17 @@ static void CAPTURE_AddAviChunk(const char * tag, Bit32u size, void * data, Bit3 #endif #if (C_SSHOT) +static void CAPTURE_VideoEvent(bool pressed) { + if (!pressed) + return; + if (CaptureState & CAPTURE_VIDEO) { + /* Close the video */ + CaptureState &= ~CAPTURE_VIDEO; + LOG_MSG("Stopped capturing video."); -static void CAPTURE_VideoHeader() { Bit8u avi_header[AVI_HEADER_SIZE]; Bitu main_list; Bitu header_pos=0; - Bitu save_pos=ftell(capture.video.handle); - #define AVIOUT4(_S_) memcpy(&avi_header[header_pos],_S_,4);header_pos+=4; #define AVIOUTw(_S_) host_writew(&avi_header[header_pos], _S_);header_pos+=2; #define AVIOUTd(_S_) host_writed(&avi_header[header_pos], _S_);header_pos+=4; @@ -284,20 +288,6 @@ static void CAPTURE_VideoHeader() { fwrite( capture.video.index, 1, capture.video.indexused, capture.video.handle); fseek(capture.video.handle, 0, SEEK_SET); fwrite(&avi_header, 1, AVI_HEADER_SIZE, capture.video.handle); - fseek(capture.video.handle, save_pos, SEEK_SET); -} - -static void CAPTURE_VideoEvent(bool pressed) { - if (!pressed) - return; - if (CaptureState & CAPTURE_VIDEO) { - /* Close the video */ - CaptureState &= ~CAPTURE_VIDEO; - LOG_MSG("Stopped capturing video."); - - /* Adds AVI header to the file */ - CAPTURE_VideoHeader(); - fclose( capture.video.handle ); free( capture.video.index ); free( capture.video.buf ); @@ -557,9 +547,6 @@ skip_shot: capture.video.audioused = 0; } - /* Adds AVI header to the file */ - CAPTURE_VideoHeader(); - /* Everything went okay, set flag again for next frame */ CaptureState |= CAPTURE_VIDEO; } @@ -756,6 +743,9 @@ public: #endif } ~HARDWARE(){ +#if (C_SSHOT) + if (capture.video.handle) CAPTURE_VideoEvent(true); +#endif if (capture.wave.handle) CAPTURE_WaveEvent(true); if (capture.midi.handle) CAPTURE_MidiEvent(true); } diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index c533042..72c7df3 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -118,30 +118,30 @@ static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) { static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart, Bitu line) { const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift); - Bit32u * draw=(Bit32u *)TempLine; - for (Bitu x=0;x> 4 | - (val2 & 0x0f) << 24 | - (val2 & 0xf0) << 12; + Bit8u* draw=TempLine; + Bitu end = vga.draw.blocks*2; + while(end) { + Bit8u byte = base[vidstart & vga.tandy.addr_mask]; + *draw++=vga.attr.palette[byte >> 4]; + *draw++=vga.attr.palette[byte & 0x0f]; + vidstart++; + end--; } return TempLine; } static Bit8u * VGA_Draw_4BPP_Line_Double(Bitu vidstart, Bitu line) { const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift); - Bit32u * draw=(Bit32u *)TempLine; - for (Bitu x=0;x> 4 | - (val & 0xf0) << 4 | - (val & 0x0f) << 16 | - (val & 0x0f) << 24; + Bit8u* draw=TempLine; + Bitu end = vga.draw.blocks; + while(end) { + Bit8u byte = base[vidstart & vga.tandy.addr_mask]; + Bit8u data = vga.attr.palette[byte >> 4]; + *draw++ = data; *draw++ = data; + data = vga.attr.palette[byte & 0x0f]; + *draw++ = data; *draw++ = data; + vidstart++; + end--; } return TempLine; } @@ -175,12 +175,28 @@ static Bit8u * VGA_Draw_Changes_Line(Bitu vidstart, Bitu line) { #endif static Bit8u * VGA_Draw_Linear_Line(Bitu vidstart, Bitu /*line*/) { -// There is guaranteed extra memory past the wrap boundary. So, instead of using temporary -// storage just copy appropriate chunk from the beginning to the wrap boundary when needed. Bitu offset = vidstart & vga.draw.linear_mask; - 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 ]; + Bit8u* ret = &vga.draw.linear_base[offset]; + + // in case (vga.draw.line_length + offset) has bits set that + // are not set in the mask: ((x|y)!=y) equals (x&~y) + if (GCC_UNLIKELY((vga.draw.line_length + offset)& ~vga.draw.linear_mask)) { + // this happens, if at all, only once per frame (1 of 480 lines) + // in some obscure games + Bitu end = (offset + vga.draw.line_length) & vga.draw.linear_mask; + + // assuming lines not longer than 4096 pixels + Bitu wrapped_len = end & 0xFFF; + Bitu unwrapped_len = vga.draw.line_length-wrapped_len; + + // unwrapped chunk: to top of memory block + memcpy(TempLine, &vga.draw.linear_base[offset], unwrapped_len); + // wrapped chunk: from base of memory block + memcpy(&TempLine[unwrapped_len], vga.draw.linear_base, wrapped_len); + + ret = TempLine; + } + #if !defined(C_UNALIGNED_MEMORY) if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) { memcpy( TempLine, ret, vga.draw.line_length ); @@ -589,10 +605,60 @@ static void VGA_ProcessSplit() { vga.draw.address_line=0; } +static Bit8u bg_color_index = 0; // screen-off black index static void VGA_DrawSingleLine(Bitu /*blah*/) { if (GCC_UNLIKELY(vga.attr.disabled)) { - // draw blanked line (DoWhackaDo, Alien Carnage, TV sports Football) - memset(TempLine, 0, sizeof(TempLine)); + switch(machine) { + case MCH_PCJR: + // Displays the border color when screen is disabled + bg_color_index = vga.tandy.border_color; + break; + case MCH_TANDY: + // Either the PCJr way or the CGA way + if (vga.tandy.gfx_control& 0x4) { + bg_color_index = vga.tandy.border_color; + } else if (vga.mode==M_TANDY4) + bg_color_index = vga.attr.palette[0]; + else bg_color_index = 0; + break; + case MCH_CGA: + // the background color + bg_color_index = vga.attr.overscan_color; + break; + case MCH_EGA: + case MCH_VGA: + // DoWhackaDo, Alien Carnage, TV sports Football + // when disabled by attribute index bit 5: + // ET3000, ET4000, Paradise display the border color + // S3 displays the content of the currently selected attribute register + // when disabled by sequencer the screen is black "257th color" + + // the DAC table may not match the bits of the overscan register + // so use black for this case too... + //if (vga.attr.disabled& 2) { + if (vga.dac.xlat16[bg_color_index] != 0) { + for(Bitu i = 0; i < 256; i++) + if (vga.dac.xlat16[i] == 0) { + bg_color_index = i; + break; + } + } + //} else + // bg_color_index = vga.attr.overscan_color; + break; + default: + bg_color_index = 0; + break; + } + if (vga.draw.bpp==8) { + memset(TempLine, bg_color_index, sizeof(TempLine)); + } else if (vga.draw.bpp==16) { + Bit16u* wptr = (Bit16u*) TempLine; + Bit16u value = vga.dac.xlat16[bg_color_index]; + for (Bitu i = 0; i < sizeof(TempLine)/2; i++) { + wptr[i] = value; + } + } RENDER_DrawLine(TempLine); } else { Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line ); @@ -966,6 +1032,7 @@ void VGA_SetupDrawing(Bitu /*val*/) { switch (machine) { case MCH_CGA: case MCH_PCJR: + case MCH_TANDY: vga.draw.mode = LINE; break; case MCH_EGA: diff --git a/src/hardware/vga_other.cpp b/src/hardware/vga_other.cpp index 7fd1829..c6cd613 100644 --- a/src/hardware/vga_other.cpp +++ b/src/hardware/vga_other.cpp @@ -153,6 +153,27 @@ static Bitu read_crtc_data_other(Bitu /*port*/,Bitu /*iolen*/) { return (Bitu)(~0); } +static void write_lightpen(Bitu port,Bitu val,Bitu) { + switch (port) { + case 0x3db: // Clear lightpen latch + vga.other.lightpen_triggered = false; + break; + case 0x3dc: // Preset lightpen latch + if (!vga.other.lightpen_triggered) { + vga.other.lightpen_triggered = true; // TODO: this shows at port 3ba/3da bit 1 + + double timeInFrame = PIC_FullIndex()-vga.draw.delay.framestart; + double timeInLine = fmod(timeInFrame,vga.draw.delay.htotal); + Bitu current_scanline = (Bitu)(timeInFrame / vga.draw.delay.htotal); + + vga.other.lightpen = (Bit16u)((vga.draw.address_add/2) * (current_scanline/2)); + vga.other.lightpen += (Bit16u)((timeInLine / vga.draw.delay.hdend) * + ((float)(vga.draw.address_add/2))); + } + break; + } +} + static double hue_offset = 0.0; static Bit8u cga16_val = 0; static void update_cga16_color(void); @@ -235,56 +256,139 @@ static void DecreaseHue(bool pressed) { LOG_MSG("Hue at %f",hue_offset); } -static void write_color_select(Bit8u val) { +static void write_cga_color_select(Bitu val) { vga.tandy.color_select=val; - switch (vga.mode) { + switch(vga.mode) { + case M_TANDY4: { + Bit8u base = (val & 0x10) ? 0x08 : 0; + Bit8u bg = val & 0xf; + if (vga.tandy.mode_control & 0x4) // cyan red white + VGA_SetCGA4Table(bg, 3+base, 4+base, 7+base); + else if (val & 0x20) // cyan magenta white + VGA_SetCGA4Table(bg, 3+base, 5+base, 7+base); + else // green red brown + VGA_SetCGA4Table(bg, 2+base, 4+base, 6+base); + vga.tandy.border_color = bg; + vga.attr.overscan_color = bg; + break; + } case M_TANDY2: VGA_SetCGA2Table(0,val & 0xf); - break; - case M_TANDY4: - { - if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) || - (machine==MCH_PCJR && (vga.tandy.mode_control==0x0b))) { - VGA_SetCGA4Table(0,1,2,3); - return; - } - Bit8u base=(val & 0x10) ? 0x08 : 0; - /* Check for BW Mode */ - if (vga.tandy.mode_control & 0x4) { - VGA_SetCGA4Table(val & 0xf,3+base,4+base,7+base); - } else { - if (val & 0x20) VGA_SetCGA4Table(val & 0xf,3+base,5+base,7+base); - else VGA_SetCGA4Table(val & 0xf,2+base,4+base,6+base); - } - } + vga.attr.overscan_color = 0; break; case M_CGA16: cga16_color_select(val); break; case M_TEXT: - case M_TANDY16: + vga.tandy.border_color = val & 0xf; + vga.attr.overscan_color = 0; break; } } -static void TANDY_FindMode(void) { - if (vga.tandy.mode_control & 0x2) { - if (vga.tandy.gfx_control & 0x10) - VGA_SetMode(M_TANDY16); - else if (vga.tandy.gfx_control & 0x08) - VGA_SetMode(M_TANDY4); - else if (vga.tandy.mode_control & 0x10) - VGA_SetMode(M_TANDY2); - else - VGA_SetMode(M_TANDY4); - write_color_select(vga.tandy.color_select); +static void write_cga(Bitu port,Bitu val,Bitu /*iolen*/) { + switch (port) { + case 0x3d8: + vga.tandy.mode_control=(Bit8u)val; + vga.attr.disabled = (val&0x8)? 0: 1; + if (vga.tandy.mode_control & 0x2) { // graphics mode + if (vga.tandy.mode_control & 0x10) {// highres mode + if (!(val & 0x4)) { // burst on + VGA_SetMode(M_CGA16); // composite ntsc 160x200 16 color mode + } else { + VGA_SetMode(M_TANDY2); + } + } else VGA_SetMode(M_TANDY4); // lowres mode + + write_cga_color_select(vga.tandy.color_select); + } else { + VGA_SetMode(M_TANDY_TEXT); + } + VGA_SetBlinking(val & 0x20); + break; + case 0x3d9: // color select + write_cga_color_select(val); + break; + } +} + +static void tandy_update_palette() { + // TODO mask off bits if needed + if (machine == MCH_TANDY) { + switch (vga.mode) { + case M_TANDY2: + VGA_SetCGA2Table(vga.attr.palette[0], + //vga.attr.palette[vga.tandy.color_select&0xf]); + vga.attr.palette[0xf]); + //VGA_SetCGA2Table(vga.attr.palette[0xf],vga.attr.palette[0]); + break; + case M_TANDY4: + if (vga.tandy.gfx_control & 0x8) { + // 4-color high resolution - might be an idea to introduce M_TANDY4H + VGA_SetCGA4Table( // function sets both medium and highres 4color tables + vga.attr.palette[0], vga.attr.palette[1], + vga.attr.palette[2], vga.attr.palette[3]); + } else { + Bit8u color_set = 0; + Bit8u r_mask = 0xf; + if (vga.tandy.color_select & 0x10) color_set |= 8; // intensity + if (vga.tandy.color_select & 0x20) color_set |= 1; // Cyan Mag. White + if (vga.tandy.mode_control & 0x04) { // Cyan Red White + color_set |= 1; + r_mask &= ~1; + } + VGA_SetCGA4Table( + vga.attr.palette[0], + vga.attr.palette[(2|color_set)& vga.tandy.palette_mask], + vga.attr.palette[(4|(color_set& r_mask))& vga.tandy.palette_mask], + vga.attr.palette[(6|color_set)& vga.tandy.palette_mask]); + } + break; + default: + break; + } } else { - VGA_SetMode(M_TANDY_TEXT); + // PCJr + switch (vga.mode) { + case M_TANDY2: + VGA_SetCGA2Table(vga.attr.palette[0],vga.attr.palette[1]); + break; + case M_TANDY4: + VGA_SetCGA4Table( + vga.attr.palette[0], vga.attr.palette[1], + vga.attr.palette[2], vga.attr.palette[3]); + break; + default: + break; + } } } void VGA_SetModeNow(VGAModes mode); +static void TANDY_FindMode(void) { + if (vga.tandy.mode_control & 0x2) { + if (vga.tandy.gfx_control & 0x10) { + if (vga.mode==M_TANDY4) { + VGA_SetModeNow(M_TANDY16); + } else VGA_SetMode(M_TANDY16); + } + else if (vga.tandy.gfx_control & 0x08) { + VGA_SetMode(M_TANDY4); + } + else if (vga.tandy.mode_control & 0x10) + VGA_SetMode(M_TANDY2); + else { + if (vga.mode==M_TANDY16) { + VGA_SetModeNow(M_TANDY4); + } else VGA_SetMode(M_TANDY4); + } + tandy_update_palette(); + } else { + VGA_SetMode(M_TANDY_TEXT); + } +} + static void PCJr_FindMode(void) { if (vga.tandy.mode_control & 0x2) { if (vga.tandy.mode_control & 0x10) { @@ -299,7 +403,6 @@ static void PCJr_FindMode(void) { if (vga.mode==M_TANDY16) VGA_SetModeNow(M_TANDY4); else VGA_SetMode(M_TANDY4); } - write_color_select(vga.tandy.color_select); } else { VGA_SetMode(M_TANDY_TEXT); } @@ -327,11 +430,16 @@ static void write_tandy_reg(Bit8u val) { vga.tandy.mode_control=val; VGA_SetBlinking(val & 0x20); PCJr_FindMode(); - vga.attr.disabled = (val&0x8)? 0: 1; + if (val&0x8) vga.attr.disabled &= ~1; + else vga.attr.disabled |= 1; } else { LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to tandy reg %X",val,vga.tandy.reg_index); } break; + case 0x1: /* Palette mask */ + vga.tandy.palette_mask = val; + tandy_update_palette(); + break; case 0x2: /* Border color */ vga.tandy.border_color=val; break; @@ -348,45 +456,12 @@ static void write_tandy_reg(Bit8u val) { TandyCheckLineMask(); VGA_SetupHandlers(); break; - case 0x8: /* Monitor mode seletion */ - //Bit 1 select mode e, for 640x200x16, some double clocking thing? - //Bit 4 select 350 line mode for hercules emulation - LOG(LOG_VGAMISC,LOG_NORMAL)("Write %2X to tandy monitor mode",val ); - break; - /* palette colors */ - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x15: case 0x16: case 0x17: - case 0x18: case 0x19: case 0x1a: case 0x1b: - case 0x1c: case 0x1d: case 0x1e: case 0x1f: - VGA_ATTR_SetPalette(vga.tandy.reg_index-0x10,val & 0xf); - break; - default: - LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to tandy reg %X",val,vga.tandy.reg_index); - } -} - -static void write_cga(Bitu port,Bitu val,Bitu /*iolen*/) { - switch (port) { - case 0x3d8: - vga.tandy.mode_control=(Bit8u)val; - vga.attr.disabled = (val&0x8)? 0: 1; - if (vga.tandy.mode_control & 0x2) { - if (vga.tandy.mode_control & 0x10) { - if (!(val & 0x4) && machine==MCH_CGA) { - VGA_SetMode(M_CGA16); //Video burst 16 160x200 color mode - } else { - VGA_SetMode(M_TANDY2); - } - } else VGA_SetMode(M_TANDY4); - write_color_select(vga.tandy.color_select); - } else { - VGA_SetMode(M_TANDY_TEXT); - } - VGA_SetBlinking(val & 0x20); - break; - case 0x3d9: - write_color_select((Bit8u)val); - break; + default: + if ((vga.tandy.reg_index & 0xf0) == 0x10) { // color palette + vga.attr.palette[vga.tandy.reg_index-0x10] = val&0xf; + tandy_update_palette(); + } else + LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to tandy reg %X",val,vga.tandy.reg_index); } } @@ -394,40 +469,32 @@ static void write_tandy(Bitu port,Bitu val,Bitu /*iolen*/) { switch (port) { case 0x3d8: vga.tandy.mode_control=(Bit8u)val; + if (val&0x8) vga.attr.disabled &= ~1; + else vga.attr.disabled |= 1; TandyCheckLineMask(); VGA_SetBlinking(val & 0x20); TANDY_FindMode(); break; case 0x3d9: - write_color_select((Bit8u)val); + vga.tandy.color_select=val; + if (vga.mode==M_TANDY2) vga.attr.palette[0xf] = vga.tandy.color_select&0xf; + else vga.attr.palette[0] = vga.tandy.color_select&0xf; // Pirates! + tandy_update_palette(); break; case 0x3da: vga.tandy.reg_index=(Bit8u)val; - break; - case 0x3db: // Clear lightpen latch - vga.other.lightpen_triggered = false; - break; - case 0x3dc: // Preset lightpen latch - if (!vga.other.lightpen_triggered) { - vga.other.lightpen_triggered = true; // TODO: this shows at port 3ba/3da bit 1 - - double timeInFrame = PIC_FullIndex()-vga.draw.delay.framestart; - double timeInLine = fmod(timeInFrame,vga.draw.delay.htotal); - Bitu current_scanline = (Bitu)(timeInFrame / vga.draw.delay.htotal); - - vga.other.lightpen = (Bit16u)((vga.draw.address_add/2) * (current_scanline/2)); - vga.other.lightpen += (Bit16u)((timeInLine / vga.draw.delay.hdend) * - ((float)(vga.draw.address_add/2))); - } + //if (val&0x10) vga.attr.disabled |= 2; + //else vga.attr.disabled &= ~2; break; // case 0x3dd: //Extended ram page address register: - break; +// break; case 0x3de: write_tandy_reg((Bit8u)val); break; case 0x3df: vga.tandy.line_mask = (Bit8u)(val >> 6); vga.tandy.draw_bank = val & ((vga.tandy.line_mask&2) ? 0x6 : 0x7); + if(vga.tandy.line_mask==3) vga.tandy.draw_bank &= ~1; // LSB unused in 32k modes vga.tandy.mem_bank = (val >> 3) & ((vga.tandy.line_mask&2) ? 0x6 : 0x7); TandyCheckLineMask(); VGA_SetupHandlers(); @@ -437,12 +504,14 @@ static void write_tandy(Bitu port,Bitu val,Bitu /*iolen*/) { static void write_pcjr(Bitu port,Bitu val,Bitu /*iolen*/) { switch (port) { - case 0x3d9: - write_color_select((Bit8u)val); - break; case 0x3da: if (vga.tandy.pcjr_flipflop) write_tandy_reg((Bit8u)val); - else vga.tandy.reg_index=(Bit8u)val; + else { + vga.tandy.reg_index=(Bit8u)val; + if (vga.tandy.reg_index & 0x10) + vga.attr.disabled |= 2; + else vga.attr.disabled &= ~2; + } vga.tandy.pcjr_flipflop=!vga.tandy.pcjr_flipflop; break; case 0x3df: @@ -577,6 +646,10 @@ void VGA_SetupOther(void) { for (i=0;i<256;i++) memcpy(&vga.draw.font[i*32],&int10_font_08[i*8],8); vga.draw.font_tables[0]=vga.draw.font_tables[1]=vga.draw.font; } + if (machine==MCH_CGA || IS_TANDY_ARCH || machine==MCH_HERC) { + IO_RegisterWriteHandler(0x3db,write_lightpen,IO_MB); + IO_RegisterWriteHandler(0x3dc,write_lightpen,IO_MB); + } if (machine==MCH_HERC) { extern Bit8u int10_font_14[256 * 14]; for (i=0;i<256;i++) memcpy(&vga.draw.font[i*32],&int10_font_14[i*14],14); @@ -586,8 +659,6 @@ void VGA_SetupOther(void) { if (machine==MCH_CGA) { IO_RegisterWriteHandler(0x3d8,write_cga,IO_MB); IO_RegisterWriteHandler(0x3d9,write_cga,IO_MB); - IO_RegisterWriteHandler(0x3db,write_tandy,IO_MB); - IO_RegisterWriteHandler(0x3dc,write_tandy,IO_MB); MAPPER_AddHandler(IncreaseHue,MK_f11,MMOD2,"inchue","Inc Hue"); MAPPER_AddHandler(DecreaseHue,MK_f11,0,"dechue","Dec Hue"); } @@ -595,14 +666,13 @@ void VGA_SetupOther(void) { write_tandy( 0x3df, 0x0, 0 ); IO_RegisterWriteHandler(0x3d8,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3d9,write_tandy,IO_MB); + IO_RegisterWriteHandler(0x3da,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3de,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3df,write_tandy,IO_MB); - IO_RegisterWriteHandler(0x3da,write_tandy,IO_MB); } if (machine==MCH_PCJR) { //write_pcjr will setup base address write_pcjr( 0x3df, 0x7 | (0x7 << 3), 0 ); - IO_RegisterWriteHandler(0x3d9,write_pcjr,IO_MB); IO_RegisterWriteHandler(0x3da,write_pcjr,IO_MB); IO_RegisterWriteHandler(0x3df,write_pcjr,IO_MB); } diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index d1e6233..1f1d20b 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -434,18 +434,16 @@ static Bitu INT17_Handler(void) { return CBRET_NONE; } -static Bit8u INT14_Wait(Bit16u port, Bit8u mask, Bit8u timeout) { +static bool INT14_Wait(Bit16u port, Bit8u mask, Bit8u timeout, Bit8u* retval) { double starttime = PIC_FullIndex(); double timeout_f = timeout * 1000.0; - Bit8u retval; - while (((retval = IO_ReadB(port)) & mask) != mask) { + while (((*retval = IO_ReadB(port)) & mask) != mask) { if (starttime < (PIC_FullIndex() - timeout_f)) { - retval |= 0x80; - break; + return false; } CALLBACK_Idle(); } - return retval; + return true; } static Bitu INT14_Handler(void) { @@ -500,7 +498,7 @@ static Bitu INT14_Handler(void) { CALLBACK_SCF(false); break; } - case 0x01: { // Transmit character + case 0x01: // Transmit character // Parameters: Return: // AL: character AL: unchanged // AH: 0x01 AH: line status from just before the char was sent @@ -510,20 +508,19 @@ static Bitu INT14_Handler(void) { // set DTR & RTS on IO_WriteB(port+4,0x3); - // wait for DSR & CTS - reg_ah = INT14_Wait(port+6, 0x30, timeout); - if (!(reg_ah & 0x80)) { + if (INT14_Wait(port+6, 0x30, timeout, ®_ah)) { // wait for TX buffer empty - reg_ah = INT14_Wait(port+5, 0x20, timeout); - if (!(reg_ah & 0x80)) { + if (INT14_Wait(port+5, 0x20, timeout, ®_ah)) { // fianlly send the character IO_WriteB(port,reg_al); - } - } // else timed out + } else + reg_ah |= 0x80; + } else // timed out + reg_ah |= 0x80; + CALLBACK_SCF(false); break; - } case 0x02: // Read character // Parameters: Return: // AH: 0x02 AL: received character @@ -537,15 +534,16 @@ static Bitu INT14_Handler(void) { IO_WriteB(port+4,0x1); // wait for DSR - reg_ah = INT14_Wait(port+6, 0x20, timeout); - if (!(reg_ah & 0x80)) { + if (INT14_Wait(port+6, 0x20, timeout, ®_ah)) { // wait for character to arrive - reg_ah = INT14_Wait(port+5, 0x01, timeout); - if (!(reg_ah & 0x80)) { + if (INT14_Wait(port+5, 0x01, timeout, ®_ah)) { reg_ah &= 0x1E; reg_al = IO_ReadB(port); - } - } + } else + reg_ah |= 0x80; + } else + reg_ah |= 0x80; + CALLBACK_SCF(false); break; case 0x03: // get status diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index a24a4a4..68a908c 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -32,6 +32,7 @@ #include "setup.h" #include "support.h" #include "cpu.h" +#include "dma.h" #define EMM_PAGEFRAME 0xE000 #define EMM_PAGEFRAME4K ((EMM_PAGEFRAME*16)/4096) @@ -88,6 +89,8 @@ struct EMM_Handle { EMM_Mapping page_map[EMM_MAX_PHYS]; }; +static Bitu ems_type; + static EMM_Handle emm_handles[EMM_MAX_HANDLES]; static EMM_Mapping emm_mappings[EMM_MAX_PHYS]; static EMM_Mapping emm_segmentmappings[0x40]; @@ -97,7 +100,8 @@ static Bit16u GEMMIS_seg; class device_EMM : public DOS_Device { public: - device_EMM() { + device_EMM(bool is_emm386_avail) { + is_emm386=is_emm386_avail; SetName("EMMXXXX0"); GEMMIS_seg=0; } @@ -108,11 +112,12 @@ public: } bool Seek(Bit32u * /*pos*/,Bit32u /*type*/){return false;} bool Close(){return false;} - Bit16u GetInformation(void){return 0xc080;} + Bit16u GetInformation(void){return 0xc0c0;} bool ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode); bool WriteToControlChannel(PhysPt /*bufptr*/,Bit16u /*size*/,Bit16u * /*retcode*/){return true;} private: Bit8u cache; + bool is_emm386; }; bool device_EMM::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { @@ -125,6 +130,7 @@ bool device_EMM::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retco *retcode=6; return true; case 0x01: { + if (!is_emm386) return false; if (size!=6) return false; if (GEMMIS_seg==0) GEMMIS_seg=DOS_GetMemory(0x20); PhysPt GEMMIS_addr=PhysMake(GEMMIS_seg,0); @@ -181,12 +187,14 @@ bool device_EMM::ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retco return true; } case 0x02: + if (!is_emm386) return false; if (size!=2) return false; mem_writeb(bufptr+0x00,EMM_VERSION>>4); // version 4 mem_writeb(bufptr+0x01,EMM_MINOR_VERSION); *retcode=2; return true; case 0x03: + if (!is_emm386) return false; if (EMM_MINOR_VERSION < 0x2d) return false; if (size!=4) return false; mem_writew(bufptr+0x00,(Bit16u)(MEM_TotalPages()*4)); // max size (kb) @@ -323,7 +331,23 @@ static Bit8u EMM_MapPage(Bitu phys_page,Bit16u handle,Bit16u log_page) { static Bit8u EMM_MapSegment(Bitu segment,Bit16u handle,Bit16u log_page) { // LOG_MSG("EMS MapSegment handle %d segment %d log %d",handle,segment,log_page); - if (((segment>=0xa000) && (segment<0xb000)) || ((segment>=EMM_PAGEFRAME-0x1000) && (segment=0xa000) && (segment<0xb000)) { + valid_segment=true; // allow mapping of graphics memory + } + if ((segment>=EMM_PAGEFRAME) && (segment=EMM_PAGEFRAME-0x1000) && (segmentGet_string("ems")); + if (emstypestr=="true") { + rtype = 1; // mixed mode + } else if (emstypestr=="emsboard") { + rtype = 2; + } else if (emstypestr=="emm386") { + rtype = 3; + } else { + rtype = 0; + } + return rtype; +} + class EMS: public Module_base { private: + DOS_Device * emm_device; /* location in protected unfreeable memory where the ems name and callback are * stored 32 bytes.*/ static Bit16u ems_baseseg; @@ -1273,7 +1313,9 @@ private: Bitu call_int67; public: - EMS(Section* configuration):Module_base(configuration){ + EMS(Section* configuration):Module_base(configuration) { + emm_device=NULL; + ems_type=0; /* Virtual DMA interrupt callback */ call_vdma.Install(&INT4B_Handler,CB_IRET,"Int 4b vdma"); @@ -1283,8 +1325,11 @@ public: GEMMIS_seg=0; Section_prop * section=static_cast(configuration); - if (!section->Get_bool("ems")) return; + ems_type=GetEMSType(section); + if (ems_type<=0) return; + if (machine==MCH_PCJR) { + ems_type=0; LOG_MSG("EMS disabled for PCJr machine"); return; } @@ -1302,8 +1347,8 @@ public: /* Register the ems device */ //TODO MAYBE put it in the class. - DOS_Device * newdev = new device_EMM(); - DOS_AddDevice(newdev); + emm_device = new device_EMM(ems_type!=2); + DOS_AddDevice(emm_device); /* Clear handle and page tables */ Bitu i; @@ -1323,61 +1368,67 @@ public: EMM_AllocateSystemHandle(8); // allocate OS-dedicated handle (ems handle zero, 128kb) + if (ems_type==3) { + DMA_SetWrapping(0xffffffff); // emm386-bug that disables dma wrapping + } if (!ENABLE_VCPI) return; - /* Install a callback that handles VCPI-requests in protected mode requests */ - call_vcpi.Install(&VCPI_PM_Handler,CB_IRETD,"VCPI PM"); - vcpi.pm_interface=(call_vcpi.Get_callback())*CB_SIZE; + if (ems_type!=2) { + /* Install a callback that handles VCPI-requests in protected mode requests */ + call_vcpi.Install(&VCPI_PM_Handler,CB_IRETD,"VCPI PM"); + vcpi.pm_interface=(call_vcpi.Get_callback())*CB_SIZE; - /* Initialize private data area and set up descriptor tables */ - SetupVCPI(); + /* Initialize private data area and set up descriptor tables */ + SetupVCPI(); - if (!vcpi.enabled) return; + if (!vcpi.enabled) return; - /* Install v86-callback that handles interrupts occuring - in v86 mode, including protection fault exceptions */ - call_v86mon.Install(&V86_Monitor,CB_IRET,"V86 Monitor"); + /* Install v86-callback that handles interrupts occuring + in v86 mode, including protection fault exceptions */ + call_v86mon.Install(&V86_Monitor,CB_IRET,"V86 Monitor"); - mem_writeb(vcpi.private_area+0x2e00,(Bit8u)0xFE); //GRP 4 - mem_writeb(vcpi.private_area+0x2e01,(Bit8u)0x38); //Extra Callback instruction - mem_writew(vcpi.private_area+0x2e02,call_v86mon.Get_callback()); //The immediate word - mem_writeb(vcpi.private_area+0x2e04,(Bit8u)0x66); - mem_writeb(vcpi.private_area+0x2e05,(Bit8u)0xCF); //A IRETD Instruction + mem_writeb(vcpi.private_area+0x2e00,(Bit8u)0xFE); //GRP 4 + mem_writeb(vcpi.private_area+0x2e01,(Bit8u)0x38); //Extra Callback instruction + mem_writew(vcpi.private_area+0x2e02,call_v86mon.Get_callback()); //The immediate word + mem_writeb(vcpi.private_area+0x2e04,(Bit8u)0x66); + mem_writeb(vcpi.private_area+0x2e05,(Bit8u)0xCF); //A IRETD Instruction - /* Testcode only, starts up dosbox in v86-mode */ - if (ENABLE_V86_STARTUP) { - /* Prepare V86-task */ - CPU_SET_CRX(0, 1); - CPU_LGDT(0xff, vcpi.private_area+0x0000); - CPU_LIDT(0x7ff, vcpi.private_area+0x2000); - if (CPU_LLDT(0x08)) LOG_MSG("VCPI:Could not load LDT"); - if (CPU_LTR(0x10)) LOG_MSG("VCPI:Could not load TR"); + /* Testcode only, starts up dosbox in v86-mode */ + if (ENABLE_V86_STARTUP) { + /* Prepare V86-task */ + CPU_SET_CRX(0, 1); + CPU_LGDT(0xff, vcpi.private_area+0x0000); + CPU_LIDT(0x7ff, vcpi.private_area+0x2000); + if (CPU_LLDT(0x08)) LOG_MSG("VCPI:Could not load LDT"); + if (CPU_LTR(0x10)) LOG_MSG("VCPI:Could not load TR"); - CPU_Push32(SegValue(gs)); - CPU_Push32(SegValue(fs)); - CPU_Push32(SegValue(ds)); - CPU_Push32(SegValue(es)); - CPU_Push32(SegValue(ss)); - CPU_Push32(0x23002); - CPU_Push32(SegValue(cs)); - CPU_Push32(reg_eip&0xffff); - /* Switch to V86-mode */ - cpu.cpl=0; - CPU_IRET(true,0); + CPU_Push32(SegValue(gs)); + CPU_Push32(SegValue(fs)); + CPU_Push32(SegValue(ds)); + CPU_Push32(SegValue(es)); + CPU_Push32(SegValue(ss)); + CPU_Push32(0x23002); + CPU_Push32(SegValue(cs)); + CPU_Push32(reg_eip&0xffff); + /* Switch to V86-mode */ + cpu.cpl=0; + CPU_IRET(true,0); + } } } ~EMS() { - Section_prop * section=static_cast(m_configuration); - if (!section->Get_bool("ems")) return; + if (ems_type<=0) return; /* Undo Biosclearing */ BIOS_ZeroExtendedSize(false); /* Remove ems device */ - device_EMM newdev; - DOS_DelDevice(&newdev); + if (emm_device!=NULL) { + DOS_DelDevice(emm_device); + emm_device=NULL; + } GEMMIS_seg=0; /* Remove the emsname and callback hack */ diff --git a/src/ints/int10.cpp b/src/ints/int10.cpp index fed4a7d..cc367ea 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -107,7 +107,9 @@ static Bitu INT10_Handler(void) { INT10_ReadCharAttr(®_ax,reg_bh); break; case 0x09: /* Write Character & Attribute at cursor CX times */ - INT10_WriteChar(reg_al,reg_bl,reg_bh,reg_cx,true); + if (real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)==0x11) + INT10_WriteChar(reg_al,(reg_bl&0x80)|0x3f,reg_bh,reg_cx,true); + else 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); @@ -138,7 +140,8 @@ 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>0x03))) break; + if (!IS_EGAVGA_ARCH && (reg_al>0x02)) break; + else if (!IS_VGA_ARCH && (reg_al>0x03)) break; switch (reg_al) { case 0x00: /* SET SINGLE PALETTE REGISTER */ INT10_SetSinglePaletteRegister(reg_bl,reg_bh); @@ -162,7 +165,7 @@ static Bitu INT10_Handler(void) { INT10_GetAllPaletteRegisters(SegPhys(es)+reg_dx); break; case 0x10: /* SET INDIVIDUAL DAC REGISTER */ - INT10_SetSingleDacRegister(reg_bl,reg_dh,reg_ch,reg_cl); + INT10_SetSingleDACRegister(reg_bl,reg_dh,reg_ch,reg_cl); break; case 0x12: /* SET BLOCK OF DAC REGISTERS */ INT10_SetDACBlock(reg_bx,reg_cx,SegPhys(es)+reg_dx); @@ -171,7 +174,7 @@ static Bitu INT10_Handler(void) { INT10_SelectDACPage(reg_bl,reg_bh); break; case 0x15: /* GET INDIVIDUAL DAC REGISTER */ - INT10_GetSingleDacRegister(reg_bl,®_dh,®_ch,®_cl); + INT10_GetSingleDACRegister(reg_bl,®_dh,®_ch,®_cl); break; case 0x17: /* GET BLOCK OF DAC REGISTER */ INT10_GetDACBlock(reg_bx,reg_cx,SegPhys(es)+reg_dx); @@ -208,11 +211,11 @@ static Bitu INT10_Handler(void) { break; case 0x01: /* Load 8x14 font */ case 0x11: - INT10_LoadFont(Real2Phys(int10.rom.font_14),reg_al==0x11,256,0,0,14); + INT10_LoadFont(Real2Phys(int10.rom.font_14),reg_al==0x11,256,0,reg_bl,14); break; case 0x02: /* Load 8x8 font */ case 0x12: - INT10_LoadFont(Real2Phys(int10.rom.font_8_first),reg_al==0x12,256,0,0,8); + INT10_LoadFont(Real2Phys(int10.rom.font_8_first),reg_al==0x12,256,0,reg_bl,8); break; case 0x03: /* Set Block Specifier */ IO_Write(0x3c4,0x3);IO_Write(0x3c5,reg_bl); @@ -220,7 +223,7 @@ static Bitu INT10_Handler(void) { case 0x04: /* Load 8x16 font */ case 0x14: if (!IS_VGA_ARCH) break; - INT10_LoadFont(Real2Phys(int10.rom.font_16),reg_al==0x14,256,0,0,16); + INT10_LoadFont(Real2Phys(int10.rom.font_16),reg_al==0x14,256,0,reg_bl,16); break; /* Graphics mode calls */ case 0x20: /* Set User 8x8 Graphics characters */ diff --git a/src/ints/int10.h b/src/ints/int10.h index 8bc7fbc..92ea79b 100644 --- a/src/ints/int10.h +++ b/src/ints/int10.h @@ -187,8 +187,8 @@ 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_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); void INT10_SelectDACPage(Bit8u function,Bit8u mode); diff --git a/src/ints/int10_modes.cpp b/src/ints/int10_modes.cpp index 54fdacc..d3d7099 100644 --- a/src/ints/int10_modes.cpp +++ b/src/ints/int10_modes.cpp @@ -246,6 +246,7 @@ VideoModeBlock ModeList_OTHER[]={ { 0x008 ,M_TANDY16,160 ,200 ,20 ,25 ,8 ,8 ,8 ,0xB8000 ,0x2000 ,56 ,127 ,40 ,100 ,0 }, { 0x009 ,M_TANDY16,320 ,200 ,40 ,25 ,8 ,8 ,8 ,0xB8000 ,0x2000 ,113 ,63 ,80 ,50 ,0 }, { 0x00A ,M_CGA4 ,640 ,200 ,80 ,25 ,8 ,8 ,8 ,0xB8000 ,0x2000 ,113 ,63 ,80 ,50 ,0 }, +//{ 0x00E ,M_TANDY16,640 ,200 ,80 ,25 ,8 ,8 ,8 ,0xA0000 ,0x10000 ,113 ,256 ,80 ,200 ,0 }, {0xFFFF ,M_ERROR ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0x00000 ,0x0000 ,0 ,0 ,0 ,0 ,0 }, }; @@ -547,6 +548,11 @@ bool INT10_SetVideoMode_OTHER(Bit16u mode,bool clearmem) { default: IO_WriteB(0x3de,0x0);break; } + // write palette + for(Bitu i = 0; i < 16; i++) { + IO_WriteB(0x3da,i+0x10); + IO_WriteB(0x3de,i); + } //Clear extended mapping IO_WriteB(0x3da,0x5); IO_WriteB(0x3de,0x0); @@ -587,8 +593,9 @@ bool INT10_SetVideoMode_OTHER(Bit16u mode,bool clearmem) { if (CurMode->mode == 0x6 || CurMode->mode==0xa) color_select=0x3f; else color_select=0x30; - IO_WriteB(0x3d9,color_select); real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select); + INT10_SetColorSelect(1); + INT10_SetBackgroundBorder(0); break; } diff --git a/src/ints/int10_pal.cpp b/src/ints/int10_pal.cpp index 266ac26..4a672c0 100644 --- a/src/ints/int10_pal.cpp +++ b/src/ints/int10_pal.cpp @@ -35,9 +35,44 @@ static INLINE void WriteTandyACTL(Bit8u creg,Bit8u val) { void INT10_SetSinglePaletteRegister(Bit8u reg,Bit8u val) { switch (machine) { - case TANDY_ARCH_CASE: + case MCH_PCJR: + reg&=0xf; IO_Read(VGAREG_TDY_RESET); WriteTandyACTL(reg+0x10,val); + IO_Write(0x3da,0x0); // palette back on + break; + case MCH_TANDY: + // TODO waits for vertical retrace + switch(vga.mode) { + case M_TANDY2: + if (reg >= 0x10) break; + else if (reg==1) reg = 0x1f; + else reg |= 0x10; + WriteTandyACTL(reg+0x10,val); + break; + case M_TANDY4: { + if (CurMode->mode!=0x0a) { + // Palette values are kept constand by the BIOS. + // The four colors are mapped to special palette values by hardware. + // 3D8/3D9 registers influence this mapping. We need to figure out + // which entry is used for the requested color. + if (reg > 3) break; + if (reg != 0) { // 0 is assumed to be at 0 + Bit8u color_select=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); + reg = reg*2+8; // Green Red Brown + if (color_select& 0x20) reg++; // Cyan Magenta White + } + WriteTandyACTL(reg+0x10,val); + } + // 4-color high resolution mode 0x0a isn't handled specially + else WriteTandyACTL(reg+0x10,val); + break; + } + default: + WriteTandyACTL(reg+0x10,val); + break; + } + IO_Write(0x3da,0x0); // palette back on break; case EGAVGA_ARCH_CASE: if (!IS_VGA_ARCH) reg&=0x1f; @@ -168,14 +203,23 @@ void INT10_GetAllPaletteRegisters(PhysPt data) { ResetACTL(); } -void INT10_SetSingleDacRegister(Bit8u index,Bit8u red,Bit8u green,Bit8u blue) { +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); + if ((real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x06)==0) { + IO_Write(VGAREG_DAC_DATA,red); + IO_Write(VGAREG_DAC_DATA,green); + IO_Write(VGAREG_DAC_DATA,blue); + } else { + /* calculate clamped intensity, taken from VGABIOS */ + Bit32u i=(( 77*red + 151*green + 28*blue ) + 0x80) >> 8; + Bit8u ic=(i>0x3f) ? 0x3f : ((Bit8u)(i & 0xff)); + IO_Write(VGAREG_DAC_DATA,ic); + IO_Write(VGAREG_DAC_DATA,ic); + IO_Write(VGAREG_DAC_DATA,ic); + } } -void INT10_GetSingleDacRegister(Bit8u index,Bit8u * red,Bit8u * green,Bit8u * 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); @@ -184,10 +228,25 @@ void INT10_GetSingleDacRegister(Bit8u index,Bit8u * red,Bit8u * green,Bit8u * bl 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++)); + if ((real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x06)==0) { + 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++)); + } + } else { + for (;count>0;count--) { + Bit8u red=mem_readb(data++); + Bit8u green=mem_readb(data++); + Bit8u blue=mem_readb(data++); + + /* calculate clamped intensity, taken from VGABIOS */ + Bit32u i=(( 77*red + 151*green + 28*blue ) + 0x80) >> 8; + Bit8u ic=(i>0x3f) ? 0x3f : ((Bit8u)(i & 0xff)); + IO_Write(VGAREG_DAC_DATA,ic); + IO_Write(VGAREG_DAC_DATA,ic); + IO_Write(VGAREG_DAC_DATA,ic); + } } } @@ -242,14 +301,24 @@ void INT10_SetPelMask(Bit8u mask) { void INT10_GetPelMask(Bit8u & mask) { mask=IO_Read(VGAREG_PEL_MASK); -} +} void INT10_SetBackgroundBorder(Bit8u val) { - Bit8u temp=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); - temp=(temp & 0xe0) | (val & 0x1f); - real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,temp); - if (machine == MCH_CGA || IS_TANDY_ARCH) - IO_Write(0x3d9,temp); + Bit8u color_select=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); + color_select=(color_select & 0xe0) | (val & 0x1f); + real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select); + + if (machine == MCH_CGA || machine == MCH_TANDY) + IO_Write(0x3d9,color_select); + else if (machine == MCH_PCJR) { + IO_Read(VGAREG_TDY_RESET); // reset the flipflop + if (vga.mode!=M_TANDY_TEXT) { + IO_Write(VGAREG_TDY_ADDRESS, 0x10); + IO_Write(VGAREG_PCJR_DATA, color_select&0xf); + } + IO_Write(VGAREG_TDY_ADDRESS, 0x2); // border color + IO_Write(VGAREG_PCJR_DATA, color_select&0xf); + } else if (IS_EGAVGA_ARCH) { val = ((val << 1) & 0x10) | (val & 0x7); /* Aways set the overscan color */ @@ -258,7 +327,7 @@ void INT10_SetBackgroundBorder(Bit8u val) { if (CurMode->mode <= 3) return; INT10_SetSinglePaletteRegister( 0, val ); - val = (temp & 0x10) | 2 | ((temp & 0x20) >> 5); + val = (color_select & 0x10) | 2 | ((color_select & 0x20) >> 5); INT10_SetSinglePaletteRegister( 1, val ); val+=2; INT10_SetSinglePaletteRegister( 2, val ); @@ -271,8 +340,31 @@ void INT10_SetColorSelect(Bit8u val) { Bit8u temp=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); temp=(temp & 0xdf) | ((val & 1) ? 0x20 : 0x0); real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,temp); - if (machine == MCH_CGA || IS_TANDY_ARCH) + if (machine == MCH_CGA || machine==MCH_TANDY) IO_Write(0x3d9,temp); + else if (machine == MCH_PCJR) { + switch(vga.mode) { + case M_TANDY2: + IO_Write(VGAREG_TDY_ADDRESS, 0x11); + IO_Write(VGAREG_PCJR_DATA, val&1? 0xf:0); + break; + case M_TANDY4: + for(Bit8u i = 0x11; i < 0x14; i++) { + const Bit8u t4_table[] = {0,2,4,6, 0,3,5,0xf}; + IO_Write(VGAREG_TDY_ADDRESS, i); + IO_Write(VGAREG_PCJR_DATA, t4_table[(i-0x10)+(val&1? 4:0)]); + } + break; + default: + // 16-color modes: always write the same palette + for(Bit8u i = 0x11; i < 0x20; i++) { + IO_Write(VGAREG_TDY_ADDRESS, i); + IO_Write(VGAREG_PCJR_DATA, i-0x10); + } + break; + } + IO_Write(VGAREG_TDY_ADDRESS, 0); // enable palette + } else if (IS_EGAVGA_ARCH) { if (CurMode->mode <= 3) //Maybe even skip the total function! return; @@ -296,6 +388,6 @@ void INT10_PerformGrayScaleSumming(Bit16u start_reg,Bit16u count) { /* calculate clamped intensity, taken from VGABIOS */ Bit32u i=(( 77*red + 151*green + 28*blue ) + 0x80) >> 8; Bit8u ic=(i>0x3f) ? 0x3f : ((Bit8u)(i & 0xff)); - INT10_SetSingleDacRegister(start_reg+ct,ic,ic,ic); + INT10_SetSingleDACRegister(start_reg+ct,ic,ic,ic); } } diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index 456fab1..a4349e7 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -412,6 +412,8 @@ Bitu XMS_Handler(void) { return CBRET_NONE; } +Bitu GetEMSType(Section_prop * section); + class XMS: public Module_base { private: CALLBACK_HandlerObject callbackhandler; @@ -445,7 +447,8 @@ public: /* Set up UMB chain */ umb_available=section->Get_bool("umb"); - DOS_BuildUMBChain(section->Get_bool("umb"),section->Get_bool("ems")); + bool ems_available = GetEMSType(section)>0; + DOS_BuildUMBChain(section->Get_bool("umb"),ems_available); } ~XMS(){