Revise Voodoo 3Dfx linear framebuffer constants and PCI handling.

Restrict S3 LFB to just below BIOS, do not let the 32MB region overlap
the BIOS. Limit Voodoo 3Dfx framebuffer to stay out of system RAM.
To prevent large memsize configurations that cause S3 and 3Dfx to
conflict, add a hardware assignment system to give each device it's own
assigned LFB region of memory. This really only has an effect when space
gets cramped with large mem sizes, otherwise it has no effect. Perhaps
someday the BIOS should assign the 3Dfx, S3, and any other PCI devices
their resources like a real PC system would.
This commit is contained in:
Jonathan Campbell 2024-12-22 09:41:43 -08:00
parent 9057fd2bbb
commit d8d28858a1
7 changed files with 85 additions and 15 deletions

View File

@ -58,6 +58,8 @@ bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bo
MemHandle MEM_NextHandle(MemHandle handle);
MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where);
uint32_t MEM_HardwareAllocate(const char *name,uint32_t sz);
/*
The following six functions are used everywhere in the end so these should be changed for
Working on big or little endian machines

View File

@ -22,13 +22,16 @@
#define VOODOO_INITIAL_LFB 0xd0000000
#define VOODOO_LFB_SIZE 0x01000000 /* VOODOO_PAGES == 4096 (4096 << 12) 16MB size must be a power of 2 */
#define VOODOO_LFB_ALIGNMASK ( ~(VOODOO_LFB_SIZE - 1u) ) /* 16MB align */
#define VOODOO_REG_PAGES 1024
#define VOODOO_LFB_PAGES 1024
#define VOODOO_TEX_PAGES 2048
#define VOODOO_PAGES (VOODOO_REG_PAGES+VOODOO_LFB_PAGES+VOODOO_TEX_PAGES)
#define VOODOO_PAGES (VOODOO_REG_PAGES+VOODOO_LFB_PAGES+VOODOO_TEX_PAGES)
static_assert( VOODOO_LFB_ALIGNMASK == 0xFF000000ul, "Voodoo LFB error" );
#define VOODOO_EMU_TYPE_OFF 0
#define VOODOO_EMU_TYPE_OFF 0
#define VOODOO_EMU_TYPE_SOFTWARE 1
#define VOODOO_EMU_TYPE_ACCELERATED 2

View File

