Skip to content

Commit

Permalink
S3: Mask Linear Address Window by memory size as documented by S3
Browse files Browse the repository at this point in the history
  • Loading branch information
joncampbell123 committed Jul 16, 2024
1 parent c2d3428 commit 6ca213c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 14 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
NEXT
- S3 emulation: Follow S3 Trio64 documentation and mask the Linear
Window Position bits according to the size of the memory. You
can only place it on a multiple of the memory size. This silences
warnings caused by Line Wars II which appears to modify only the
upper byte but not the lower when modifying this register, which
then leaves 0xA0 in the lower half. That lower half would be
ignored for 1MB or larger video memory sizes. (joncampbell123).
- S3 XGA emulation: Add XGA acceleration for 4bpp packed 16-color
SVGA modes. A CAD package has S3 support drivers that use the
16-color 4bpp packed modes and expects XGA acceleration to work.
Expand Down
38 changes: 24 additions & 14 deletions src/hardware/vga_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2945,30 +2945,40 @@ void VGA_StartUpdateLFB(void) {
// FIXME: What about the 8MB window?
}

/* The LFB register has an enable bit */
if (!(vga.s3.reg_58 & 0x10)) {
vga.lfb.page = (unsigned int)vga.s3.la_window << 4u;
vga.lfb.addr = (unsigned int)vga.s3.la_window << 16u;
vga.lfb.handler = NULL;
MEM_SetLFB(0,0,NULL,NULL);
}
/* if the DOS application or Windows 3.1 driver attempts to put the linear framebuffer
/* NTS: 64KB winsz = 0x10000 => winmsk = 0xFFFF0000 => 0xFFFF
* 1MB winsz = 0x100000 => winmsk = 0xFFF00000 => 0xFFF0
* 2MB winsz = 0x200000 => winmsk = 0xFFE00000 => 0xFFE0
* and so on.
*
* From the S3 Trio32/Trio64 documentation regarding the Linear Address Window Position Registers:
* "The Linear Address Window resides on a 64KB, 1MB, 2MB, or 4MB (Trio64 only) memory boundary (size-aligned) ...
* Some LSBs of this register are ignored because of the size-aligned boundary scheme" */
const unsigned int la_winmsk = ~((winsz - 1u) >> 16u); /* Register holds the upper 16 bits of the linear address */

/* The LFB register has an enable bit */
if (!(vga.s3.reg_58 & 0x10)) {
vga.lfb.page = (unsigned int)(vga.s3.la_window & la_winmsk) << 4u;
vga.lfb.addr = (unsigned int)(vga.s3.la_window & la_winmsk) << 16u;
vga.lfb.handler = NULL;
MEM_SetLFB(0,0,NULL,NULL);
}
/* if the DOS application or Windows 3.1 driver attempts to put the linear framebuffer
* below the top of memory, then we're probably entering a DOS VM and it's probably
* a 64KB window. If it's not a 64KB window then print a warning. */
else if ((unsigned long)(vga.s3.la_window << 4UL) < (unsigned long)MEM_TotalPages()) {
else if ((unsigned long)(vga.s3.la_window << 4UL) < (unsigned long)MEM_TotalPages()) {
if (winsz != 0x10000) // 64KB window normal for entering a DOS VM in Windows 3.1 or legacy bank switching in DOS
LOG(LOG_MISC,LOG_WARN)("S3 warning: Window size != 64KB and address conflict with system RAM!");

vga.lfb.page = (unsigned int)vga.s3.la_window << 4u;
vga.lfb.addr = (unsigned int)vga.s3.la_window << 16u;
vga.lfb.page = (unsigned int)(vga.s3.la_window & la_winmsk) << 4u;
vga.lfb.addr = (unsigned int)(vga.s3.la_window & la_winmsk) << 16u;
vga.lfb.handler = NULL;
MEM_SetLFB(0,0,NULL,NULL);
}
else {
vga.lfb.page = (unsigned int)vga.s3.la_window << 4u;
vga.lfb.addr = (unsigned int)vga.s3.la_window << 16u;
vga.lfb.page = (unsigned int)(vga.s3.la_window & la_winmsk) << 4u;
vga.lfb.addr = (unsigned int)(vga.s3.la_window & la_winmsk) << 16u;
vga.lfb.handler = &vgaph.lfb;
MEM_SetLFB((unsigned int)vga.s3.la_window << 4u,(unsigned int)vga.mem.memsize/4096u, vga.lfb.handler, &vgaph.mmio);
MEM_SetLFB((unsigned int)(vga.s3.la_window & la_winmsk) << 4u,(unsigned int)vga.mem.memsize/4096u, vga.lfb.handler, &vgaph.mmio);
}
}

Expand Down

0 comments on commit 6ca213c

Please sign in to comment.