diff --git a/doc/RIVA fansites.txt b/doc/RIVA fansites.txt new file mode 100644 index 000000000..5a3104837 --- /dev/null +++ b/doc/RIVA fansites.txt @@ -0,0 +1,24 @@ +RIVA fansites (?????): +RIVA User's Group http://tiger.tnstate.edu:8080/ +RIVA 128 Homepage http://pages.prodigy.net/babblin5/Main.html -> Riva3D (riva3d.com) +Zone 128 http://www.tc.umn.edu/~reda0003/zone128/ +RIVAZone https://web.archive.org/web/19981212032348/http://www.rivazone.com/ (Launched January 2, 1998) +Dimension 128 (early domain name that was never archived) -> d128.com (1999-2001) +Riva3D https://web.archive.org/web/20000525110305/http://riva3d.gxnetwork.com/s3.html +nVNews https://web.archive.org/web/20001205171202/http://www.nvnews.net/ (1999-2015) + +BluesNews has stuff https://www.bluesnews.com/archives/ +(July 1996-present!) + +https://www.bluesnews.com/archives/july97-3.html July 21, 1997 ("unreleased nvidia RIVA chipset is indeed faster than 3dfx" (carmack) + +"However, using the nvidia RIVA 128 chip it runs 1 f/s faster" + +https://web.archive.org/web/19980615024744/http://www.ogr.com/columns/techtalk/technology_talk_0611_2.shtml First mention of NV10 (June 1998) + +"RIVA 128 Turbo" early ZX name +"Riva4" early TNT name + +https://web.archive.org/web/20001002193706/http://www.rivazone.com/files/rivalog.txt + +https://web.archive.org/web/20010422044820/http://www.rivazone.com/finger/finger.cgi?nick@finger.nvidia.com nvidia .plan files \ No newline at end of file diff --git a/doc/Versions.txt b/doc/Versions.txt new file mode 100644 index 000000000..052de854f --- /dev/null +++ b/doc/Versions.txt @@ -0,0 +1,8 @@ +Name Base Version Notes Date API Support Platform +0.75_nt4 Version 0.75 No Resource Manager (miniport) 1997-08-15 GDI NT4.0 +0.77_win9x Version 0.77 Symbols (COFF/VXD) 1997-09-02 GDI, D3D5 +nv3quake.zip Version 1.21 OpenGL Alpha 1 1997-11-14 GDI, D3D5, OpenGL 1.1 (alpha; Build 151) Win9x +quakea2f.zip Version 1.21 OpenGL Alpha 2 1997-12-02 GDI, D3D5, OpenGL 1.1 (alpha; Build 258) Win9x +win95_131.zip Version 1.31 OpenGL Beta 1 1998-02-04 GDI, D3D5, OpenGL 1.1 (beta; Build 661) Win9x + + diff --git a/doc/gpucompanies.txt b/doc/gpucompanies.txt new file mode 100644 index 000000000..08a6c61c5 --- /dev/null +++ b/doc/gpucompanies.txt @@ -0,0 +1,63 @@ +GPU companies (the period they made gpus) + +DEC 19xx-1998 +HP 19xx-2000+ (possibly until present) +IBM 19xx-2002+ (possibly until present) +E&S 1968-2006 +Intergraph 1969-2000 +Apple 1976-present (some break) +Motorola 1977-1994+ (???) +TI 1979-1988+ +Matrox 1979-2014 +Hitachi 1981-1986 +SGI 1981-2009 +Intel 1983-present +Number Nine 1983-2000 +Tseng Labs 1983-1997 +Cirrus Logic 1984-1998 +Video 7 1985-1991 +C&T 1985-1999 +Imagination 1985-present +NCR 1986-1993 +Paradise/WD 1986-1996 +Gemini 1987-1990 +Genoa Systems 1987-1991 +Trident 1987-2003 +Oak Technology 1988-1997 +Realtek 1988-1997 +Compaq 1989-1991 +Sun 1989-2002(+?) +S3 Graphics 1989-2010 +Macronix 1989-1998 +Winbond 1989-1996+ +Tamarack 198x-1991+ +UMC 198x-1993 +Sigma Designs 198x-1996 +Acer 198x-1998 (roughly) +Fujitsu 198x-1998 +AMD 1991-present (really starting in 2006) +HMC 1991-1994 +Avance Logic 1991-1995 +Weitek <1991-1996 +Bitboys 1991-2006 +IIT 1992-1994 +Weitek 1992-1996(?) +Rendition 1993-1998 +ARK Logic 1993-1999 +S-MOS/Stellar 1994-1999 +Nvidia 1993-present +Alliance 1994-1997 +iGS 1994-1999 +3dfx 1994-2000 +3dlabs 1994-2006 +Silicon Motion 1995-200? +SiS 1995-2007 +Dynamic Pictures1996-1997 +NeoMagic 1996-2000 +GigaPixel 1997-2000 +Philips 1997-199x +Tatung 199x-199x +ASPEED 2004-present +Jingjia 2006-present + + diff --git a/src/86box.c b/src/86box.c index 5e1f58413..1bb24b055 100644 --- a/src/86box.c +++ b/src/86box.c @@ -103,6 +103,7 @@ #include <86box/machine_status.h> #include <86box/apm.h> #include <86box/acpi.h> +#include <86box/nv/vid_nv_rivatimer.h> // Disable c99-designator to avoid the warnings about int ng #ifdef __clang__ @@ -1421,6 +1422,9 @@ pc_run(void) pc_reset_hard_init(); } + /* Update the guest-CPU independent timer for devices with independent clock speed */ + rivatimer_update_all(); + /* Run a block of code. */ startblit(); cpu_exec((int32_t) cpu_s->rspeed / 100); diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index 48ba92526..7e8f6f7c1 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -318,14 +318,30 @@ extern const device_config_t nv3_config[]; #define NV3_PGRAPH_CONTEXT_USER 0x400194 // Current DMA context state, may rename #define NV3_PGRAPH_CONTEXT_CACHE(i) 0x4001A0+(i*4) // Context Cache #define NV3_PGRAPH_CONTEXT_CACHE_SIZE 8 -#define NV3_PGRAPH_SRC_CANVAS_MIN 0x440550 // Minimum Source Canvas for Blit, X,Y position -#define NV3_PGRAPH_SRC_CANVAS_MAX 0x440554 // Maximum Source Canvas for Blit, X,Y position -#define NV3_PGRAPH_DST_CANVAS_MIN 0x440558 // Minimum Destination Canvas for Blit, X,Y position -#define NV3_PGRAPH_DST_CANVAS_MAX 0x44055C // Maximum Destination Canvas for Blit, X,Y position -#define NV3_PGRAPH_CLIP0_MIN 0x440690 // Clip for Blitting 0 Min -#define NV3_PGRAPH_CLIP0_MAX 0x440694 // Clip for Blitting 0 Max -#define NV3_PGRAPH_CLIP1_MIN 0x440698 // Clip for Blitting 1 Min -#define NV3_PGRAPH_CLIP1_MAX 0x44069C // Clip for Blitting 1 Max +#define NV3_PGRAPH_ABS_UCLIP_XMIN 0x40053C // Clip X minimum +#define NV3_PGRAPH_ABS_UCLIP_XMAX 0x400540 // Clip X maximum +#define NV3_PGRAPH_ABS_UCLIP_YMIN 0x400544 // Clip Y minimum +#define NV3_PGRAPH_ABS_UCLIP_YMAX 0x400548 // Clip Y maximum +#define NV3_PGRAPH_SRC_CANVAS_MIN 0x400550 // Minimum Source Canvas for Blit, X,Y position +#define NV3_PGRAPH_SRC_CANVAS_MAX 0x400554 // Maximum Source Canvas for Blit, X,Y position +#define NV3_PGRAPH_DST_CANVAS_MIN 0x400558 // Minimum Destination Canvas for Blit, X,Y position +#define NV3_PGRAPH_DST_CANVAS_MAX 0x40055C // Maximum Destination Canvas for Blit, X,Y position +#define NV3_PGRAPH_PATTERN_COLOR_0_0 0x400600 +#define NV3_PGRAPH_PATTERN_COLOR_0_1 0x400604 +#define NV3_PGRAPH_PATTERN_COLOR_1_0 0x400608 +#define NV3_PGRAPH_PATTERN_COLOR_1_1 0x40060C // pattern color +#define NV3_PGRAPH_PATTERN_BITMAP_HIGH 0x400610 // pattern bitmap [31:0] +#define NV3_PGRAPH_PATTERN_BITMAP_LOW 0x400614 // pattern bitmap [63:32] +#define NV3_PGRAPH_PATTERN_SHAPE 0x400618 +#define NV3_PGRAPH_ROP3 0x400624 // ROP3 +#define NV3_PGRAPH_PLANE_MASK 0x400628 +#define NV3_PGRAPH_CHROMA_KEY 0x40062C +#define NV3_PGRAPH_BETA 0x400640 // Beta factor (30:23 fractional, 22:0 before fraction) +#define NV3_PGRAPH_NOTIFY 0x400684 // Notifier for PGRAPH +#define NV3_PGRAPH_CLIP0_MIN 0x400690 // Clip for Blitting 0 Min +#define NV3_PGRAPH_CLIP0_MAX 0x400694 // Clip for Blitting 0 Max +#define NV3_PGRAPH_CLIP1_MIN 0x400698 // Clip for Blitting 1 Min +#define NV3_PGRAPH_CLIP1_MAX 0x40069C // Clip for Blitting 1 Max #define NV3_PGRAPH_FIFO_ACCESS 0x4006A4 // Is PGRAPH enabled? #define NV3_PGRAPH_FIFO_ACCESS_DISABLED 0x0 #define NV3_PGRAPH_FIFO_ACCESS_ENABLED 0x1 @@ -335,6 +351,8 @@ extern const device_config_t nv3_config[]; #define NV3_PGRAPH_TRAPPED_DATA 0x4006B8 #define NV3_PGRAPH_TRAPPED_INSTANCE 0x4006BC +#define NV3_PGRAPH_DMA_INTR_0 0x401000 // PGRAPH DMA Interrupt Status +#define NV3_PGRAPH_DMA_INTR_EN_0 0x401140 // PGRAPH DMA Interrupt Enable 0 // not sure about the class ids // these are NOT what each class is, just uSed to manipulate it (there isn't a one to one class->reg mapping anyway) diff --git a/src/include/86box/nv/vid_nv_rivatimer.h b/src/include/86box/nv/vid_nv_rivatimer.h new file mode 100644 index 000000000..00e94cd97 --- /dev/null +++ b/src/include/86box/nv/vid_nv_rivatimer.h @@ -0,0 +1,83 @@ +/* + * 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. + * + * Fast, high-frequency, guest CPU-independent timer for Riva emulation. + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +/* +RivaTimer + +This is a fast, high-frequency, guest CPU-independent timer. + +The main 86box timer is dependent on the TSC (time-stamp counter) register of the emulated CPU core. +This is fine for most purposes and has advantages in the fields of synchronisation and integrates neatly with +the clock dividers of the PC architecture, but in the case of the RIVA 128 it does not particularly suffice +(although it can be made to work with various techniques) since the clock source on the RIVA 128 is on the board itself +and the GPU has several different clocks that control different parts of the GPU (e.g., PTIMER runs on the memory clock but the core gpu is using the pixel clock). + +As faster graphics cards that offload more and more of the 3D graphics pipeline are emulated in the future, more and more work needs to be done by the emulator and +issues of synchronisation with a host CPU will simply make that work harder. Some features that are required for + +Architecture Brand Name 3D Features +NV1 (1995) NV1 Some weird URBS rectangle crap but feature set generally similar to nv3 but a bit worse +NV3 (1997) RIVA 128 (ZX) Triangle setup, edge-slope calculations, edge interpolation, span-slope calculations, span interpolation (Color-buffer, z-buffer, texture mapping, filtering) +NV4 (1998) RIVA TNT NV3 + 2x1 pixel pipelines + 32-bit colour + larger textures + trilinear + more ram (16mb) +NV5 (1999) RIVA TNT2 NV4 + higher clock speed +NV10 (1999) GeForce 256 NV5 + initial geometry transformation + lighting (8x lights) + MPEG-2 motion compensation + 4x1 pixel pipelines +NV15 (2000) GeForce 2 NV10 + First attempt at programmability + 4x2 pixel pipelines +NV20 (2001) GeForce 3 Programmable shaders! + +As you can see, the performance basically exponentially increases over a period of only 4 years. + +So I decided to create this timer that is completely separate from the CPU Core. +*/ + +#pragma once +#include +#include +#include +#include +#include <86Box\86box.h> + +#ifdef _WIN32 +#include +// Linux & MacOS should have the same API since OSX 10.12 +#else +#include +#endif + +typedef struct rivatimer_s +{ + struct rivatimer_s* prev; // Previous Rivatimer + double period; // Period in uS before firing + double value; // The current value of the rivatimer + bool running; // Is this RivaTimer running? + struct rivatimer_s* next; // Next RivaTimer + void (*callback)(); // Callback to call on fire + #ifdef _WIN32 + LARGE_INTEGER starting_time; // Starting time. + #else + struct timespec starting_time; // Starting time. + #endif + double time; // Accumulated time in uS. +} rivatimer_t; + +void rivatimer_init(); // Initialise the Rivatimer. +rivatimer_t* rivatimer_create(double period, void (*callback)()); +void rivatimer_destroy(rivatimer_t* rivatimer_ptr); + +void rivatimer_update_all(); +void rivatimer_start(rivatimer_t* rivatimer_ptr); +void rivatimer_stop(rivatimer_t* rivatimer_ptr); +double rivatimer_get_time(rivatimer_t* rivatimer_ptr); +void rivatimer_set_callback(rivatimer_t* rivatimer_ptr, void (*callback)()); \ No newline at end of file diff --git a/src/timer.c b/src/timer.c index 6ddf8ebb5..2b92a1958 100644 --- a/src/timer.c +++ b/src/timer.c @@ -4,6 +4,7 @@ #include #include <86box/86box.h> #include <86box/timer.h> +#include <86Box/nv/vid_nv_rivatimer.h> uint64_t TIMER_USEC; uint32_t timer_target; @@ -168,6 +169,9 @@ timer_init(void) timer_target = 0ULL; tsc = 0; + /* Initialise the CPU-independent timer */ + rivatimer_init(); + timer_inited = 1; } diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index a7bc62326..4b927c9ea 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -28,8 +28,8 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_mga.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c vid_xga.c vid_bochs_vbe.c - nv/nv_base.c - nv/nv3/nv3_core.c nv/nv3/nv3_core_config.c nv/nv3/nv3_core_arbiter.c nv/nv3/nv3_interrupt.c + nv/nv_base.c nv/nv_rivatimer.c + nv/nv3/nv3_core.c nv/nv3/nv3_core_config.c nv/nv3/nv3_core_arbiter.c nv/nv3/subsystems/nv3_pramdac.c nv/nv3/subsystems/nv3_pfifo.c nv/nv3/subsystems/nv3_pgraph.c diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index e78d624e1..f0ff0f028 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -13,7 +13,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include #include diff --git a/src/video/nv/nv3/nv3_core_arbiter.c b/src/video/nv/nv3/nv3_core_arbiter.c index 41799c760..48c0c93db 100644 --- a/src/video/nv/nv3/nv3_core_arbiter.c +++ b/src/video/nv/nv3/nv3_core_arbiter.c @@ -16,7 +16,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ // STANDARD NV3 includes diff --git a/src/video/nv/nv3/nv3_core_config.c b/src/video/nv/nv3/nv3_core_config.c index d7944b69c..3bc8692b9 100644 --- a/src/video/nv/nv3/nv3_core_config.c +++ b/src/video/nv/nv3/nv3_core_config.c @@ -11,7 +11,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include #include diff --git a/src/video/nv/nv3/nv3_interrupt.c b/src/video/nv/nv3/nv3_interrupt.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/video/nv/nv3/subsystems/nv3_pbus.c b/src/video/nv/nv3/subsystems/nv3_pbus.c index fddedd5cf..5d50bf2fb 100644 --- a/src/video/nv/nv3/subsystems/nv3_pbus.c +++ b/src/video/nv/nv3/subsystems/nv3_pbus.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email dataess ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pbus_dma.c b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c index 825f326f2..8043fd758 100644 --- a/src/video/nv/nv3/subsystems/nv3_pbus_dma.c +++ b/src/video/nv/nv3/subsystems/nv3_pbus_dma.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pextdev.c b/src/video/nv/nv3/subsystems/nv3_pextdev.c index 761bacdb3..485763696 100644 --- a/src/video/nv/nv3/subsystems/nv3_pextdev.c +++ b/src/video/nv/nv3/subsystems/nv3_pextdev.c @@ -13,7 +13,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pfb.c b/src/video/nv/nv3/subsystems/nv3_pfb.c index e1d1c8352..9711f3c9a 100644 --- a/src/video/nv/nv3/subsystems/nv3_pfb.c +++ b/src/video/nv/nv3/subsystems/nv3_pfb.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pfifo.c b/src/video/nv/nv3/subsystems/nv3_pfifo.c index 8f8abbac4..772839128 100644 --- a/src/video/nv/nv3/subsystems/nv3_pfifo.c +++ b/src/video/nv/nv3/subsystems/nv3_pfifo.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pgraph.c b/src/video/nv/nv3/subsystems/nv3_pgraph.c index ac2970e35..b1696f950 100644 --- a/src/video/nv/nv3/subsystems/nv3_pgraph.c +++ b/src/video/nv/nv3/subsystems/nv3_pgraph.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pmc.c b/src/video/nv/nv3/subsystems/nv3_pmc.c index 379c4ed7c..f69b2b430 100644 --- a/src/video/nv/nv3/subsystems/nv3_pmc.c +++ b/src/video/nv/nv3/subsystems/nv3_pmc.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pme.c b/src/video/nv/nv3/subsystems/nv3_pme.c index 9683ff5ab..8e0b7ddb5 100644 --- a/src/video/nv/nv3/subsystems/nv3_pme.c +++ b/src/video/nv/nv3/subsystems/nv3_pme.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pramdac.c b/src/video/nv/nv3/subsystems/nv3_pramdac.c index 3dec7329a..ed89f9448 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramdac.c +++ b/src/video/nv/nv3/subsystems/nv3_pramdac.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ // nv3_pramdac.c: NV3 RAMDAC diff --git a/src/video/nv/nv3/subsystems/nv3_pramin.c b/src/video/nv/nv3/subsystems/nv3_pramin.c index 9750e2f4c..7448f77c7 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin.c @@ -13,7 +13,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c index 9a397c8d7..0d141a222 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramfc.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c index baadb9666..5cb9e9d86 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramht.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c index 46c95deac..dd96adb40 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c +++ b/src/video/nv/nv3/subsystems/nv3_pramin_ramro.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_ptimer.c b/src/video/nv/nv3/subsystems/nv3_ptimer.c index ca86716c0..1eb53409a 100644 --- a/src/video/nv/nv3/subsystems/nv3_ptimer.c +++ b/src/video/nv/nv3/subsystems/nv3_ptimer.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv3/subsystems/nv3_pvideo.c b/src/video/nv/nv3/subsystems/nv3_pvideo.c index 1aede7b0c..ea929ad2c 100644 --- a/src/video/nv/nv3/subsystems/nv3_pvideo.c +++ b/src/video/nv/nv3/subsystems/nv3_pvideo.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ #include diff --git a/src/video/nv/nv_base.c b/src/video/nv/nv_base.c index b67c65dc2..da776a721 100644 --- a/src/video/nv/nv_base.c +++ b/src/video/nv/nv_base.c @@ -12,7 +12,7 @@ * * Authors: Connor Hyde, I need a better email address ;^) * - * Copyright 2024 starfrost + * Copyright 2024-2025 starfrost */ // Common NV1/3/4... init diff --git a/src/video/nv/nv_rivatimer.c b/src/video/nv/nv_rivatimer.c new file mode 100644 index 000000000..27c63088d --- /dev/null +++ b/src/video/nv/nv_rivatimer.c @@ -0,0 +1,248 @@ +/* + * 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. + * + * Fast, high-frequency, CPU-independent timer. + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +/* See vid_nv_rivatimer.h comments for rationale behind not using the regular timer system + +Notes applicable to this file: +Since Windows XP, QueryPerformanceCounter and QueryPerformanceFrequency cannot fail so they are not checked. + +*/ + +#include <86Box/nv/vid_nv_rivatimer.h> + +#ifdef _WIN32 +LARGE_INTEGER performance_frequency; +#endif + +rivatimer_t* rivatimer_head; // The head of the rivatimer list. +rivatimer_t* rivatimer_tail; // The tail of the rivatimer list. + +/* Functions only used in this translation unit */ +bool rivatimer_really_exists(rivatimer_t* rivatimer); // Determine if a rivatimer really exists in the linked list. + +void rivatimer_init() +{ + // Destroy all the rivatimers. + rivatimer_t* rivatimer_ptr = rivatimer_head; + + if (!rivatimer_ptr) + return; + + while (rivatimer_ptr->next) + rivatimer_destroy(rivatimer_ptr); + + #ifdef _WIN32 + // Query the performance frequency. + QueryPerformanceFrequency(&performance_frequency); + #endif +} + +// Creates a rivatimer. +rivatimer_t* rivatimer_create(double period, void (*callback)()) +{ + rivatimer_t* new_rivatimer = NULL; + + // See i + if (period <= 0 + || !callback) + { + fatal("Invalid rivatimer_create call: period <= 0 or no callback"); + } + + // If there are no rivatimers, create one + if (!rivatimer_head) + { + rivatimer_head = calloc(1, sizeof(rivatimer_t)); + rivatimer_head->prev = NULL; // indicate this is the first in the list even if we don't strictly need to + rivatimer_tail = rivatimer_head; + new_rivatimer = rivatimer_head; + } + else // Otherwise add a new one to the list + { + rivatimer_tail->next = calloc(1, sizeof(rivatimer_t)); + rivatimer_tail = rivatimer_tail->next; + new_rivatimer = rivatimer_tail; + } + + // sanity check + if (new_rivatimer) + { + new_rivatimer->running = false; + new_rivatimer->period = period; + new_rivatimer->next = NULL; // indicate this is the last in the list + new_rivatimer->callback = callback; + } + + return new_rivatimer; +} + +// Determines if a rivatimer really exists. +bool rivatimer_really_exists(rivatimer_t* rivatimer) +{ + rivatimer_t* current = rivatimer_head; + + if (!current) + return false; + + while (current->next != NULL) + { + if (current == rivatimer) + return true; + } + + return false; +} + +// Destroy a rivatimer. +void rivatimer_destroy(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_destroy: The timer was already destroyed, or never existed in the first place. Punch starfrost in the face"); + + // Case: We are destroying the head + if (rivatimer_ptr == rivatimer_head) + { + // This is the only rivatimer + if (rivatimer_ptr->next == NULL) + { + rivatimer_head = NULL; + rivatimer_tail = NULL; + } + // This is not the only rivatimer + else + { + rivatimer_head = rivatimer_ptr->next; + rivatimer_head->prev = NULL; + // This is the only rivatimer and now there is only one + if (!rivatimer_head->next) + rivatimer_tail = rivatimer_head; + } + } + // Case: We are destroying the tail + else if (rivatimer_ptr == rivatimer_tail) + { + // We already covered the case where there is only one item above + rivatimer_tail = rivatimer_ptr->prev; + rivatimer_tail->next = NULL; + } + // Case: This is not the first or last rivatimer, so we don't need to set the head or tail + else + { + // Fix the break in the chain that this + if (rivatimer_ptr->next) + rivatimer_ptr->prev->next = rivatimer_ptr->next; + if (rivatimer_ptr->prev) + rivatimer_ptr->next->prev = rivatimer_ptr->prev; + } + + free(rivatimer_ptr); + rivatimer_ptr = NULL; //explicitly set to null +} + +void rivatimer_update_all() +{ + rivatimer_t* rivatimer_ptr = rivatimer_head; + + if (!rivatimer_ptr) + return; + + while (rivatimer_ptr->next) + { + if (!rivatimer_ptr->running) + continue; + + #ifdef _WIN32 + LARGE_INTEGER current_time; + + QueryPerformanceCounter(¤t_time); + + double microseconds = ((double)current_time.QuadPart / 1000000.0) - (rivatimer_ptr->starting_time.QuadPart / 1000000.0); + #else + struct timespec current_time; + + clock_gettime(CLOCK_REALTIME, ¤t_time); + + double microseconds = ((double)current_time.tv_sec * 1000000.0) + ((double)current_time.tv_nsec / 1000.0); + #endif + + rivatimer_ptr->time += microseconds; + + // Reset the current time so we can actually restart + #ifdef _WIN32 + QueryPerformanceCounter(&rivatimer_ptr->starting_time); + #else + clock_gettime(CLOCK_REALTIME, &rivatimer_ptr->starting_time); + #endif + + // Time to fire + if (microseconds > rivatimer_ptr->period) + { + if (!rivatimer_ptr->callback) + { + pclog("Eh? No callback in RivaTimer?"); + continue; + } + + rivatimer_ptr->callback(); + } + } + +} + +void rivatimer_start(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_start: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + if (rivatimer_ptr->period <= 0) + fatal("rivatimer_start: Zero period!"); + + rivatimer_ptr->running = true; + + // Start off so rivatimer_update_all can actually update. + #ifdef _WIN32 + QueryPerformanceCounter(&rivatimer_ptr->starting_time); + #else + clock_gettime(CLOCK_REALTIME, &rivatimer_ptr->starting_time); + #endif +} + +void rivatimer_stop(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_stop: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + rivatimer_ptr->running = false; +} + +// Get the current time value of a rivatimer +double rivatimer_get_time(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_get_time: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); +} + +void rivatimer_set_callback(rivatimer_t* rivatimer_ptr, void (*callback)()) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_set_callback: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + if (!callback) + fatal("rivatimer_set_callback: No callback!"); + + rivatimer_ptr->callback = callback; +} \ No newline at end of file