VOGONS


PCEm. Another PC emulator.

Topic actions

  • This topic is locked. You cannot reply or edit posts.

Reply 960 of 1046, by hail-to-the-ryzen

User metadata
Rank Member
Rank
Member

I agree given the optimizations are small. However, it would be worthwhile if the performance gains are high, such as >25%. I haven't seen any benchmarks in other x86/x87 emulators that show that gain is even possible.

One advantage is for considering or benchmarking against a dynamic recompiler core in a non-x86/x64 computer platform. There may be cases where an interpreter core is useful for other systems and where some early era of games are playable.

Reply 961 of 1046, by superfury

User metadata
Rank l33t++
Rank
l33t++

It's usually a 320x200 framebuffer, upscaled to 720x400 using double scanning and half pixel clocking as far as I know(CGA doesn't afaik).

The refresh rate is usually dependent on the output resolution (720x400 with front and back porch added) and the clock used(in this case 25MHz divided by 720(+porches)x400(+porces), which is the refresh rate). So in this case ~70Hz. Usually, VGA-compatible monitors should be able to handle it(it's a standard (S)VGA mode after all).

The only thing you can usually do, is modifying it or drivers to provide a different(higher) clock instead when asked for(e.g. 28MHz, the other standard VGA clock).

Lower frequencies require hardware modifications(putting in a different clock crystal). Not advised with modern graphics cards. Maybe possible with older VGA cards from the same period(basic VGA clones).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 963 of 1046, by superfury

User metadata
Rank l33t++
Rank
l33t++
SarahWalker wrote:

PCem will scale the emulated display to whatever resolution/refresh rate your desktop is running at - it makes no attempt to change either.

Whoops, you're right. I forgot that it's running inside an emulator, since bluejeans started talking about a crt, which is controlled by the OS running the emulator, not running bluejeans' application on the bare hardware. My comments then apply to the app within the emulator, thus requiring app modification or emulator modification to adjust refresh/render rates. The physical CRT isn't affected by either, running as the host OS directs it to(usually 60Hz or 70Hz).

The host OS probably just emulates the resolution(upscaling as needed). Thus you'll need to consult you display for exact rates. It usually can be found within some button menu on the screen, or it's manuals.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 964 of 1046, by hail-to-the-ryzen

User metadata
Rank Member
Rank
Member

Code below for exchanging openal dependency for directsound (credit to Winquake). It produces audio but requires further work and testing.

Requires the following modifications in addition to the code below:
* Replace object file soundopenal.o in Makefile with dsound.o
* Link to the directsound library: LIBS += -ldsound

Only tested in an older, non-SDL2 pcem build modified
for use of a single input sound source (ex. no CD audio)

For development only

diff -rupN pcem-orig//dsound.c pcem//dsound.c
--- pcem-orig//dsound.c
+++ pcem//dsound.c
@@ -0,0 +1,165 @@
+#include <windows.h>
+#include <dsound.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ibm.h"
+#include "sound.h"
+
+#define DIRECTSOUND_VERSION 0x0500
+
+// 64K is > 1 second at 16-bit, 22050 Hz = 0x10000 buffer size
+#define SECONDARY_BUFFER_SIZE 0x4000
+
+static void* lpData;
+static LPDIRECTSOUND pDS;
+static LPDIRECTSOUNDBUFFER pDSBuf;
+
+HWND ghwnd;
+
+void dsound_init(void);
+void dsound_free(void);
+
+/*
+==================
+dsound_init
+==================
+*/
+void dsound_init(void)
+{
+ DSBUFFERDESC dsbuf;
+ DSBCAPS dsbcaps;
+ DWORD dwSize, dwWrite;
+ DSCAPS dscaps;
+ WAVEFORMATEX format;
+ HRESULT hresult;
+ int reps;
+
+ memset (&format, 0, sizeof(format));
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = 2;
+ format.wBitsPerSample = 16;
+ format.nSamplesPerSec = 48000;
+ format.nBlockAlign = 4;
+ format.nAvgBytesPerSec = 192000;
+
Show last 156 lines
+	while ((hresult = DirectSoundCreate(NULL, &pDS, NULL)) != DS_OK)
+ {
+ pclog("directSound failed hardware in use\n");
+ return;
+ }
+
+ // pclog("1\n");
+
+ dscaps.dwSize = sizeof(dscaps);
+
+ if (DS_OK != pDS->lpVtbl->GetCaps (pDS, &dscaps))
+ {
+ pclog("no DS caps\n");
+ }
+
+ if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
+ {
+ pclog("no DirectSound driver installed\n");
+ dsound_free();
+ return;
+ }
+
+ if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, ghwnd, DSSCL_EXCLUSIVE))
+ {
+ pclog("setCooperativeLevel failed\n");
+ dsound_free();
+ return;
+ }
+
+ // create secondary buffer
+ memset (&dsbuf, 0, sizeof(dsbuf));
+ dsbuf.dwSize = sizeof(DSBUFFERDESC);
+ dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
+ dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
+ dsbuf.lpwfxFormat = &format;
+
+ memset(&dsbcaps, 0, sizeof(dsbcaps));
+ dsbcaps.dwSize = sizeof(dsbcaps);
+
+ if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
+ {
+ pclog ("createSoundBuffer Failed");
+ dsound_free();
+ return;
+ }
+
+ if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
+ {
+ pclog ("getCaps failed\n");
+ dsound_free();
+ return;
+ }
+
+ pclog("audio format: %d channel(s), %d bits/sample, %d bytes/sec\n",
+ format.nChannels, format.wBitsPerSample, format.nSamplesPerSec);
+ return;
+}
+
+/*
+==============
+dsound_free
+===============
+*/
+void dsound_free(void)
+{
+ int i;
+
+ if (pDSBuf) {
+ pDSBuf->lpVtbl->Stop(pDSBuf);
+ pDSBuf->lpVtbl->Release(pDSBuf);
+ }
+
+ if (pDS) {
+ pDS->lpVtbl->SetCooperativeLevel (pDS, ghwnd, DSSCL_NORMAL);
+ pDS->lpVtbl->Release(pDS);
+ }
+
+ pDS = NULL;
+ pDSBuf = NULL;
+ lpData = NULL;
+}
+
+/*
+==============
+copy_buffer
+===============
+*/
+void copy_buffer(int16_t *buf)
+{
+ int reps;
+ DWORD dwBytes;
+ HRESULT hresult;
+
+ // initialize buffer
+ reps = 0;
+
+ while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, 0, &lpData, &dwBytes, NULL, NULL, DSBLOCK_ENTIREBUFFER)) != DS_OK)
+ {
+ if (hresult != DSERR_BUFFERLOST) {
+ pclog ("lock sound buffer failed\n");
+ dsound_free();
+ return;
+ }
+
+ if (++reps > 10000) {
+ pclog ("unable to restore sound buffer\n");
+ dsound_free();
+ return;
+ }
+ }
+
+ // Copy audio data into buffer
+ memcpy(lpData, buf, dwBytes);
+ pDSBuf->lpVtbl->Unlock(pDSBuf, lpData, dwBytes, NULL, 0);
+ pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, 0);
+
+ return;
+}
diff -rupN pcem-orig//sound.c pcem//sound.c
--- pcem-orig//sound.c
+++ pcem//sound.c
@@ -87,8 +87,7 @@ static uint16_t *outbuffer;

