Mostly working audio, better than POSE!

This commit is contained in:
meepingsnesroms
2018-10-18 11:35:09 -07:00
parent 0f37324265
commit 5fc429ff14
4 changed files with 187 additions and 45 deletions

View File

@@ -182,6 +182,9 @@ uint64_t emulatorGetStateSize(){
size += sizeof(uint16_t) * 9;//RX 8 * 16 SPI1 FIFO, 1 index is for FIFO full
size += sizeof(uint16_t) * 9;//TX 8 * 16 SPI1 FIFO, 1 index is for FIFO full
size += sizeof(uint8_t) * 4;//spi1(R/T)x(Read/Write)Position
size += sizeof(int32_t);//pwm1ClocksToNextSample
size += sizeof(uint8_t) * 6;//pwm1Fifo[6]
size += sizeof(uint8_t) * 2;//pwm1(Read/Write)
size += sizeof(uint8_t) * 7;//palmMisc
size += sizeof(uint32_t);//palmSdCard.command
size += sizeof(uint8_t) * 2;//palmSdCard.response / palmSdCard.commandBitsRemaining
@@ -293,6 +296,18 @@ bool emulatorSaveState(buffer_t buffer){
writeStateValueUint8(buffer.data + offset, spi1TxWritePosition);
offset += sizeof(uint8_t);
//PWM1, audio
writeStateValueInt32(buffer.data + offset, pwm1ClocksToNextSample);
offset += sizeof(int32_t);
for(uint8_t fifoPosition = 0; fifoPosition < 6; fifoPosition++){
writeStateValueUint8(buffer.data + offset, pwm1Fifo[fifoPosition]);
offset += sizeof(uint8_t);
}
writeStateValueUint8(buffer.data + offset, pwm1ReadPosition);
offset += sizeof(uint8_t);
writeStateValueUint8(buffer.data + offset, pwm1WritePosition);
offset += sizeof(uint8_t);
//misc
writeStateValueBool(buffer.data + offset, palmMisc.powerButtonLed);
offset += sizeof(uint8_t);
@@ -428,6 +443,18 @@ bool emulatorLoadState(buffer_t buffer){
spi1TxWritePosition = readStateValueUint8(buffer.data + offset);
offset += sizeof(uint8_t);
//PWM1, audio
pwm1ClocksToNextSample = readStateValueInt32(buffer.data + offset);
offset += sizeof(int32_t);
for(uint8_t fifoPosition = 0; fifoPosition < 6; fifoPosition++){
pwm1Fifo[fifoPosition] = readStateValueUint8(buffer.data + offset);
offset += sizeof(uint8_t);
}
pwm1ReadPosition = readStateValueUint8(buffer.data + offset);
offset += sizeof(uint8_t);
pwm1WritePosition = readStateValueUint8(buffer.data + offset);
offset += sizeof(uint8_t);
//misc
palmMisc.powerButtonLed = readStateValueBool(buffer.data + offset);
offset += sizeof(uint8_t);

View File

@@ -28,6 +28,10 @@ uint8_t spi1RxReadPosition;
uint8_t spi1RxWritePosition;
uint8_t spi1TxReadPosition;
uint8_t spi1TxWritePosition;
int32_t pwm1ClocksToNextSample;
uint8_t pwm1Fifo[6];
uint8_t pwm1ReadPosition;
uint8_t pwm1WritePosition;
static void checkInterrupts();
@@ -37,10 +41,36 @@ static double sysclksPerClk32();
static inline uint32_t audioGetFramePercentIncrementFromClk32s(uint32_t count);
static inline uint32_t audioGetFramePercentIncrementFromSysclks(double count);
static inline uint32_t audioGetFramePercentage();
void runPwm1Sample(uint8_t sample);//fixme
#include "hardwareRegistersAccessors.c.h"
#include "hardwareRegistersTiming.c.h"
//this needs to be moved later!!!
void runPwm1Sample(uint8_t sample){
uint16_t pwmc1 = registerArrayRead16(PWMC1);
if(!(pwmc1 & 0x8000)){
//SYSCLK
uint8_t prescaler = (pwmc1 >> 8 & 0x7F) + 1;
uint8_t clockDivider = 2 << (pwmc1 & 0x03);
uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03);
double dutyCycle = dMin((double)sample / (registerArrayRead8(PWMP1) + 2), 1.0);
uint32_t audioNow = audioGetFramePercentage();
uint32_t audioSampleDuration = audioGetFramePercentIncrementFromSysclks(prescaler * clockDivider);
uint32_t audioDutyCycle = audioSampleDuration * dutyCycle;
for(uint8_t times = 0; times < repeat; times++){
blip_add_delta(palmAudioResampler, audioNow, AUDIO_AMPLITUDE);
blip_add_delta(palmAudioResampler, audioNow + audioDutyCycle, -AUDIO_AMPLITUDE);
audioNow += audioSampleDuration;
}
}
else{
//CLK32
}
}
bool pllIsOn(){
return !(registerArrayRead16(PLLCR) & 0x0008);
}
@@ -607,30 +637,8 @@ void setHwRegister8(uint32_t address, uint8_t value){
case PWMS1 + 1:
//write only if PWM1 and FIFOAV are set and a slot is available
if((registerArrayRead16(PWMC1) & 0x0030) == 0x0030){
uint16_t pwmc1 = registerArrayRead16(PWMC1);
if(!(pwmc1 & 0x8000)){
//SYSCLK
uint8_t prescaler = (pwmc1 >> 8 & 0x7F) + 1;
uint8_t clockDivider = 2 << (pwmc1 & 0x03);
uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03);
double dutyCycle = dMin((double)value / (registerArrayRead8(PWMP1) + 2), 1.0);
uint32_t audioNow = audioGetFramePercentage();
uint32_t audioSampleDuration = audioGetFramePercentIncrementFromSysclks(prescaler * clockDivider);
uint32_t audioDutyCycle = audioSampleDuration * dutyCycle;
for(uint8_t times = 0; times < repeat; times++){
blip_add_delta(palmAudioResampler, audioNow, AUDIO_AMPLITUDE);
blip_add_delta(palmAudioResampler, audioNow + audioDutyCycle, -AUDIO_AMPLITUDE);
audioNow += audioSampleDuration;
}
}
else{
//CLK32
}
}
if((registerArrayRead16(PWMC1) & 0x0030) == 0x0030)
pwm1FifoWrite(value);
break;
case PWMP1:
@@ -1004,7 +1012,8 @@ void setHwRegister16(uint32_t address, uint16_t value){
case PWMS1:
//write only if PWM1 and FIFOAV are set and a slot is available
if((registerArrayRead16(PWMC1) & 0x0030) == 0x0030){
//empty
pwm1FifoWrite(value >> 8);
pwm1FifoWrite(value & 0xFF);
}
break;

View File

@@ -18,7 +18,21 @@ static inline void registerArrayWrite8(uint32_t address, uint8_t value){BUFFER_W
static inline void registerArrayWrite16(uint32_t address, uint16_t value){BUFFER_WRITE_16(palmReg, address, 0xFFF, value);}
static inline void registerArrayWrite32(uint32_t address, uint32_t value){BUFFER_WRITE_32(palmReg, address, 0xFFF, value);}
//SPI1 FIFO accessors, this doesnt quite belong here but it is a memory accessor so its ok for now
//interrupt setters
static inline void setIprIsrBit(uint32_t interruptBit){
//allows for setting an interrupt with masking by IMR and logging in IPR
uint32_t newIpr = registerArrayRead32(IPR) | interruptBit;
registerArrayWrite32(IPR, newIpr);
registerArrayWrite32(ISR, newIpr & ~registerArrayRead32(IMR));
}
static inline void clearIprIsrBit(uint32_t interruptBit){
uint32_t newIpr = registerArrayRead32(IPR) & ~interruptBit;
registerArrayWrite32(IPR, newIpr);
registerArrayWrite32(ISR, newIpr & ~registerArrayRead32(IMR));
}
//SPI1 FIFO accessors
static inline uint16_t spi1RxFifoRead(){
uint16_t value = spi1RxFifo[spi1RxReadPosition];
spi1RxReadPosition = (spi1RxReadPosition + 1) % 9;
@@ -55,20 +69,64 @@ static inline uint8_t spi1TxFifoEntrys(){
return spi1TxWritePosition - spi1TxReadPosition;
}
//PWM1 FIFO accessors
static inline uint8_t pwm1FifoEntrys(){
//check for wraparound
if(pwm1WritePosition < pwm1ReadPosition)
return pwm1WritePosition + 6 - pwm1ReadPosition;
return pwm1WritePosition - pwm1ReadPosition;
}
static inline uint8_t pwm1FifoCurrentValue(){
return pwm1Fifo[pwm1ReadPosition];
}
static inline void pwm1FifoRemove(){
if(pwm1FifoEntrys() > 0){
pwm1ReadPosition = (pwm1ReadPosition + 1) % 6;
//set FIFOAV
registerArrayWrite16(PWMC1, registerArrayRead16(PWMC1) | 0x0020);
}
if(pwm1FifoEntrys() < 2){
uint16_t pwmc1 = registerArrayRead16(PWMC1);
//trigger interrupt if enabled
if(pwmc1 & 0x0040)
setIprIsrBit(INT_PWM1);
registerArrayWrite16(PWMC1, pwmc1 | 0x0080);//set IRQ bit
}
}
static inline void pwm1FifoWrite(uint8_t value){
if(pwm1FifoEntrys() < 5){
pwm1Fifo[pwm1WritePosition] = value;
pwm1WritePosition = (pwm1WritePosition + 1) % 6;
//clear FIFOAV if full
if(pwm1FifoEntrys() == 5)
registerArrayWrite16(PWMC1, registerArrayRead16(PWMC1) & 0xFFDF);
}
}
static inline void pwm1FifoFlush(){
pwm1ReadPosition = 0;
pwm1WritePosition = 0;
//set FIFOAV
registerArrayWrite16(PWMC1, registerArrayRead16(PWMC1) | 0x0020);
}
static inline uint16_t pwm1FifoSampleDuration(){
uint16_t pwmc1 = registerArrayRead16(PWMC1);
uint8_t prescaler = (pwmc1 >> 8 & 0x7F) + 1;
uint8_t clockDivider = 2 << (pwmc1 & 0x03);
uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03);
return prescaler * clockDivider * repeat;
}
//register setters
static inline void setIprIsrBit(uint32_t interruptBit){
//allows for setting an interrupt with masking by IMR and logging in IPR
uint32_t newIpr = registerArrayRead32(IPR) | interruptBit;
registerArrayWrite32(IPR, newIpr);
registerArrayWrite32(ISR, newIpr & ~registerArrayRead32(IMR));
}
static inline void clearIprIsrBit(uint32_t interruptBit){
uint32_t newIpr = registerArrayRead32(IPR) & ~interruptBit;
registerArrayWrite32(IPR, newIpr);
registerArrayWrite32(ISR, newIpr & ~registerArrayRead32(IMR));
}
static inline void setCsa(uint16_t value){
chips[CHIP_A0_ROM].enable = value & 0x0001;
chips[CHIP_A0_ROM].readOnly = value & 0x8000;
@@ -376,11 +434,14 @@ static inline void setPwmc1(uint16_t value){
uint16_t oldPwmc1 = registerArrayRead16(PWMC1);
//always have FIFOAV set right now, hack
value |= 0x0020;
if(pwm1FifoEntrys() < 5)
value |= 0x0020;
//PWM1 enabled, set IRQ and FIFOAV bit to fill FIFO
if(!(oldPwmc1 & 0x0010) && value & 0x0010)
value |= 0x00A0;
//PWM1 enabled, set IRQ
if(!(oldPwmc1 & 0x0010) && value & 0x0010){
value |= 0x0080;//enable IRQ
pwm1ClocksToNextSample = 0;//when first sample is written output it immediatly
}
//clear interrupt by write(reading can also clear the interrupt)
if(oldPwmc1 & 0x0080 && !(value & 0x0080)){
@@ -396,8 +457,11 @@ static inline void setPwmc1(uint16_t value){
}
//PWM1 disabled
if(oldPwmc1 & 0x0010 && !(value & 0x0010))
if(oldPwmc1 & 0x0010 && !(value & 0x0010)){
pwm1FifoFlush();
value |= 0x0020;//set FIFOAV since FIFO is now empty, should be set by pwm1FifoFlush()
value &= 0x80FF;//clear PWM prescaler value
}
registerArrayWrite16(PWMC1, value);
}
@@ -554,6 +618,46 @@ static inline uint8_t getPortMValue(){
return ((registerArrayRead8(PMDATA) & registerArrayRead8(PMDIR)) | (~registerArrayRead8(PMDIR) & 0x20)) & registerArrayRead8(PMSEL);
}
static inline void samplePwm1(bool forClk32, double sysclks){
//clear PWM1 FIFO values if enough time has passed
uint16_t pwmc1 = registerArrayRead16(PWMC1);
int32_t decrement = forClk32 ? 1 : sysclks;
//check if enabled and validate clock mode
if(!(pwmc1 & 0x0010) || forClk32 != (bool)(pwmc1 & 0x8000))
return;
//add cycles
if(pwm1FifoEntrys() > 0){
pwm1ClocksToNextSample -= decrement;
if(pwm1ClocksToNextSample <= 0){
while(pwm1FifoEntrys() > 0 && pwm1ClocksToNextSample <= 0){
//switch out samples
runPwm1Sample(pwm1FifoCurrentValue());
pwm1FifoRemove();
pwm1ClocksToNextSample += pwm1FifoSampleDuration();
}
//dont carry negative cycles over when the FIFO runs out
if(pwm1FifoEntrys() == 0 && pwm1ClocksToNextSample < 0)
pwm1ClocksToNextSample = 0;
/*
//interrupt to fill FIFO
if(pwm1FifoEntrys() < 2 && (pwmc1 & 0x00C0) == 0x0040){
registerArrayWrite16(PWMC1, pwmc1 | 0x0080);//set IRQ bit
setIprIsrBit(INT_PWM1);
checkInterrupts();
}
*/
}
}
else{
//still allow the sample timer to run out but cap a 0
pwm1ClocksToNextSample = sMax(pwm1ClocksToNextSample - decrement, 0);
}
}
static inline uint16_t getPwmc1(){
uint16_t returnValue = registerArrayRead16(PWMC1);

View File

@@ -327,6 +327,7 @@ void endClk32(){
timer1(TIMER_REASON_CLK32, 0);
timer2(TIMER_REASON_CLK32, 0);
samplePwm1(true/*forClk32*/, 0.0);
//PLLCR wake select wait
if(pllWakeWait != -1){
@@ -343,9 +344,10 @@ void endClk32(){
}
void addSysclks(double count){
palmClk32Sysclks += count;
timer1(TIMER_REASON_SYSCLK, count);
timer2(TIMER_REASON_SYSCLK, count);
samplePwm1(false/*forClk32*/, count);
palmClk32Sysclks += count;
}
static inline uint32_t audioGetFramePercentIncrementFromClk32s(uint32_t count){