From c2622359f9ca7a4bca91fd673ad2d3b84dc508f1 Mon Sep 17 00:00:00 2001 From: Ralf Grillenberger Date: Fri, 1 Oct 2010 19:39:14 +0000 Subject: [PATCH] - implement Tandy special 4-color palette handling - remove 3d8/3d9 from PCJr mode (PCJr didn't have it) - update INT10 palette functions accordingly - add a level of indirection to Tandy and PCjr palette deconding to fix video recording with on-screen palette changes - enable line-by-line emulation for Tandy too - machine-specific implementation of the color when display is disabled (vgaonly too) - enable the light pen stub on all machines that it is documented for - mask off a bank-selection bit that is not used under a specific circumstance Fixes Alley Cat palette on PCJr, Gauntlet, Ghostbusters, Pirates! on Tandy, Video recording on Tandy/PCJr where the palette is changed on-screen Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3647 --- src/hardware/vga_draw.cpp | 91 ++++++++++--- src/hardware/vga_other.cpp | 268 +++++++++++++++++++++++-------------- src/ints/int10.cpp | 3 +- src/ints/int10_modes.cpp | 9 +- src/ints/int10_pal.cpp | 86 ++++++++++-- 5 files changed, 327 insertions(+), 130 deletions(-) diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index c5330421..494a2b34 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; } @@ -589,10 +589,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 +1016,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 7fd18293..c6cd613f 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/int10.cpp b/src/ints/int10.cpp index dd86ad85..cc367ea3 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -140,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); diff --git a/src/ints/int10_modes.cpp b/src/ints/int10_modes.cpp index 54fdaccb..d3d7099d 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 092a647e..4a672c09 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; @@ -266,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 */ @@ -282,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 ); @@ -295,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;