I have ported my old project “pNesX” game console emulator to the nucleo.
Dependencies: SDFileSystem mbed
pNesX_Apu.cpp
00001 /*===================================================================*/ 00002 /* */ 00003 /* pNesX_Apu.cpp : NES APU emulation (for Nucleo) */ 00004 /* */ 00005 /* 2016/1/20 Racoon */ 00006 /* */ 00007 /*===================================================================*/ 00008 00009 #include "mbed.h" 00010 #include "SDFileSystem.h" 00011 00012 #include "pNesX.h" 00013 #include "pNesX_System.h" 00014 00015 //==================== 00016 // DAC 00017 //==================== 00018 AnalogOut DAC_Out(PA_4); 00019 WORD TrDac, P1Dac, P2Dac, NsDac, MixDac; 00020 #define DACFreq 24000 00021 // Pulse clock(8 steps) = 1789773 / 2 / DACFreq * 1000 00022 #define PuClock 37287 00023 // Triangle clock(32 steps) = 1789773 / DACFreq * 1000 00024 #define TrClock 74574 00025 00026 //==================== 00027 // DAC Timer 00028 //==================== 00029 #define TIMx TIM4 00030 #define TIMx_CLK_ENABLE __HAL_RCC_TIM4_CLK_ENABLE 00031 #define TIMx_IRQn TIM4_IRQn 00032 #define TIMx_IRQHandler TIM4_IRQHandler 00033 TIM_HandleTypeDef TimHandle; 00034 00035 //==================== 00036 // Audio channel variables 00037 //==================== 00038 00039 const BYTE LengthTable[] = {10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 00040 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30}; 00041 00042 // Minimum Volume 00043 #define MV 4096 00044 const WORD Pulse_Table[4][8] = { 0,MV, 0, 0, 0, 0, 0, 0, 00045 0,MV,MV, 0, 0, 0, 0, 0, 00046 0,MV,MV,MV,MV, 0, 0, 0, 00047 MV, 0, 0,MV,MV,MV,MV,MV}; 00048 // Pulse1 00049 bool P1Enable; 00050 int P1Timer; 00051 int P1WaveLength; 00052 int P1WavePeriod; 00053 int P1Lapse; 00054 int P1Duty; 00055 int P1Vol; 00056 int P1LengthCounter; 00057 int P1EnvSeq; 00058 int P1EnvCnt; 00059 int P1Sweep; 00060 int P1SwCnt; 00061 int P1SwLevel; 00062 bool P1SwReloadFlag; 00063 bool P1SwOverflow; 00064 00065 // Pulse2 00066 bool P2Enable; 00067 int P2Timer; 00068 int P2WaveLength; 00069 int P2WavePeriod; 00070 int P2Lapse; 00071 int P2Duty; 00072 int P2Vol; 00073 int P2LengthCounter; 00074 int P2EnvSeq; 00075 int P2EnvCnt; 00076 int P2Sweep; 00077 int P2SwCnt; 00078 int P2SwLevel; 00079 bool P2SwReloadFlag; 00080 bool P2SwOverflow; 00081 00082 // Triangle 00083 bool TrEnable; 00084 int TrTimer; 00085 const WORD Triangle_Table[] = {61440,57344,53248,49152,45056,40960,36864,32768,28672,24576,20480,16384,12288,8192,4096,0, 00086 0,4096,8192,12288,16384,20480,24576,28672,32768,36864,40960,45056,49152,53248,57344,61440}; 00087 bool LinearCounterReloadFlag; 00088 int LinearCounter; 00089 int TrLengthCounter; 00090 int TrWaveLength; 00091 int TrWavePeriod; 00092 int TrLapse; 00093 00094 // Noise 00095 bool NsEnable; 00096 const WORD Noise_Freq[] = {0,0,0,0,0,0,12000,11186,8860,7046,4710,3523,2349,1762,880,440}; 00097 int NsFreq; 00098 int NsSum; 00099 int NsVol; 00100 int NsLengthCounter; 00101 int NsEnvSeq; 00102 int NsEnvCnt; 00103 00104 // DMC 00105 int DmOutLevel; 00106 00107 /*-------------------------------------------------------------------*/ 00108 /* DAC Timer callback */ 00109 /*-------------------------------------------------------------------*/ 00110 extern "C" { 00111 void TIMx_IRQHandler(void) 00112 { 00113 HAL_TIM_IRQHandler(&TimHandle); 00114 } 00115 00116 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) 00117 { 00118 TIMx_CLK_ENABLE(); 00119 00120 HAL_NVIC_SetPriority(TIMx_IRQn, 4, 0); 00121 HAL_NVIC_EnableIRQ(TIMx_IRQn); 00122 } 00123 00124 static void Error_Handler(void) 00125 { 00126 while(1); 00127 } 00128 } // extern "C" 00129 00130 /*-------------------------------------------------------------------*/ 00131 /* Randomize value (Noise channel) */ 00132 /*-------------------------------------------------------------------*/ 00133 WORD ShiftReg = 1; 00134 00135 WORD Rand96() 00136 { 00137 ShiftReg |= ((ShiftReg ^ (ShiftReg >> 6)) & 1) << 15; 00138 ShiftReg >>= 1; 00139 return (ShiftReg & 1) ? MV : 0; 00140 } 00141 00142 WORD Rand32k() 00143 { 00144 ShiftReg |= ((ShiftReg ^ (ShiftReg >> 1)) & 1) << 15; 00145 ShiftReg >>= 1; 00146 return (ShiftReg & 1) ? MV : 0; 00147 } 00148 00149 /*-------------------------------------------------------------------*/ 00150 /* DAC Timer Interrup */ 00151 /*-------------------------------------------------------------------*/ 00152 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 00153 { 00154 // Pulse1 00155 if (P1Enable && P1LengthCounter > 0 && !P1SwOverflow && P1Timer > 8) 00156 { 00157 P1Lapse += PuClock; 00158 P1Lapse %= P1WavePeriod; 00159 P1Dac = Pulse_Table[P1Duty][P1Lapse / P1WaveLength] * P1Vol; 00160 } 00161 00162 // Pulse2 00163 if (P2Enable && P2LengthCounter > 0 && !P2SwOverflow && P2Timer > 8) 00164 { 00165 P2Lapse += PuClock; 00166 P2Lapse %= P2WavePeriod; 00167 P2Dac = Pulse_Table[P2Duty][P2Lapse / P2WaveLength] * P2Vol; 00168 } 00169 00170 // Triangle 00171 if (TrEnable && LinearCounter > 0 && TrLengthCounter > 0) 00172 { 00173 TrLapse += TrClock; 00174 TrLapse %= TrWavePeriod; 00175 TrDac = Triangle_Table[TrLapse / TrWaveLength]; 00176 TrDac -= (TrDac * DmOutLevel / 295); 00177 } 00178 00179 // Noise 00180 if (NsEnable && NsLengthCounter > 0) 00181 { 00182 NsSum += NsFreq; 00183 if (NsSum >= DACFreq) 00184 { 00185 NsSum %= DACFreq; 00186 00187 NsDac = ((APU_Reg[0xe] & 0x80) ? Rand96() : Rand32k()) * NsVol; 00188 NsDac -= (NsDac * DmOutLevel / 295); 00189 } 00190 } 00191 00192 // Mixing 00193 MixDac = (P1Dac + P2Dac + TrDac + NsDac) / 4; 00194 00195 // Output to DAC 00196 DAC_Out.write_u16(MixDac); 00197 } 00198 00199 /*-------------------------------------------------------------------*/ 00200 /* Apu Initialize Function */ 00201 /*-------------------------------------------------------------------*/ 00202 void ApuInit() 00203 { 00204 // Setup DAC Timer 00205 TimHandle.Instance = TIMx; 00206 TimHandle.Init.Prescaler = (uint32_t) ((SystemCoreClock / 2) / 240000) - 1; // 240000Hz 00207 TimHandle.Init.Period = 10 - 1; // 240000/10=24000Hz 00208 TimHandle.Init.ClockDivision = 0; 00209 TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; 00210 00211 if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK) 00212 Error_Handler(); 00213 00214 if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK) 00215 Error_Handler(); 00216 } 00217 00218 /*-------------------------------------------------------------------*/ 00219 /* Apu Mute */ 00220 /*-------------------------------------------------------------------*/ 00221 void ApuMute(bool mute) 00222 { 00223 if (mute) 00224 { 00225 if(HAL_TIM_Base_Stop_IT(&TimHandle) != HAL_OK) 00226 Error_Handler(); 00227 } 00228 else 00229 { 00230 if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK) 00231 Error_Handler(); 00232 } 00233 } 00234 00235 /*-------------------------------------------------------------------*/ 00236 /* Apu Write Function */ 00237 /*-------------------------------------------------------------------*/ 00238 void ApuWrite( WORD wAddr, BYTE byData ) 00239 { 00240 APU_Reg[ wAddr ] = byData; 00241 00242 switch( wAddr ) 00243 { 00244 //==================== 00245 // Pulse1 00246 //==================== 00247 case 0: 00248 P1Duty = (byData & 0xc0) >> 6; 00249 00250 if (byData & 0x10) 00251 { 00252 // constant volume 00253 P1Vol = byData & 0xf; 00254 } 00255 else 00256 { 00257 // envelope on 00258 P1Vol = 15; 00259 P1EnvCnt = (byData & 0xf) + 1; 00260 } 00261 break; 00262 00263 case 1: 00264 P1SwReloadFlag = true; 00265 P1SwLevel = (byData & 7); 00266 break; 00267 00268 case 2: 00269 case 3: 00270 P1Timer = APU_Reg[3] & 7; 00271 P1Timer = (P1Timer << 8) | APU_Reg[2]; 00272 P1WaveLength = (P1Timer+1) * 1000; 00273 P1WavePeriod = P1WaveLength * 8; 00274 00275 if (wAddr == 3) 00276 { 00277 P1LengthCounter = LengthTable[(byData & 0xf8) >> 3]; 00278 00279 // Reset sequencer 00280 P1Lapse = 0; 00281 P1EnvSeq = P1EnvCnt; 00282 P1Sweep = 0; 00283 P1SwCnt = 0; 00284 P1SwOverflow = false; 00285 } 00286 break; 00287 00288 //==================== 00289 // Pulse2 00290 //==================== 00291 case 4: 00292 P2Duty = (byData & 0xc0) >> 6; 00293 00294 if (byData & 0x10) 00295 { 00296 // constant volume 00297 P2Vol = byData & 0xf; 00298 } 00299 else 00300 { 00301 // envelope on 00302 P2Vol = 15; 00303 P2EnvCnt = (byData & 0xf) + 1; 00304 } 00305 break; 00306 00307 case 5: 00308 P2SwReloadFlag = true; 00309 P2SwLevel = (byData & 7); 00310 break; 00311 00312 case 6: 00313 case 7: 00314 P2Timer = APU_Reg[7] & 7; 00315 P2Timer = (P2Timer << 8) | APU_Reg[6]; 00316 P2WaveLength = (P2Timer+1) * 1000; 00317 P2WavePeriod = P2WaveLength * 8; 00318 if (wAddr == 7) 00319 { 00320 P2LengthCounter = LengthTable[(byData & 0xf8) >> 3]; 00321 00322 // Reset sequencer 00323 P2Lapse = 0; 00324 P2EnvSeq = P2EnvCnt; 00325 P2Sweep = 0; 00326 P2SwCnt = 0; 00327 P2SwOverflow = false; 00328 } 00329 break; 00330 00331 //==================== 00332 // Triangle 00333 //==================== 00334 case 0x8: 00335 LinearCounterReloadFlag = true; 00336 break; 00337 00338 case 0xA: 00339 case 0xB: 00340 TrTimer = APU_Reg[0xB] & 7; 00341 TrTimer = (TrTimer << 8) | APU_Reg[0xA]; 00342 TrWaveLength = TrTimer * 1000; 00343 TrWavePeriod = TrWaveLength * 32; 00344 00345 if (wAddr == 0xB) 00346 { 00347 TrLengthCounter = LengthTable[(byData & 0xf8) >> 3]; 00348 LinearCounterReloadFlag = true; 00349 } 00350 break; 00351 00352 //==================== 00353 // Noise 00354 //==================== 00355 case 0xC: 00356 if (byData & 0x10) 00357 { 00358 // constant volume 00359 NsVol = byData & 0xf; 00360 } 00361 else 00362 { 00363 // envelope on 00364 NsVol = 15; 00365 NsEnvCnt = (byData & 0xf) + 1; 00366 } 00367 break; 00368 00369 case 0xF: 00370 NsLengthCounter = LengthTable[(byData & 0xf8) >> 3]; 00371 00372 // Reset sequencer 00373 NsEnvSeq = NsEnvCnt; 00374 break; 00375 00376 case 0xE: 00377 NsFreq = Noise_Freq[byData & 0xf]; 00378 break; 00379 00380 //==================== 00381 // DMC(PCM) 00382 //==================== 00383 case 0x11: 00384 DmOutLevel = byData & 0x7f; 00385 break; 00386 00387 //==================== 00388 // Control 00389 //==================== 00390 case 0x15: 00391 if (byData & 1) 00392 { 00393 P1Enable = true; 00394 } 00395 else 00396 { 00397 P1Enable = false; 00398 P1LengthCounter = 0; 00399 } 00400 00401 if (byData & 2) 00402 { 00403 P2Enable = true; 00404 } 00405 else 00406 { 00407 P2Enable = false; 00408 P2LengthCounter = 0; 00409 } 00410 00411 if (byData & 4) 00412 { 00413 TrEnable = true; 00414 } 00415 else 00416 { 00417 TrEnable = false; 00418 TrLengthCounter = 0; 00419 } 00420 00421 if (byData & 8) 00422 { 00423 NsEnable = true; 00424 } 00425 else 00426 { 00427 NsEnable = false; 00428 NsLengthCounter = 0; 00429 } 00430 break; 00431 } // Switch( wAddr ) 00432 } 00433 00434 /*-------------------------------------------------------------------*/ 00435 /* 240Hz Clock */ 00436 /*-------------------------------------------------------------------*/ 00437 void pNesX_ApuClk_240Hz() 00438 { 00439 //==================== 00440 // Pulse1 Envelope 00441 //==================== 00442 if (!(APU_Reg[0] & 0x10) && P1EnvSeq > 0) 00443 { 00444 P1EnvSeq--; 00445 if (P1EnvSeq == 0) 00446 { 00447 if (P1Vol > 0) 00448 { 00449 --P1Vol; 00450 P1EnvSeq = P1EnvCnt; 00451 } 00452 else 00453 { 00454 if (APU_Reg[0] & 0x20) 00455 { 00456 P1Vol = 15; 00457 P1EnvSeq = P1EnvCnt; 00458 } 00459 } 00460 } 00461 } 00462 00463 //==================== 00464 // Pulse2 Envelope 00465 //==================== 00466 if (!(APU_Reg[4] & 0x10) && P2EnvSeq > 0) 00467 { 00468 P2EnvSeq--; 00469 if (P2EnvSeq == 0) 00470 { 00471 if (P2Vol > 0) 00472 { 00473 --P2Vol; 00474 P2EnvSeq = P2EnvCnt; 00475 } 00476 else 00477 { 00478 if (APU_Reg[4] & 0x20) 00479 { 00480 P2Vol = 15; 00481 P2EnvSeq = P2EnvCnt; 00482 } 00483 } 00484 } 00485 } 00486 00487 //==================== 00488 // Triangle Linear Counter 00489 //==================== 00490 if (LinearCounterReloadFlag) 00491 { 00492 LinearCounter = APU_Reg[0x8] & 0x7f; 00493 } 00494 else if (LinearCounter > 0) 00495 { 00496 LinearCounter--; 00497 } 00498 00499 if (!(APU_Reg[0x8] & 0x80)) 00500 { 00501 LinearCounterReloadFlag = false; 00502 } 00503 00504 //==================== 00505 // Noise Envelope 00506 //==================== 00507 if (!(APU_Reg[0xc] & 0x10) && NsEnvSeq > 0) 00508 { 00509 NsEnvSeq--; 00510 if (NsEnvSeq == 0) 00511 { 00512 if (NsVol > 0) 00513 { 00514 --NsVol; 00515 NsEnvSeq = NsEnvCnt; 00516 } 00517 else 00518 { 00519 if (APU_Reg[0xc] & 0x20) 00520 { 00521 NsVol = 15; 00522 NsEnvSeq = NsEnvCnt; 00523 } 00524 } 00525 } 00526 } 00527 } 00528 00529 /*-------------------------------------------------------------------*/ 00530 /* 120Hz Clock */ 00531 /*-------------------------------------------------------------------*/ 00532 void pNesX_ApuClk_120Hz() 00533 { 00534 //==================== 00535 // Pulse1 Sweep 00536 //==================== 00537 if (P1SwReloadFlag) 00538 { 00539 P1Sweep = ((APU_Reg[1] & 0x70) >> 4) + 1; 00540 P1SwCnt = 0; 00541 P1SwReloadFlag = false; 00542 } 00543 else if (APU_Reg[1] & 0x80 && !P1SwOverflow) 00544 { 00545 P1SwCnt++; 00546 if (P1SwCnt == P1Sweep) 00547 { 00548 P1SwCnt = 0; 00549 00550 int sweep = P1Timer >> P1SwLevel; 00551 int value = P1Timer; 00552 if (APU_Reg[1] & 8) 00553 { 00554 value = value - sweep - 1; 00555 if (value < 8) 00556 { 00557 P1SwOverflow = true; 00558 return; 00559 } 00560 } 00561 else 00562 { 00563 value = value + sweep; 00564 if (value > 0x7ff) 00565 { 00566 P1SwOverflow = true; 00567 return; 00568 } 00569 } 00570 P1Timer = value; 00571 00572 APU_Reg[3] &= 7; 00573 APU_Reg[3] |= value >> 8; 00574 APU_Reg[2] = value & 0xff; 00575 00576 P1WaveLength = (value + 1) * 1000; 00577 P1WavePeriod = P1WaveLength * 8; 00578 } 00579 } 00580 00581 //==================== 00582 // Pulse1 Sweep 00583 //==================== 00584 if (P2SwReloadFlag) 00585 { 00586 P2Sweep = ((APU_Reg[5] & 0x70) >> 4) + 1; 00587 P2SwCnt = 0; 00588 P2SwReloadFlag = false; 00589 } 00590 else if (APU_Reg[5] & 0x80 && !P2SwOverflow) 00591 { 00592 P2SwCnt++; 00593 if (P2SwCnt == P2Sweep) 00594 { 00595 P2SwCnt = 0; 00596 00597 int sweep = P2Timer >> P2SwLevel; 00598 int value = P2Timer; 00599 if (APU_Reg[5] & 8) 00600 { 00601 value = value - sweep; 00602 if (value < 8) 00603 { 00604 P2SwOverflow = true; 00605 return; 00606 } 00607 } 00608 else 00609 { 00610 value = value + sweep; 00611 if (value > 0x7ff) 00612 { 00613 P2SwOverflow = true; 00614 return; 00615 } 00616 } 00617 00618 P2Timer = value; 00619 00620 APU_Reg[7] &= 7; 00621 APU_Reg[7] |= value >> 8; 00622 APU_Reg[6] = value & 0xff; 00623 00624 P2WaveLength = (value + 1) * 1000; 00625 P2WavePeriod = P2WaveLength * 8; 00626 00627 } 00628 } 00629 } 00630 00631 /*-------------------------------------------------------------------*/ 00632 /* 60Hz Clock */ 00633 /*-------------------------------------------------------------------*/ 00634 void pNesX_ApuClk_60Hz() 00635 { 00636 // Pulse1 00637 if (!(APU_Reg[0] & 0x20) && P1LengthCounter > 0) 00638 { 00639 P1LengthCounter--; 00640 } 00641 00642 // Pulse2 00643 if (!(APU_Reg[4] & 0x20) && P2LengthCounter > 0) 00644 { 00645 P2LengthCounter--; 00646 } 00647 00648 // Triangle 00649 if (!(APU_Reg[0x8] & 0x80) && TrLengthCounter > 0) 00650 { 00651 TrLengthCounter--; 00652 } 00653 00654 // Noise 00655 if (!(APU_Reg[0xc] & 0x20) && NsLengthCounter > 0) 00656 { 00657 NsLengthCounter--; 00658 } 00659 00660 } 00661 00662 /*-------------------------------------------------------------------*/ 00663 /* Status */ 00664 /*-------------------------------------------------------------------*/ 00665 BYTE ApuRead( WORD wAddr ) 00666 { 00667 if (wAddr == 0x15) 00668 { 00669 return (P1LengthCounter > 0) | (P2LengthCounter > 0) << 1 | (TrLengthCounter > 0) << 2 | (NsLengthCounter > 0) << 3; 00670 } 00671 00672 return APU_Reg[ wAddr ]; 00673 } 00674
Generated on Tue Jul 12 2022 20:36:59 by 1.7.2