Add register framework

This commit is contained in:
starfrost013
2025-09-21 18:45:32 +01:00
parent ec40252a71
commit 599b391095
7 changed files with 206 additions and 7 deletions

View File

@@ -136,6 +136,10 @@ typedef struct nv_base_s
bool pixel_clock_enabled; // Pixel Clock Enabled - stupid crap used to prevent us enabling the timer multiple times
double memory_clock_frequency; // Source Frequency for PTIMER
rivatimer_t* memory_clock_timer; // Timer for measuring memory/gpu clock
// VCLK / NVCLK do not have timers set here.
pc_timer_t* nv4_vclk_timer; // NV4+ MCLK (Video RAM) timer
bool memory_clock_enabled; // Memory Clock Enabled - stupid crap used to prevent us eanbling the timer multiple times
void* i2c; // I2C for monitor EDID
void* ddc; // Display Data Channel for EDID

View File

@@ -62,6 +62,7 @@ typedef struct nv4_pramdac_s
uint32_t mclk;
uint32_t vclk;
uint32_t nvclk;
uint32_t clk_coeff_select; // Clock coefficient selection
uint32_t cursor_address;
} nv4_pramdac_t;
@@ -83,6 +84,13 @@ extern const device_config_t nv4_config[];
extern nv4_t* nv4; // Allocated at device startup
#ifdef NV_LOG
// Debug register list
extern nv_register_t nv4_registers[];
#endif
//
// Functions
//
@@ -120,9 +128,22 @@ void nv4_ramin_write32(uint32_t addr, uint32_t val, void* priv);
uint8_t nv4_pci_read(int32_t func, int32_t addr, void* priv);
void nv4_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv);
// PRAMDAC
// SVGA
uint8_t nv4_svga_read(uint16_t addr, void* priv);
void nv4_svga_write(uint16_t addr, uint8_t val, void* priv);
void nv4_update_mappings();
// Memory
void nv4_update_mappings();
// PRAMDAC
uint32_t nv4_pramdac_read(uint32_t address);
void nv4_pramdac_write(uint32_t address, uint32_t data);
// We don't implement NVCLK/VCLK because they are too fast
void nv4_pramdac_set_vclk();
void nv4_vclk_tick();
// PTIMER
uint32_t nv4_ptimer_read(uint32_t address);
void nv4_ptimer_write(uint32_t address, uint32_t data);

View File