void sound_init()
{
- initalmain(0,NULL);
- inital();
+ dsound_init();

outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int16_t));
}
@@ -124,7 +123,7 @@ void sound_get_buffer(void *priv)
for (c = 0; c < sound_handlers_num; c++)
sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv);

- givealbuffer(outbuffer);
+ copy_buffer(outbuffer);
}

void sound_reset()
diff -rupN pcem-orig//sound.h pcem//sound.h
--- pcem-orig//sound.h
+++ pcem//sound.h
@@ -16,10 +16,7 @@ void sound_speed_changed();
void sound_init();
void sound_reset();

-void initalmain(int argc, char *argv[]);
-void inital();
-
-void givealbuffer(int16_t *buf);
+void copy_buffer(int16_t *buf);

extern int sound_gain;

Reply 966 of 1046, by Battler

User metadata
Rank Member
Rank
Member

I am looking the recent PIC commit that implemented level-sensitive interrupts:
https://bitbucket.org/pcem_emulator/pcem/comm … cb6812d0c89696f
And I have a question - wouldn't the current implementation essentially prevent any IRQ's higher than the currently pending level-sensitive IRQ from being processed at all?

Edit: Also, this:

                                if (!(pic2.level_sensitive & (1 << c)))
pic.pend &= ~(1 << c);
pic.ins |= (1 << 2); /*Cascade IRQ*/
pic_update_mask(&pic.mask2, pic.ins);

