Skip to content

Commit

Permalink
More work on emulator audio (especially for wasm)
Browse files Browse the repository at this point in the history
  • Loading branch information
visrealm committed Sep 17, 2023
1 parent b514964 commit b3108c9
Show file tree
Hide file tree
Showing 13 changed files with 102 additions and 77 deletions.
1 change: 0 additions & 1 deletion emulator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,4 @@ else()
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/imgui.ini DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
endif()

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/imgui.ini DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/roms DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
28 changes: 15 additions & 13 deletions emulator/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@



add_executable (Hbc56Emu WIN32)
file(GLOB_RECURSE SRC_DEVICES
"${CMAKE_CURRENT_SOURCE_DIR}/devices/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/devices/*.h"
)
file(GLOB_RECURSE SRC_DEBUGGER
"${CMAKE_CURRENT_SOURCE_DIR}/debugger/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/debugger/*.h"
)

add_definitions(-DVR_6502_EMU_STATIC)
source_group ("debugger" FILES ${SRC_DEBUGGER})
source_group ("devices" FILES ${SRC_DEVICES})

add_executable (Hbc56Emu WIN32 ${SRC_DEBUGGER} ${SRC_DEVICES})

add_definitions(-DVR_6502_EMU_STATIC)

target_sources(Hbc56Emu
PUBLIC hbc56emu.h
PRIVATE hbc56emu.cpp
audio.c
debugger/debugger.cpp
devices/6502_device.c
devices/ay38910_device.c
devices/device.c
devices/keyboard_device.c
devices/lcd_device.c
devices/memory_device.c
devices/nes_device.c
devices/tms9918_device.c
devices/uart_device.c
devices/via_device.c)
audio.h
config.h)

if (WIN32)
target_sources(Hbc56Emu PRIVATE Hbc56Emu.rc)
Expand Down
2 changes: 1 addition & 1 deletion emulator/src/audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void hbc56Audio(int start)
want.freq = HBC56_AUDIO_FREQ;
want.format = AUDIO_F32SYS;
want.channels = 2;
want.samples = 1024;
want.samples = 2048;
want.callback = hbc56AudioCallback;
if (SDL_OpenAudio(&want, &audioSpec) == 0) audioDevice = 1;

Expand Down
25 changes: 22 additions & 3 deletions emulator/src/devices/6502_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

static void reset6502CpuDevice(HBC56Device*);
static void destroy6502CpuDevice(HBC56Device*);
static void tick6502CpuDevice(HBC56Device*, uint32_t, double);
static void tick6502CpuDevice(HBC56Device*, uint32_t, float);

#define CPU_6502_MAX_CALL_STACK 128
#define CPU_6502_JSR 0x20
Expand All @@ -45,6 +45,8 @@ struct CPU6502Device
uint64_t ticks;
uint64_t ticksWai;
int extraTicks;
double secsPerTick;
double runTimeSeconds;
IsBreakpointFn isBreakFn;
};
typedef struct CPU6502Device CPU6502Device;
Expand All @@ -56,7 +58,7 @@ void hbc56MemWrite(uint16_t addr, uint8_t val);
* --------------------
* create an AY-3-8910 PSG device
*/
HBC56Device create6502CpuDevice(IsBreakpointFn brkCb)
HBC56Device create6502CpuDevice(IsBreakpointFn brkCb, int clockFreqHz)
{
HBC56Device device = createDevice("6502 CPU");
CPU6502Device* cpuDevice = (CPU6502Device*)malloc(sizeof(CPU6502Device));
Expand All @@ -69,6 +71,8 @@ HBC56Device create6502CpuDevice(IsBreakpointFn brkCb)
cpuDevice->callStackPtr = 0;
cpuDevice->breakMode = 0;
cpuDevice->breakAddr = 0;
cpuDevice->secsPerTick = 1.0 / (double)clockFreqHz;
cpuDevice->runTimeSeconds = 0.0;
cpuDevice->ticks = cpuDevice->ticksWai = 0L;
cpuDevice->extraTicks = 0;
cpuDevice->isBreakFn = brkCb;
Expand Down Expand Up @@ -141,7 +145,7 @@ static inline void checkInterrupt(HBC56InterruptSignal* status, vrEmu6502Interru
}
}