@@ -201,6 +201,8 @@ add_library(vid OBJECT
nv/nv4/nv4_core.c
nv/nv4/nv4_core_io.c
nv/nv4/nv4_core_config.c
nv/nv4/nv4_debug_register_list.c
nv/nv4/subsystems/nv4_pramdac.c
nv/nv4/subsystems/nv4_ptimer.c
# Generic

View File

@@ -199,7 +199,6 @@ bool nv4_init()
/* Set log device name based on card model */
const char* log_device_name = "NV4";
/* Just hardcode full logging */
if (device_get_config_int("nv_debug_fulllog"))
@@ -234,6 +233,15 @@ bool nv4_init()
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_nv4_agp);
// Setup clock information. These values don't matter, I pulled them out of an STB BIOS, we don't need to macro them
nv4->pramdac.nvclk = 0x17809;
nv4->pramdac.mclk = 0x1a30a;
nv4->pramdac.vclk = 0x1400c;
//timer_add(nv4->pramdac.nvclk, )
nv4_init_mappings();
//nv4_update_mappings();
@@ -250,6 +258,21 @@ void* nv4_init_stb4400(const device_t *info)
return NULL;
}
void nv4_nvclk_tick()
{
}
void nv4_mclk_tick()
{
}
void nv4_vclk_tick()
{
}
void nv4_close(void* priv)
{
free(nv4);
@@ -278,7 +301,7 @@ void nv4_recalc_timings(svga_t* svga)
nv4_t* nv4 = (nv4_t*)svga->priv;
// TODO: Everything, this code sucks, incl. NV4_PRAMDAC_GENERAL_CONTROL_BPC and the OFFSET register
// TODO: Everything, this code sucks, incl. NV4_PRAMDAC_GENERAL_CONTROL_BPC and the offset register
uint32_t pixel_mode = svga->crtc[NV4_CIO_CRE_PIXEL_INDEX] & 0x03;
svga->memaddr_latch += (svga->crtc[NV4_CIO_CRE_RPC0_INDEX] & 0x1F) << 16;

View File

@@ -44,12 +44,47 @@ void nv4_svga_write(uint16_t addr, uint8_t val, void* priv);
uint32_t nv4_mmio_arbitrate_read(uint32_t addr)
{
nv_log_verbose_only("MMIO read from address=0x%08x\n", addr);
uint32_t ret = 0x00;
if (addr >= NV4_PTIMER_START && addr <= NV4_PTIMER_END)
ret = nv4_ptimer_read(addr);
else if (addr >= NV4_PRAMDAC_START && addr <= NV4_PRAMDAC_END)
ret = nv4_pramdac_read(addr);
#ifdef NV_LOG
nv_register_t reg = nv_get_register(addr, &nv4_registers, sizeof(nv4_registers)/sizeof(nv4_registers[0]));
if (reg)
{
if (reg->on_read)
ret = reg->on_read();
nv_log_verbose_only("Register read from 0x%08x value=%08x", addr, ret);
}
#endif
}
void nv4_mmio_arbitrate_write(uint32_t addr, uint32_t val)
{
nv_log_verbose_only("MMIO write to address=0x%08x value %08x\n", addr, val);
if (addr >= NV4_PTIMER_START && addr <= NV4_PTIMER_END)
nv4_ptimer_write(addr, val);
else if (addr >= NV4_PRAMDAC_START && addr <= NV4_PRAMDAC_END)
nv4_pramdac_write(addr, val);
#ifdef NV_LOG
nv_register_t reg = nv_get_register(addr, &nv4_registers, sizeof(nv4_registers)/sizeof(nv4_registers[0]));
if (reg)
{
if (reg->on_write)
reg->on_write(val);
nv_log_verbose_only("Register write from 0x%08x value=%08x", addr, val);
}
#endif
}
// Determine if this address needs to be redirected to the SVGA subsystem.

View File

@@ -0,0 +1,46 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* NV4 debug register list
*
*
* Authors: Connor Hyde, <mario64crashed@gmail.com> I need a better email address ;^)
*
* Copyright 2024-2025 starfrost
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/io.h>
#include <86box/pci.h>
#include <86box/rom.h>
#include <86box/video.h>
#include <86box/nv/vid_nv.h>
#include <86box/nv/vid_nv4.h>
#ifdef NV_LOG
nv_register_t nv4_registers[] = {
{ NV4_PTIMER_INTR, "NV4 PTIMER - Interrupt Status", NULL, NULL},
{ NV4_PTIMER_INTR_EN, "NV4 PTIMER - Interrupt Enable", NULL, NULL,},
{ NV4_PTIMER_NUMERATOR, "NV4 PTIMER - Numerator", NULL, NULL, },
{ NV4_PTIMER_DENOMINATOR, "NV4 PTIMER - Denominator", NULL, NULL, },
{ NV4_PTIMER_TIME_0_NSEC, "NV4 PTIMER - Time0", NULL, NULL, },
{ NV4_PTIMER_TIME_1_NSEC, "NV4 PTIMER - Time1", NULL, NULL, },
{ NV4_PTIMER_ALARM_NSEC, "NV4 PTIMER - Alarm", NULL, NULL, },
{ NV4_PRAMDAC_VPLL_COEFF, "NV4 PRAMDAC - Pixel Clock Coefficient", NULL, NULL, },
{ NV4_PRAMDAC_NVPLL_COEFF, "NV4 PRAMDAC - GPU Core Clock Coefficient", NULL, NULL, },
{ NV4_PRAMDAC_MPLL_COEFF, "NV4 PRAMDAC - VRAM Clock Coefficient", NULL, NULL, },
{ NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value
};
#endif

View File

@@ -14,3 +14,71 @@
* Copyright 2024-2025 starfrost
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/pci.h>
#include <86box/rom.h> // DEPENDENT!!!
#include <86box/video.h>
#include <86box/nv/vid_nv.h>
#include <86box/nv/vid_nv4.h>
uint64_t nv4_pramdac_get_hz(uint32_t coeff, bool apply_divider)
{
uint32_t m = coeff & 0xFF;
uint32_t n = (coeff >> 8) & 0xFF;
uint32_t p = (coeff >> 16) & 0x07;
// Check clock base
uint32_t hz_base = (nv4->straps & (1 << NV4_STRAP_CRYSTAL)) ? 14318180 : 13500000;
uint32_t final_hz = (hz_base * n) / (m << p);
// Check VCLK divider
if (apply_divider)
{
if (nv4->pramdac.clk_coeff_select & (1 << NV4_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO))
final_hz >>= 1;
}
return final_hz;
}
void nv4_pramdac_set_vclk()
{
uint64_t final_hz = nv4_pramdac_get_hz(nv4->pramdac.nvclk, false);
//TODO: Everything
if (!nv4->nvbase.nv4_vclk_timer)
timer_set_delay_u64(nv4->nvbase.nv4_vclk_timer, final_hz / TIMER_USEC);
}
uint32_t nv4_pramdac_read(uint32_t address)
{
uint32_t ret = 0x00;
switch (address)
{
case NV4_PRAMDAC_VPLL_COEFF: // Pixel clock
ret = nv4->pramdac.vclk;
break;
case NV4_PRAMDAC_NVPLL_COEFF: // System clock
ret = nv4->pramdac.nvclk;
break;
case NV4_PRAMDAC_MPLL_COEFF: // Memory clock
ret = nv4->pramdac.mclk;
break;
}
}
void nv4_pramdac_write(uint32_t address, uint32_t data)
{
}