mirror of
https://github.com/libretro/Mu.git
synced 2026-09-23 15:15:43 +00:00
Emulate inductor, its still not tuned properly
This commit is contained in:
@@ -25,6 +25,7 @@ ICR POL(1,2,3,6) may flip the pin value as well as the interrupt, POL5 does not
|
||||
edge triggered INT* don't clear on write to ISR when masked in IMR(at least that seems to be the reason)
|
||||
if a sound interrupt is triggered while the button interrupt is disabled the button interrupt will still trigger(in galax game)
|
||||
PWM1 output value is not a direct range cast of 0<->255 to 0<->32767, its additive, see properPwmSineWave.png
|
||||
inductor dosent properly drain when PWM1 gets disabled
|
||||
|
||||
Debug tools:
|
||||
ADS7846 channels can't be read in single reference mode in hwTestSuite
|
||||
|
||||
@@ -84,7 +84,8 @@ SOURCES += \
|
||||
src/pdiUsbD12.c \
|
||||
src/sdCard.c \
|
||||
src/sed1376.c \
|
||||
src/silkscreen.c
|
||||
src/silkscreen.c \
|
||||
src/audio/inductor.c
|
||||
|
||||
HEADERS += \
|
||||
src/audio/blip_buf.h \
|
||||
@@ -117,7 +118,8 @@ HEADERS += \
|
||||
emuwrapper.h \
|
||||
mainwindow.h \
|
||||
statemanager.h \
|
||||
touchscreen.h
|
||||
touchscreen.h \
|
||||
src/audio/inductor.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui \
|
||||
|
||||
29
src/audio/inductor.c
Normal file
29
src/audio/inductor.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../portability.h"
|
||||
#include "../emulator.h"
|
||||
#include "blip_buf.h"
|
||||
|
||||
|
||||
#define INDUCTOR_RANGE 10000
|
||||
#define INDUCTOR_CLOCK_POWER 0.80
|
||||
|
||||
|
||||
int32_t inductorCurrentCharge;
|
||||
int32_t inductorLastAudioSample;
|
||||
|
||||
|
||||
void inductorReset(){
|
||||
inductorCurrentCharge = 0;
|
||||
inductorLastAudioSample = 0;
|
||||
}
|
||||
|
||||
void inductorAddClocks(int32_t clocks, bool charge){
|
||||
inductorCurrentCharge = sClamp(-INDUCTOR_RANGE, inductorCurrentCharge + (charge ? +clocks : -clocks) * INDUCTOR_CLOCK_POWER, INDUCTOR_RANGE);
|
||||
}
|
||||
|
||||
void inductorSampleAudio(int32_t now){
|
||||
blip_add_delta(palmAudioResampler, now, inductorCurrentCharge - inductorLastAudioSample);
|
||||
inductorLastAudioSample = inductorCurrentCharge;
|
||||
}
|
||||
12
src/audio/inductor.h
Normal file
12
src/audio/inductor.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int32_t inductorCurrentCharge;
|
||||
extern int32_t inductorLastAudioSample;
|
||||
|
||||
void inductorReset();
|
||||
|
||||
void inductorAddClocks(int32_t clocks, bool charge);
|
||||
void inductorSampleAudio(int32_t now);
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "m68k/m68k.h"
|
||||
#include "audio/blip_buf.h"
|
||||
#include "audio/inductor.h"
|
||||
#include "m68328.h"
|
||||
#include "emulator.h"
|
||||
#include "hardwareRegisters.h"
|
||||
@@ -107,6 +108,7 @@ uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t spec
|
||||
sed1376Reset();
|
||||
ads7846Reset();
|
||||
pdiUsbD12Reset();
|
||||
inductorReset();
|
||||
sandboxInit();
|
||||
|
||||
memset(&palmInput, 0x00, sizeof(palmInput));
|
||||
@@ -144,11 +146,11 @@ void emulatorExit(){
|
||||
void emulatorReset(){
|
||||
//reset doesnt clear RAM or SD card, all programs are stored in RAM or on SD card
|
||||
debugLog("Reset triggered, PC:0x%08X\n", m68k_get_reg(NULL, M68K_REG_PPC));
|
||||
blip_add_delta(palmAudioResampler, 0, -pwm1LastSampleDelta);
|
||||
m68328Reset();
|
||||
sed1376Reset();
|
||||
ads7846Reset();
|
||||
pdiUsbD12Reset();
|
||||
inductorReset();
|
||||
}
|
||||
|
||||
void emulatorSetRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds){
|
||||
@@ -186,7 +188,7 @@ uint64_t emulatorGetStateSize(){
|
||||
size += sizeof(int32_t);//pwm1ClocksToNextSample
|
||||
size += sizeof(uint8_t) * 6;//pwm1Fifo[6]
|
||||
size += sizeof(uint8_t) * 2;//pwm1(Read/Write)
|
||||
size += sizeof(int32_t);//pwm1LastSampleDelta
|
||||
size += sizeof(int32_t) * 2;//inductorCurrentCharge / inductorLastAudioSample
|
||||
size += sizeof(uint8_t) * 7;//palmMisc
|
||||
size += sizeof(uint32_t);//palmSdCard.command
|
||||
size += sizeof(uint8_t) * 2;//palmSdCard.response / palmSdCard.commandBitsRemaining
|
||||
@@ -311,7 +313,9 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
offset += sizeof(uint8_t);
|
||||
writeStateValueUint8(buffer.data + offset, pwm1WritePosition);
|
||||
offset += sizeof(uint8_t);
|
||||
writeStateValueInt32(buffer.data + offset, pwm1LastSampleDelta);
|
||||
writeStateValueInt32(buffer.data + offset, inductorCurrentCharge);
|
||||
offset += sizeof(int32_t);
|
||||
writeStateValueInt32(buffer.data + offset, inductorLastAudioSample);
|
||||
offset += sizeof(int32_t);
|
||||
|
||||
//misc
|
||||
@@ -462,10 +466,10 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
offset += sizeof(uint8_t);
|
||||
pwm1WritePosition = readStateValueUint8(buffer.data + offset);
|
||||
offset += sizeof(uint8_t);
|
||||
blip_add_delta(palmAudioResampler, 0, -pwm1LastSampleDelta);
|
||||
pwm1LastSampleDelta = readStateValueInt32(buffer.data + offset);
|
||||
inductorCurrentCharge = readStateValueInt32(buffer.data + offset);
|
||||
offset += sizeof(int32_t);
|
||||
inductorLastAudioSample = readStateValueInt32(buffer.data + offset);
|
||||
offset += sizeof(int32_t);
|
||||
blip_add_delta(palmAudioResampler, 0, pwm1LastSampleDelta);
|
||||
|
||||
//misc
|
||||
palmMisc.powerButtonLed = readStateValueBool(buffer.data + offset);
|
||||
|
||||
@@ -120,7 +120,7 @@ typedef struct{
|
||||
|
||||
//system constants
|
||||
#define CRYSTAL_FREQUENCY 32768
|
||||
#define AUDIO_AMPLITUDE 1000000
|
||||
#define AUDIO_VOLUME 10//1000000
|
||||
#define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLE_RATE / EMU_FPS)
|
||||
#define AUDIO_END_OF_FRAME (235929600 / EMU_FPS)//smallest amount of time a second can be split into:(2.0 * (14.0 * (255 + 1.0) + 15 + 1.0)) * 32768 == 235929600, used to convert the variable timing of SYSCLK and CLK32 to a fixed location in the current frame 0<->AUDIO_END_OF_FRAME
|
||||
#define AUDIO_WAIT_FOR_SAMPLE INT32_MIN
|
||||
|
||||
@@ -34,7 +34,6 @@ int32_t pwm1ClocksToNextSample;
|
||||
uint8_t pwm1Fifo[6];
|
||||
uint8_t pwm1ReadPosition;
|
||||
uint8_t pwm1WritePosition;
|
||||
int32_t pwm1LastSampleDelta;
|
||||
|
||||
|
||||
static void checkInterrupts();
|
||||
@@ -1083,7 +1082,6 @@ void resetHwRegisters(){
|
||||
memset(pwm1Fifo, 0x00, sizeof(pwm1Fifo));
|
||||
pwm1ReadPosition = 0;
|
||||
pwm1WritePosition = 0;
|
||||
pwm1LastSampleDelta = 0;
|
||||
|
||||
memset(chips, 0x00, sizeof(chips));
|
||||
//all chip selects are disabled at boot and CSA0 is mapped to 0x00000000 and covers the entire address range until CSA is set enabled
|
||||
|
||||
@@ -80,7 +80,6 @@ extern int32_t pwm1ClocksToNextSample;
|
||||
extern uint8_t pwm1Fifo[];
|
||||
extern uint8_t pwm1ReadPosition;
|
||||
extern uint8_t pwm1WritePosition;
|
||||
extern int32_t pwm1LastSampleDelta;
|
||||
|
||||
//timing
|
||||
void beginClk32();
|
||||
|
||||
@@ -85,12 +85,18 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){
|
||||
uint8_t prescaler = (pwmc1 >> 8 & 0x7F) + 1;
|
||||
uint8_t clockDivider = 2 << (pwmc1 & 0x03);
|
||||
uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03);
|
||||
int32_t audioStart = now + clockOffset;
|
||||
int32_t audioSampleDuration = usingClk32 ? audioGetFramePercentIncrementFromClk32s(period * prescaler * clockDivider * repeat) : audioGetFramePercentIncrementFromSysclks(period * prescaler * clockDivider * repeat);
|
||||
int32_t audioDeew = dMin((double)sample / period, 1.0)/*dutyCycle*/ * AUDIO_AMPLITUDE;
|
||||
int32_t audioNow = now + clockOffset;
|
||||
int32_t audioSampleDuration = usingClk32 ? audioGetFramePercentIncrementFromClk32s(period * prescaler * clockDivider) : audioGetFramePercentIncrementFromSysclks(period * prescaler * clockDivider);
|
||||
int32_t audioDutyCycle = dMin((double)sample / period, 1.0)/*dutyCycle*/ * audioSampleDuration;
|
||||
|
||||
blip_add_delta(palmAudioResampler, audioStart, audioDeew - pwm1LastSampleDelta);
|
||||
pwm1LastSampleDelta = audioDeew;
|
||||
//relay all the samples to the inductor
|
||||
for(uint8_t index = 0; index < repeat; index++){
|
||||
inductorAddClocks(audioDutyCycle, true);
|
||||
inductorSampleAudio(audioNow + audioDutyCycle);
|
||||
inductorAddClocks(audioSampleDuration - audioDutyCycle, false);
|
||||
inductorSampleAudio(audioNow + audioSampleDuration);
|
||||
audioNow += audioSampleDuration;
|
||||
}
|
||||
|
||||
//remove used entry
|
||||
if(pwm1FifoEntrys() > 0)
|
||||
@@ -106,12 +112,7 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){
|
||||
registerArrayWrite16(PWMC1, pwmc1 | 0x0080);//set IRQ bit
|
||||
}
|
||||
|
||||
return audioSampleDuration;
|
||||
}
|
||||
|
||||
static inline void pwm1FifoFinished(int32_t now){
|
||||
blip_add_delta(palmAudioResampler, now, -pwm1LastSampleDelta);
|
||||
pwm1LastSampleDelta = 0;
|
||||
return audioSampleDuration * repeat;
|
||||
}
|
||||
|
||||
static inline void pwm1FifoWrite(uint8_t value){
|
||||
@@ -619,18 +620,23 @@ static inline uint8_t getPortMValue(){
|
||||
static inline void samplePwm1(bool forClk32, double sysclks){
|
||||
//clear PWM1 FIFO values if enough time has passed
|
||||
uint16_t pwmc1 = registerArrayRead16(PWMC1);
|
||||
int32_t audioClocks;
|
||||
|
||||
//check if enabled and validate clock mode
|
||||
if(!(pwmc1 & 0x0010) || forClk32 != (bool)(pwmc1 & 0x8000))
|
||||
return;
|
||||
|
||||
//this calculation is fairly heavy, only do it after we know the clock mode is valid
|
||||
audioClocks = forClk32 ? audioGetFramePercentIncrementFromClk32s(1) : audioGetFramePercentIncrementFromSysclks(sysclks);
|
||||
|
||||
//add cycles
|
||||
if(pwm1ClocksToNextSample != AUDIO_WAIT_FOR_SAMPLE)
|
||||
pwm1ClocksToNextSample -= forClk32 ? audioGetFramePercentIncrementFromClk32s(1) : audioGetFramePercentIncrementFromSysclks(sysclks);
|
||||
pwm1ClocksToNextSample -= audioClocks;
|
||||
|
||||
//use samples
|
||||
if(pwm1ClocksToNextSample <= 0){
|
||||
int32_t audioNow = audioGetFramePercentage();
|
||||
int32_t audioClocksLeft = audioClocks;
|
||||
|
||||
while(pwm1FifoEntrys() > 0 && pwm1ClocksToNextSample <= 0){
|
||||
int32_t audioUsed;
|
||||
@@ -648,12 +654,17 @@ static inline void samplePwm1(bool forClk32, double sysclks){
|
||||
}
|
||||
|
||||
audioNow += audioUsed;
|
||||
audioClocksLeft -= audioUsed;//goes negative when extra clocks are used
|
||||
}
|
||||
|
||||
//all samples used and its still negative, wait for next sample
|
||||
if(pwm1ClocksToNextSample != AUDIO_WAIT_FOR_SAMPLE && pwm1ClocksToNextSample <= 0){
|
||||
pwm1FifoFinished(audioNow);
|
||||
if(pwm1ClocksToNextSample <= 0)
|
||||
pwm1ClocksToNextSample = AUDIO_WAIT_FOR_SAMPLE;
|
||||
|
||||
//add 0 cycles to inductor when theres no samples
|
||||
if(audioClocksLeft > 0){
|
||||
inductorAddClocks(audioClocksLeft, false);
|
||||
inductorSampleAudio(audioNow + audioClocksLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,5 @@ EMU_SOURCES_C := $(EMU_PATH)/emulator.c \
|
||||
$(EMU_PATH)/m68k/m68kdasm.c \
|
||||
$(EMU_PATH)/m68k/m68kcpu.c \
|
||||
$(EMU_PATH)/audio/blip_buf.c \
|
||||
$(EMU_PATH)/audio/inductor.c \
|
||||
$(EMU_PATH)/debug/sandbox.c
|
||||
|
||||
Reference in New Issue
Block a user