Should IMHO be:

                                if (!pic2.pend & ~pic2.mask)
pic.pend &= ~(1 << 2);
pic.ins |= (1 << 2); /*Cascade IRQ*/
pic_update_mask(&pic.mask2, pic.ins);

It's IRQ 2's pending state that you're clearing there, while you were clearing the the PIC2's interrupt from PIC1. Also, it should be cleared if and only if no interrupt is pending on PIC2 anymore.

Reply 968 of 1046, by Battler

User metadata
Rank Member
Rank
Member

Yes, the driver indeed errors out when run after the mouse had been moved or even just identified (which is of course the case after Windows 95 has started and exited to DOS). It's because the serial ports' FIFO emulation is very over-simplified, which causes mouse drivers to not get the ID bytes right if they ID the mouse while the FIFO had been used before. Also notably lacking is FIFO width control and a no-FIFO mode which would be needed for mostly 486 and earlier because those tend to have the Intel 8255 or compatibles (which do not have a FIFO) instead of 16550(-compatibles).

Reply 970 of 1046, by Jo22

User metadata
Rank l33t++
Rank
l33t++

Regarding that maximum conventional memory on page 45, again..
"I have found out that IBM PC 5150 continues BIOS memory test to 704 kilobytes with undocumented
SW2 DIP switch settings ON ON OFF ON OFF and DOS automatically uses all of that as conventional memory.
This is an alternative way to utilize 64 kilobytes of RAM at segment A0000.
"
Source.

"Time, it seems, doesn't flow. For some it's fast, for some it's slow.
In what to one race is no time at all, another race can rise and fall..." - The Minstrel

//My video channel//

Reply 971 of 1046, by Battler

User metadata
Rank Member
Rank
Member

I just saw this commit: https://bitbucket.org/pcem_emulator/pcem/comm … d11056702919eee .
Are we sure this is the right solution? It looks to me like this is a hack to get around the problem I pointed out, thought I need to look at the RTL8029AS specification for this.

Edit: Here's the quote from the RTL8029AS datasheet:

All bits correspond to the bits in the ISR register. POWER UP=all 0s. Setting individual bits will enable the
corresponding interrupts.

Are we sure the current implemenetation of the IMR is even remotely correct? IIRC this was originally ported from DOSBox and I have no idea whether or not the implementation there is correct. From how I interpret this, a bit from IMR, when set, makes the card issue that type of interrupt. If it's clear, such an interrupt is not issued.

Edit #2: Seems I misunderstood the code. What the code does is, checks if any unmasked interrupts are currently pending and raises the interrupt if yes, otherwise it lowers the interrupt. This is OK. However, my point about the implementation of level-sensitive interrupts still stands - it *IS* going to prevent all other interrupts from being processed, causing Windows 9x to triple fault reset when someone attempts a large download over the network.

Reply 972 of 1046, by hail-to-the-ryzen

User metadata
Rank Member
Rank
Member

In this commit: "Implement read & write masks on S3 blitter...", there is this portion:

                                         if (vram_mask)
{
- READ(s3->accel.src + s3->accel.cx, mix_dat)
+ READ_SRC(s3->accel.src + s3->accel.cx, mix_dat)
+
mix_dat = mix_dat ? mix_mask : 0;

but semicolon missing from the added line.

Reply 978 of 1046, by hail-to-the-ryzen

User metadata
Rank Member
Rank
Member

In my case, the ctmouse driver is now loading the serial mouse device after exiting Windows 95. The cause was in model.c which initializes the serial port for the ctmouse at a set address and irq, but this port setting was later removed wherever serial1_remove() was called and in addition any serial port setting in the bios should not use that same serial port dedicated to the serial mouse.