@ -30,6 +30,7 @@
#include "programs.h"
#include "zipfile.h"
#include "regs.h"
#include "bitop.h"
#ifndef WIN32
# include <stdlib.h>
# include <unistd.h>
@ -200,6 +201,7 @@ static struct MemoryBlock {
uint32_t mem_alias_pagemask = 0;
uint32_t mem_alias_pagemask_active = 0;
uint32_t address_bits = 0;
uint32_t hw_next_assign = 0;
} memory;
uint32_t MEM_get_address_bits() {
@ -1890,6 +1892,27 @@ void MEM_InitCallouts(void) {
MEM_callouts[MEM_callouts_index(MEM_TYPE_MB)].resize(64);
}
uint32_t MEM_HardwareAllocate(const char *name,uint32_t sz) {
uint32_t assign = 0;
if (sz != 0ul && bitop::ispowerof2(sz)) {
if (memory.hw_next_assign < 0xFE000000ul) {
memory.hw_next_assign += sz - 1ul;
memory.hw_next_assign &= ~(sz - 1ul);
}
if (memory.hw_next_assign < 0xFE000000ul) {
assign = memory.hw_next_assign;
memory.hw_next_assign += sz;
LOG(LOG_MISC,LOG_DEBUG)("Device '%s' assigned address 0x%lx-0x%lx which it may treat as minimum\n",name,(unsigned long)assign,(unsigned long)assign+(unsigned long)sz-1ul);
}
}
if (assign == 0)
LOG(LOG_MISC,LOG_DEBUG)("Unable to assign device '%s' a physical address of size 0x%lx\n",name,(unsigned long)sz);
return assign;
}
void Init_RAM() {
Section_prop * section=static_cast<Section_prop *>(control->GetSection("dosbox"));
Bitu i;
@ -1936,6 +1959,15 @@ void Init_RAM() {
{
Bitu maxsz;
/* Leave 128MB of space at the top for the BIOS, S3 VGA, and Voodoo 3Dfx emulation.
* There was a known bug 2024/12/21 where setting the maximum memory size and installing
* Windows XP caused problems because XP would try to use the Voodoo 3Dfx MMIO as memory
* when enabled at 0xD0000000.
*
* BIOS: Given the 512KB at the top, including for ACPI structures
* PC-98 PEGC framebuffer: 512KB below BIOS
* S3 LFB and MMIO: 32MB at 32MB alignment
* Voodoo 3Dfx: 16MB at 16MB alignment */
if (sizeof(void*) > 4) // 64-bit address space
maxsz = (Bitu)(3968ul * 1024ul); // 3.9GB (up to 0xF8000000)
else
@ -1949,6 +1981,8 @@ void Init_RAM() {
LOG_MSG("Final %lu\n",(unsigned long)memsizekb);
}
memory.reported_pages = memory.pages = memsizekb/4;
memory.hw_next_assign = memory.pages << 12ul;
LOG(LOG_MISC,LOG_DEBUG)("Hardware assignment will begin at 0x%lx",(unsigned long)memory.hw_next_assign);
// FIXME: Hopefully our refactoring will remove the need for this hack
/* if the config file asks for less than 1MB of memory

View File

@ -248,12 +248,12 @@ public:
void config_write(uint8_t regnum,Bitu iolen,uint32_t value) override {
if (iolen == 1) {
const unsigned char mask = config_writemask[regnum];
const unsigned char nmask = ~mask;
const unsigned char mask = config_writemask[regnum];
const unsigned char nmask = ~mask;
/* configuration write masks apply here as well */
config[regnum] =
((unsigned char)value & mask) +
((unsigned char)value & mask) +
(config[regnum] & nmask);
switch (regnum) { /* FIXME: I hope I ported this right --J.C. */

View File

@ -708,6 +708,8 @@ bool has_pcibus_enable(void);
uint32_t MEM_get_address_bits();
uint32_t GetReportedVideoMemorySize(void);
static uint32_t assigned_lfb = 0;
void VGA_Reset(Section*) {
// All non-PC98 video-related config settings are now in the [video] section
@ -749,9 +751,9 @@ void VGA_Reset(Section*) {
lfb_default = true;
}
/* no farther than 32MB below the top */
if (S3_LFB_BASE > 0xFE000000UL)
S3_LFB_BASE = 0xFE000000UL;
/* no farther than 64MB below the top, do not overlap the BIOS */
if (S3_LFB_BASE > 0xFC000000UL)
S3_LFB_BASE = 0xFC000000UL;
/* if the user WANTS the base address to be PCI misaligned, then turn off PCI VGA emulation */
if (enable_pci_vga && has_pcibus_enable() && (S3_LFB_BASE & 0x1FFFFFFul)) {
@ -768,21 +770,26 @@ void VGA_Reset(Section*) {
enable_pci_vga = false;
}
/* must not overlap system RAM */
/* must not overlap system RAM or other devices */
if (S3_LFB_BASE < (MEM_TotalPages()*4096))
S3_LFB_BASE = (MEM_TotalPages()*4096);
if (S3_LFB_BASE < assigned_lfb)
S3_LFB_BASE = assigned_lfb;
if (enable_pci_vga && has_pcibus_enable()) {
/* must be 32MB aligned (PCI) */
S3_LFB_BASE += 0x0FFFFFFUL;
S3_LFB_BASE += 0x1FFFFFFUL;
S3_LFB_BASE &= ~0x1FFFFFFUL;
}
else {
/* must be 64KB aligned (ISA) */
S3_LFB_BASE += 0x7FFFUL;
S3_LFB_BASE += 0xFFFFUL;
S3_LFB_BASE &= ~0xFFFFUL;
}
/* sanity check */
if (S3_LFB_BASE >= 0xFE000000UL) E_Exit("S3 LFB base 0x%lx would overlap BIOS",(unsigned long)S3_LFB_BASE);
/* if the constraints we imposed make it impossible to maintain the alignment required for PCI,
* then just switch off PCI VGA emulation. */
if (IS_VGA_ARCH && enable_pci_vga && has_pcibus_enable()) {
@ -1663,6 +1670,12 @@ void VGA_Init() {
LOG(LOG_MISC,LOG_DEBUG)("Initializing VGA");
LOG(LOG_MISC,LOG_DEBUG)("Render scaler maximum resolution is %u x %u",SCALER_MAXWIDTH,SCALER_MAXHEIGHT);
/* the purpose of this is so that, if everything is crammed up at the top to make room for system RAM, the S3 and 3Dfx do not conflict */
if (IS_VGA_ARCH && svgaCard != SVGA_None)
assigned_lfb = MEM_HardwareAllocate("VGA",32ul << 20ul/*32MB*/);
else
LOG(LOG_MISC,LOG_DEBUG)("Emulation does not require allocating or assigning any LFB");
VGA_TweakUserVsyncOffset(0.0f);
for (i=0;i<256;i++) {

View File

@ -37,6 +37,7 @@
class VOODOO;
static VOODOO* voodoo_dev;
static uint32_t assigned_lfb = 0;
static uint32_t voodoo_current_lfb=(VOODOO_INITIAL_LFB&0xffff0000);
static bool voodoo_pci_enabled = false;
@ -127,7 +128,10 @@ public:
break;
}
if (needs_pci_device) PCI_AddSST_Device((Bitu)card_type);
if (needs_pci_device) {
LOG(LOG_MISC,LOG_DEBUG)("Voodoo 3Dfx LFB at 0x%lx",(unsigned long)voodoo_current_lfb);
PCI_AddSST_Device((Bitu)card_type);
}
}
~VOODOO(){
@ -197,7 +201,7 @@ void VOODOO_PCI_Enable(bool enable) {
void VOODOO_PCI_SetLFB(uint32_t lfbaddr) {
lfbaddr &= 0xFFFF0000UL;
lfbaddr &= VOODOO_LFB_ALIGNMASK;
if (lfbaddr == voodoo_current_lfb)
return;
@ -232,7 +236,18 @@ void VOODOO_Destroy(Section* /*sec*/) {
void VOODOO_OnPowerOn(Section* /*sec*/) {
if (voodoo_dev == NULL) {
voodoo_pci_enabled = true;
voodoo_current_lfb=(VOODOO_INITIAL_LFB&0xffff0000);
voodoo_current_lfb = VOODOO_INITIAL_LFB & VOODOO_LFB_ALIGNMASK;
/* must not overlap system RAM */
if (voodoo_current_lfb < (MEM_TotalPages()*4096))
voodoo_current_lfb = (MEM_TotalPages()*4096);
if (voodoo_current_lfb < assigned_lfb)
voodoo_current_lfb = assigned_lfb;
voodoo_current_lfb += ~VOODOO_LFB_ALIGNMASK; /* round up */
voodoo_current_lfb &= VOODOO_LFB_ALIGNMASK;
voodoo_dev = new VOODOO(control->GetSection("voodoo"));
voodoo_lfb_cb_init();
@ -242,6 +257,9 @@ void VOODOO_OnPowerOn(Section* /*sec*/) {
void VOODOO_Init() {
LOG(LOG_MISC,LOG_DEBUG)("Initializing Voodoo/3DFX emulation");
/* the purpose of this is so that, if everything is crammed up at the top to make room for system RAM, the S3 and 3Dfx do not conflict */
assigned_lfb = MEM_HardwareAllocate("Voodoo 3Dfx",16ul << 20ul/*16MB*/);
AddExitFunction(AddExitFunctionFuncPair(VOODOO_Destroy),true);
AddVMEventFunction(VM_EVENT_POWERON,AddVMEventFunctionFuncPair(VOODOO_OnPowerOn));
}

View File

@ -9726,7 +9726,7 @@ private:
bios_has_exec_vga_bios = false;
LOG(LOG_MISC,LOG_DEBUG)("BIOS: executing POST routine");
if (ACPI_REGION_SIZE != 0) {
if (ACPI_REGION_SIZE != 0 && !IS_PC98_ARCH) {
// place it just below the mirror of the BIOS at FFFF0000
ACPI_BASE = 0xFFFF0000 - ACPI_REGION_SIZE;