static void tick6502CpuDevice(HBC56Device* device, uint32_t deltaTicks, double deltaTime)
static void tick6502CpuDevice(HBC56Device* device, uint32_t deltaTicks, float deltaTime)
{
CPU6502Device* cpuDevice = get6502CpuDevice(device);
if (cpuDevice)
Expand Down Expand Up @@ -226,6 +230,10 @@ static void tick6502CpuDevice(HBC56Device* device, uint32_t deltaTicks, double d
}

cpuDevice->ticks += cycleTicks;

// note: we do this now rather than at the end, because some devices require accurate timing
cpuDevice->runTimeSeconds += cycleTicks * cpuDevice->secsPerTick;

if (vrEmu6502GetCurrentOpcode(cpuDevice->cpu6502) == CPU_6502_WAI)
{
cpuDevice->ticksWai += cycleTicks;
Expand Down Expand Up @@ -344,5 +352,16 @@ VrEmu6502* getCpuDevice(HBC56Device* device)
return NULL;
}

double getCpuRuntimeSeconds(HBC56Device* device)
{
CPU6502Device* cpuDevice = get6502CpuDevice(device);
if (cpuDevice)
{
return cpuDevice->runTimeSeconds;;
}
return 0;
}



#endif
4 changes: 3 additions & 1 deletion emulator/src/devices/6502_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ typedef enum
* --------------------
* create a 6502 CPU device
*/
HBC56Device create6502CpuDevice(IsBreakpointFn brkCb);
HBC56Device create6502CpuDevice(IsBreakpointFn brkCb, int clockFreqHz);

void interrupt6502(HBC56Device* device, HBC56InterruptType type, HBC56InterruptSignal signal);

Expand All @@ -50,6 +50,8 @@ VrEmu6502* getCpuDevice(HBC56Device* device);

float getCpuUtilization(HBC56Device* device);

double getCpuRuntimeSeconds(HBC56Device* device);

#ifdef __cplusplus
}
#endif
Expand Down
66 changes: 29 additions & 37 deletions emulator/src/devices/ay38910_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*
*/

#include "hbc56emu.h"
#include "ay38910_device.h"

#include "emu2149.h"
Expand All @@ -24,14 +25,15 @@ static void destroyAy38910Device(HBC56Device*);
static void audioAy38910Device(HBC56Device* device, float* buffer, int numSamples);
static uint8_t readAy38910Device(HBC56Device*, uint16_t, uint8_t*, uint8_t);
static uint8_t writeAy38910Device(HBC56Device*, uint16_t, uint8_t);
static void tickAy38910Device(HBC56Device*, uint32_t, double);
static void tickAy38910Device(HBC56Device*, uint32_t, float);

#define AY3891X_INACTIVE 0x03
#define AY3891X_READ 0x02
#define AY3891X_WRITE 0x01
#define AY3891X_ADDR 0x00

#define BUFFER_MAX_SIZE 4096
#define BUFFER_MAX_SIZE 16384
#define BUFFER_MASK (BUFFER_MAX_SIZE - 1)

struct AY38910Device
{
Expand All @@ -43,6 +45,7 @@ struct AY38910Device
int bufferEnd;
double deltaTimeOverFlow;
double timePerSample;
double lastCpuRuntimeSeconds;
PSG* psg;
SDL_mutex* mutex;
};
Expand Down Expand Up @@ -129,30 +132,33 @@ static inline void addSampleToBuffer(AY38910Device* ayDevice)
PSG_calc(ayDevice->psg);

ayDevice->buffer[ayDevice->bufferEnd++] = ((ayDevice->psg->ch_out[0] * 2 + ayDevice->psg->ch_out[2]) / (8192.0f * 3.0f));
ayDevice->bufferEnd &= 0x0fff;
ayDevice->bufferEnd &= BUFFER_MASK;

if (ayDevice->channels > 1)
{
ayDevice->buffer[ayDevice->bufferEnd++] = ((ayDevice->psg->ch_out[1] * 2 + ayDevice->psg->ch_out[2]) / (8192.0f * 3.0f));
ayDevice->bufferEnd &= 0x0fff;
ayDevice->bufferEnd &= BUFFER_MASK;
}
ayDevice->deltaTimeOverFlow -= ayDevice->timePerSample;
}


static void tickAy38910Device(HBC56Device* device, uint32_t deltaTicks, double deltaTime)
static void tickAy38910Device(HBC56Device* device, uint32_t deltaTicks, float deltaTime)
{
AY38910Device* ayDevice = getAy38910Device(device);
if (ayDevice)
{
SDL_LockMutex(ayDevice->mutex);

ayDevice->deltaTimeOverFlow += deltaTime;
double currentTime = hbc56CpuRuntimeSeconds();
double extraTime = currentTime - ayDevice->lastCpuRuntimeSeconds;
ayDevice->deltaTimeOverFlow += extraTime;

while (ayDevice->deltaTimeOverFlow > 0.0)
while (ayDevice->deltaTimeOverFlow > 0)
{
addSampleToBuffer(ayDevice);
ayDevice->lastCpuRuntimeSeconds = currentTime;
}

SDL_UnlockMutex(ayDevice->mutex);
}
}
Expand All @@ -169,41 +175,25 @@ static void audioAy38910Device(HBC56Device* device, float* buffer, int numSample

int size = end - ayDevice->bufferStart;

// here, if we have less than half the required samples
// we need to catch up (synchronise) so we'll skip this
// request.
if (size > numSamples)
{
int samples = size >> 1;
int samples = size >> 1;

while (samples++ < numSamples)
{
addSampleToBuffer(ayDevice);
}

for (int i = 0; i < numSamples; ++i)
{
buffer[i * ayDevice->channels] += ayDevice->buffer[ayDevice->bufferStart++];
ayDevice->bufferStart &= 0x0fff;

if (ayDevice->channels > 1)
{
buffer[i * ayDevice->channels + 1] += ayDevice->buffer[ayDevice->bufferStart++];
ayDevice->bufferStart &= 0x0fff;
}
}
while (samples++ < numSamples)
{
addSampleToBuffer(ayDevice);
}
else

for (int i = 0; i < numSamples; ++i)
{
for (int i = 0; i < numSamples; ++i)
buffer[i * ayDevice->channels] += ayDevice->buffer[ayDevice->bufferStart++];
ayDevice->bufferStart &= BUFFER_MASK;

if (ayDevice->channels > 1)
{
buffer[i * ayDevice->channels] += ayDevice->buffer[ayDevice->bufferStart];
if (ayDevice->channels > 1)
{
buffer[i * ayDevice->channels + 1] += ayDevice->buffer[ayDevice->bufferStart + 1];
}
buffer[i * ayDevice->channels + 1] += ayDevice->buffer[ayDevice->bufferStart++];
ayDevice->bufferStart &= BUFFER_MASK;
}
}

SDL_UnlockMutex(ayDevice->mutex);
}
}
Expand Down Expand Up @@ -235,6 +225,8 @@ static uint8_t writeAy38910Device(HBC56Device* device, uint16_t addr, uint8_t va
}
else if (addr == (ayDevice->baseAddr | AY3891X_WRITE))
{
tickAy38910Device(device, 0, 0);

PSG_writeReg(ayDevice->psg, ayDevice->regAddr, val);
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion emulator/src/devices/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void resetDevice(HBC56Device* device)
* --------------------
* tick a device (for devices which require regular attention)
*/
void tickDevice(HBC56Device* device, uint32_t deltaTicks, double deltaTime)
void tickDevice(HBC56Device* device, uint32_t deltaTicks, float deltaTime)
{
if (device && device->tickFn)
{
Expand Down
4 changes: 2 additions & 2 deletions emulator/src/devices/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ typedef enum
/* tick function pointer */
/* uint32_t deltaTicks: change in clock ticks since last call */
/* double deltaTime: change in elapsed time in seconds since last call */
typedef void (*DeviceTickFn)(HBC56Device*,uint32_t, double);
typedef void (*DeviceTickFn)(HBC56Device*,uint32_t, float);

/* reset function pointer */
typedef void (*DeviceResetFn)(HBC56Device*);
Expand Down Expand Up @@ -117,7 +117,7 @@ void resetDevice(HBC56Device* device);
* --------------------
* tick a device (for devices which require regular attention)
*/
void tickDevice(HBC56Device* device, uint32_t deltaTicks, double deltaTime);
void tickDevice(HBC56Device* device, uint32_t deltaTicks, float deltaTime);

/* Function: readDevice
* --------------------
Expand Down
20 changes: 10 additions & 10 deletions emulator/src/devices/tms9918_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@
static void resetTms9918Device(HBC56Device*);
static void destroyTms9918Device(HBC56Device*);
static void renderTms9918Device(HBC56Device* device);
static void tickTms9918Device(HBC56Device*, uint32_t, double);
static void tickTms9918Device(HBC56Device*, uint32_t, float);
static uint8_t readTms9918Device(HBC56Device*, uint16_t, uint8_t*, uint8_t);
static uint8_t writeTms9918Device(HBC56Device*, uint16_t, uint8_t);

/* tms9918 constants */
#define TMS9918_DISPLAY_WIDTH 320
#define TMS9918_DISPLAY_HEIGHT 240
#define TMS9918_FPS 60.0
#define TMS9918_FPS 60.0f
#define TMS9918_TICK_MIN_PIXELS 26

/* tms9918 computed constants */
#define TMS9918_FRAME_TIME (1.0 / TMS9918_FPS)
#define TMS9918_ROW_TIME (TMS9918_FRAME_TIME / (double)TMS9918_DISPLAY_HEIGHT)
#define TMS9918_PIXEL_TIME (TMS9918_ROW_TIME / (double)TMS9918_DISPLAY_WIDTH)
#define TMS9918_FRAME_TIME (1.0f / TMS9918_FPS)
#define TMS9918_ROW_TIME (TMS9918_FRAME_TIME / (float)TMS9918_DISPLAY_HEIGHT)
#define TMS9918_PIXEL_TIME (TMS9918_ROW_TIME / (float)TMS9918_DISPLAY_WIDTH)
#define TMS9918_BORDER_X ((TMS9918_DISPLAY_WIDTH - TMS9918_PIXELS_X) / 2)
#define TMS9918_BORDER_Y ((TMS9918_DISPLAY_HEIGHT - TMS9918_PIXELS_Y) / 2)
#define TMS9918_DISPLAY_PIXELS (TMS9918_DISPLAY_WIDTH * TMS9918_DISPLAY_HEIGHT)
Expand All @@ -50,7 +50,7 @@ struct TMS9918Device
uint16_t regAddr;
VrEmuTms9918 *tms9918;
uint32_t frameBuffer[TMS9918_DISPLAY_PIXELS];
double unusedTime;
float unusedTime;
int currentFramePixels;
uint8_t scanlineBuffer[TMS9918_DISPLAY_WIDTH];
uint8_t irq;
Expand Down Expand Up @@ -165,7 +165,7 @@ static void renderTms9918Device(HBC56Device* device)
* shown in the display if called frequently enough. you can achieve beam racing effects.
*/
int c = 0;
static void tickTms9918Device(HBC56Device* device, uint32_t deltaTicks, double deltaTime)
static void tickTms9918Device(HBC56Device* device, uint32_t deltaTicks, float deltaTime)
{
TMS9918Device* tmsDevice = getTms9918Device(device);
if (tmsDevice)
Expand All @@ -174,9 +174,9 @@ static void tickTms9918Device(HBC56Device* device, uint32_t deltaTicks, double d
deltaTime += tmsDevice->unusedTime;

/* how many pixels are we rendering? */
double thisStepTotalPixelsDbl = 0.0;
tmsDevice->unusedTime = modf(deltaTime / (double)TMS9918_PIXEL_TIME, &thisStepTotalPixelsDbl) * TMS9918_PIXEL_TIME;
int thisStepTotalPixels = (uint32_t)thisStepTotalPixelsDbl;
float thisStepTotalPixelsFlt = 0.0f;
tmsDevice->unusedTime = modff(deltaTime / (float)TMS9918_PIXEL_TIME, &thisStepTotalPixelsFlt) * TMS9918_PIXEL_TIME;
int thisStepTotalPixels = (uint32_t)thisStepTotalPixelsFlt;

/* if we haven't reached the minimum, accumulate time for the next call and return */
if (thisStepTotalPixels < TMS9918_TICK_MIN_PIXELS)
Expand Down
6 changes: 3 additions & 3 deletions emulator/src/devices/uart_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

static void resetUartDevice(HBC56Device*);
static void destroyUartDevice(HBC56Device*);
static void tickUartDevice(HBC56Device*, uint32_t, double);
static void tickUartDevice(HBC56Device*, uint32_t, float);
static uint8_t readUartDevice(HBC56Device*, uint16_t, uint8_t*, uint8_t);
static uint8_t writeUartDevice(HBC56Device*, uint16_t, uint8_t);

Expand All @@ -46,7 +46,7 @@ struct UartDevice
uint8_t statusReg;
uint8_t irq;

double timeSinceIO;
float timeSinceIO;

};
typedef struct UartDevice UartDevice;
Expand Down Expand Up @@ -165,7 +165,7 @@ static void destroyUartDevice(HBC56Device *device)
* --------------------
* tick the uart device
*/
static void tickUartDevice(HBC56Device* device, uint32_t deltaTicks, double deltaTime)
static void tickUartDevice(HBC56Device* device, uint32_t deltaTicks, float deltaTime)
{
UartDevice* uartDevice = getUartDevice(device);
if (uartDevice && uartDevice->handle)
Expand Down
Loading

0 comments on commit b3108c9

Please sign in to comment.