I have ported my old project “pNesX” game console emulator to the nucleo.

Dependencies:   SDFileSystem mbed

Intro

I have ported my old project “pNesX” to the STM32 Nucleo. The pNesX is a NES emulator for the PlayStation that I have created 16 years ago!

Emulation part was almost without change, the sound part was newly added.

Parts

STM32 Nucleo F446RE
QVGA 2.2 TFT SPI (with the SD card slot)
Audio jack(TS or TRS)
USB Connector
Register 100k, 10k, 4.7k, 100
Capacitor 0.01uF, 2.2uF
Breadboard
Wires
Computer Speakers
USB GamePad

Wiring diagram

/media/uploads/beaglescout007/nucleo_ex06_emu.png

TFT J2Nucleo
VCC3V3
GNDGND
CSPB_5(D4)
ResetPA_10(D2) Pull Up(100k)
D/CPA_8(D7)
MOSIPA_7(D11)
SCKPA_5(D13)
LEDLED-100ohm-3V3
MISOPA_6(D12)
TFT J4Nucleo
SD_CSPA_9
SD_MOSIPB_15
SD_MISOPB_14
SD_SCKPB_13
AudioNucleo
TIPPA_4(A2)
USB con.Nucleo
GNDGND
+PA_12
-PA_11
5V5V

https://youtu.be/jL24IjT6LnI

Limitations

  • Since the rest of the RAM is about 50kbyte, maximum capacity of the game ROM is about 50kbyte.
  • The length of the file name up to 32 characters.
  • The number of files in the folder is up to 100.

Used Library

Committer:
beaglescout007
Date:
Sun Apr 03 07:45:29 2016 +0000
Revision:
0:3dac1f1bc9e0
Release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
beaglescout007 0:3dac1f1bc9e0 1 /*===================================================================*/
beaglescout007 0:3dac1f1bc9e0 2 /* */
beaglescout007 0:3dac1f1bc9e0 3 /* pNesX_Apu.cpp : NES APU emulation (for Nucleo) */
beaglescout007 0:3dac1f1bc9e0 4 /* */
beaglescout007 0:3dac1f1bc9e0 5 /* 2016/1/20 Racoon */
beaglescout007 0:3dac1f1bc9e0 6 /* */
beaglescout007 0:3dac1f1bc9e0 7 /*===================================================================*/
beaglescout007 0:3dac1f1bc9e0 8
beaglescout007 0:3dac1f1bc9e0 9 #include "mbed.h"
beaglescout007 0:3dac1f1bc9e0 10 #include "SDFileSystem.h"
beaglescout007 0:3dac1f1bc9e0 11
beaglescout007 0:3dac1f1bc9e0 12 #include "pNesX.h"
beaglescout007 0:3dac1f1bc9e0 13 #include "pNesX_System.h"
beaglescout007 0:3dac1f1bc9e0 14
beaglescout007 0:3dac1f1bc9e0 15 //====================
beaglescout007 0:3dac1f1bc9e0 16 // DAC
beaglescout007 0:3dac1f1bc9e0 17 //====================
beaglescout007 0:3dac1f1bc9e0 18 AnalogOut DAC_Out(PA_4);
beaglescout007 0:3dac1f1bc9e0 19 WORD TrDac, P1Dac, P2Dac, NsDac, MixDac;
beaglescout007 0:3dac1f1bc9e0 20 #define DACFreq 24000
beaglescout007 0:3dac1f1bc9e0 21 // Pulse clock(8 steps) = 1789773 / 2 / DACFreq * 1000
beaglescout007 0:3dac1f1bc9e0 22 #define PuClock 37287
beaglescout007 0:3dac1f1bc9e0 23 // Triangle clock(32 steps) = 1789773 / DACFreq * 1000
beaglescout007 0:3dac1f1bc9e0 24 #define TrClock 74574
beaglescout007 0:3dac1f1bc9e0 25
beaglescout007 0:3dac1f1bc9e0 26 //====================
beaglescout007 0:3dac1f1bc9e0 27 // DAC Timer
beaglescout007 0:3dac1f1bc9e0 28 //====================
beaglescout007 0:3dac1f1bc9e0 29 #define TIMx TIM4
beaglescout007 0:3dac1f1bc9e0 30 #define TIMx_CLK_ENABLE __HAL_RCC_TIM4_CLK_ENABLE
beaglescout007 0:3dac1f1bc9e0 31 #define TIMx_IRQn TIM4_IRQn
beaglescout007 0:3dac1f1bc9e0 32 #define TIMx_IRQHandler TIM4_IRQHandler
beaglescout007 0:3dac1f1bc9e0 33 TIM_HandleTypeDef TimHandle;
beaglescout007 0:3dac1f1bc9e0 34
beaglescout007 0:3dac1f1bc9e0 35 //====================
beaglescout007 0:3dac1f1bc9e0 36 // Audio channel variables
beaglescout007 0:3dac1f1bc9e0 37 //====================
beaglescout007 0:3dac1f1bc9e0 38
beaglescout007 0:3dac1f1bc9e0 39 const BYTE LengthTable[] = {10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14,
beaglescout007 0:3dac1f1bc9e0 40 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30};
beaglescout007 0:3dac1f1bc9e0 41
beaglescout007 0:3dac1f1bc9e0 42 // Minimum Volume
beaglescout007 0:3dac1f1bc9e0 43 #define MV 4096
beaglescout007 0:3dac1f1bc9e0 44 const WORD Pulse_Table[4][8] = { 0,MV, 0, 0, 0, 0, 0, 0,
beaglescout007 0:3dac1f1bc9e0 45 0,MV,MV, 0, 0, 0, 0, 0,
beaglescout007 0:3dac1f1bc9e0 46 0,MV,MV,MV,MV, 0, 0, 0,
beaglescout007 0:3dac1f1bc9e0 47 MV, 0, 0,MV,MV,MV,MV,MV};
beaglescout007 0:3dac1f1bc9e0 48 // Pulse1
beaglescout007 0:3dac1f1bc9e0 49 bool P1Enable;
beaglescout007 0:3dac1f1bc9e0 50 int P1Timer;
beaglescout007 0:3dac1f1bc9e0 51 int P1WaveLength;
beaglescout007 0:3dac1f1bc9e0 52 int P1WavePeriod;
beaglescout007 0:3dac1f1bc9e0 53 int P1Lapse;
beaglescout007 0:3dac1f1bc9e0 54 int P1Duty;
beaglescout007 0:3dac1f1bc9e0 55 int P1Vol;
beaglescout007 0:3dac1f1bc9e0 56 int P1LengthCounter;
beaglescout007 0:3dac1f1bc9e0 57 int P1EnvSeq;
beaglescout007 0:3dac1f1bc9e0 58 int P1EnvCnt;
beaglescout007 0:3dac1f1bc9e0 59 int P1Sweep;
beaglescout007 0:3dac1f1bc9e0 60 int P1SwCnt;
beaglescout007 0:3dac1f1bc9e0 61 int P1SwLevel;
beaglescout007 0:3dac1f1bc9e0 62 bool P1SwReloadFlag;
beaglescout007 0:3dac1f1bc9e0 63 bool P1SwOverflow;
beaglescout007 0:3dac1f1bc9e0 64
beaglescout007 0:3dac1f1bc9e0 65 // Pulse2
beaglescout007 0:3dac1f1bc9e0 66 bool P2Enable;
beaglescout007 0:3dac1f1bc9e0 67 int P2Timer;
beaglescout007 0:3dac1f1bc9e0 68 int P2WaveLength;
beaglescout007 0:3dac1f1bc9e0 69 int P2WavePeriod;
beaglescout007 0:3dac1f1bc9e0 70 int P2Lapse;
beaglescout007 0:3dac1f1bc9e0 71 int P2Duty;
beaglescout007 0:3dac1f1bc9e0 72 int P2Vol;
beaglescout007 0:3dac1f1bc9e0 73 int P2LengthCounter;
beaglescout007 0:3dac1f1bc9e0 74 int P2EnvSeq;
beaglescout007 0:3dac1f1bc9e0 75 int P2EnvCnt;
beaglescout007 0:3dac1f1bc9e0 76 int P2Sweep;
beaglescout007 0:3dac1f1bc9e0 77 int P2SwCnt;
beaglescout007 0:3dac1f1bc9e0 78 int P2SwLevel;
beaglescout007 0:3dac1f1bc9e0 79 bool P2SwReloadFlag;
beaglescout007 0:3dac1f1bc9e0 80 bool P2SwOverflow;
beaglescout007 0:3dac1f1bc9e0 81
beaglescout007 0:3dac1f1bc9e0 82 // Triangle
beaglescout007 0:3dac1f1bc9e0 83 bool TrEnable;
beaglescout007 0:3dac1f1bc9e0 84 int TrTimer;
beaglescout007 0:3dac1f1bc9e0 85 const WORD Triangle_Table[] = {61440,57344,53248,49152,45056,40960,36864,32768,28672,24576,20480,16384,12288,8192,4096,0,
beaglescout007 0:3dac1f1bc9e0 86 0,4096,8192,12288,16384,20480,24576,28672,32768,36864,40960,45056,49152,53248,57344,61440};
beaglescout007 0:3dac1f1bc9e0 87 bool LinearCounterReloadFlag;
beaglescout007 0:3dac1f1bc9e0 88 int LinearCounter;
beaglescout007 0:3dac1f1bc9e0 89 int TrLengthCounter;
beaglescout007 0:3dac1f1bc9e0 90 int TrWaveLength;
beaglescout007 0:3dac1f1bc9e0 91 int TrWavePeriod;
beaglescout007 0:3dac1f1bc9e0 92 int TrLapse;
beaglescout007 0:3dac1f1bc9e0 93
beaglescout007 0:3dac1f1bc9e0 94 // Noise
beaglescout007 0:3dac1f1bc9e0 95 bool NsEnable;
beaglescout007 0:3dac1f1bc9e0 96 const WORD Noise_Freq[] = {0,0,0,0,0,0,12000,11186,8860,7046,4710,3523,2349,1762,880,440};
beaglescout007 0:3dac1f1bc9e0 97 int NsFreq;
beaglescout007 0:3dac1f1bc9e0 98 int NsSum;
beaglescout007 0:3dac1f1bc9e0 99 int NsVol;
beaglescout007 0:3dac1f1bc9e0 100 int NsLengthCounter;
beaglescout007 0:3dac1f1bc9e0 101 int NsEnvSeq;
beaglescout007 0:3dac1f1bc9e0 102 int NsEnvCnt;
beaglescout007 0:3dac1f1bc9e0 103
beaglescout007 0:3dac1f1bc9e0 104 // DMC
beaglescout007 0:3dac1f1bc9e0 105 int DmOutLevel;
beaglescout007 0:3dac1f1bc9e0 106
beaglescout007 0:3dac1f1bc9e0 107 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 108 /* DAC Timer callback */
beaglescout007 0:3dac1f1bc9e0 109 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 110 extern "C" {
beaglescout007 0:3dac1f1bc9e0 111 void TIMx_IRQHandler(void)
beaglescout007 0:3dac1f1bc9e0 112 {
beaglescout007 0:3dac1f1bc9e0 113 HAL_TIM_IRQHandler(&TimHandle);
beaglescout007 0:3dac1f1bc9e0 114 }
beaglescout007 0:3dac1f1bc9e0 115
beaglescout007 0:3dac1f1bc9e0 116 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
beaglescout007 0:3dac1f1bc9e0 117 {
beaglescout007 0:3dac1f1bc9e0 118 TIMx_CLK_ENABLE();
beaglescout007 0:3dac1f1bc9e0 119
beaglescout007 0:3dac1f1bc9e0 120 HAL_NVIC_SetPriority(TIMx_IRQn, 4, 0);
beaglescout007 0:3dac1f1bc9e0 121 HAL_NVIC_EnableIRQ(TIMx_IRQn);
beaglescout007 0:3dac1f1bc9e0 122 }
beaglescout007 0:3dac1f1bc9e0 123
beaglescout007 0:3dac1f1bc9e0 124 static void Error_Handler(void)
beaglescout007 0:3dac1f1bc9e0 125 {
beaglescout007 0:3dac1f1bc9e0 126 while(1);
beaglescout007 0:3dac1f1bc9e0 127 }
beaglescout007 0:3dac1f1bc9e0 128 } // extern "C"
beaglescout007 0:3dac1f1bc9e0 129
beaglescout007 0:3dac1f1bc9e0 130 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 131 /* Randomize value (Noise channel) */
beaglescout007 0:3dac1f1bc9e0 132 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 133 WORD ShiftReg = 1;
beaglescout007 0:3dac1f1bc9e0 134
beaglescout007 0:3dac1f1bc9e0 135 WORD Rand96()
beaglescout007 0:3dac1f1bc9e0 136 {
beaglescout007 0:3dac1f1bc9e0 137 ShiftReg |= ((ShiftReg ^ (ShiftReg >> 6)) & 1) << 15;
beaglescout007 0:3dac1f1bc9e0 138 ShiftReg >>= 1;
beaglescout007 0:3dac1f1bc9e0 139 return (ShiftReg & 1) ? MV : 0;
beaglescout007 0:3dac1f1bc9e0 140 }
beaglescout007 0:3dac1f1bc9e0 141
beaglescout007 0:3dac1f1bc9e0 142 WORD Rand32k()
beaglescout007 0:3dac1f1bc9e0 143 {
beaglescout007 0:3dac1f1bc9e0 144 ShiftReg |= ((ShiftReg ^ (ShiftReg >> 1)) & 1) << 15;
beaglescout007 0:3dac1f1bc9e0 145 ShiftReg >>= 1;
beaglescout007 0:3dac1f1bc9e0 146 return (ShiftReg & 1) ? MV : 0;
beaglescout007 0:3dac1f1bc9e0 147 }
beaglescout007 0:3dac1f1bc9e0 148
beaglescout007 0:3dac1f1bc9e0 149 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 150 /* DAC Timer Interrup */
beaglescout007 0:3dac1f1bc9e0 151 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 152 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
beaglescout007 0:3dac1f1bc9e0 153 {
beaglescout007 0:3dac1f1bc9e0 154 // Pulse1
beaglescout007 0:3dac1f1bc9e0 155 if (P1Enable && P1LengthCounter > 0 && !P1SwOverflow && P1Timer > 8)
beaglescout007 0:3dac1f1bc9e0 156 {
beaglescout007 0:3dac1f1bc9e0 157 P1Lapse += PuClock;
beaglescout007 0:3dac1f1bc9e0 158 P1Lapse %= P1WavePeriod;
beaglescout007 0:3dac1f1bc9e0 159 P1Dac = Pulse_Table[P1Duty][P1Lapse / P1WaveLength] * P1Vol;
beaglescout007 0:3dac1f1bc9e0 160 }
beaglescout007 0:3dac1f1bc9e0 161
beaglescout007 0:3dac1f1bc9e0 162 // Pulse2
beaglescout007 0:3dac1f1bc9e0 163 if (P2Enable && P2LengthCounter > 0 && !P2SwOverflow && P2Timer > 8)
beaglescout007 0:3dac1f1bc9e0 164 {
beaglescout007 0:3dac1f1bc9e0 165 P2Lapse += PuClock;
beaglescout007 0:3dac1f1bc9e0 166 P2Lapse %= P2WavePeriod;
beaglescout007 0:3dac1f1bc9e0 167 P2Dac = Pulse_Table[P2Duty][P2Lapse / P2WaveLength] * P2Vol;
beaglescout007 0:3dac1f1bc9e0 168 }
beaglescout007 0:3dac1f1bc9e0 169
beaglescout007 0:3dac1f1bc9e0 170 // Triangle
beaglescout007 0:3dac1f1bc9e0 171 if (TrEnable && LinearCounter > 0 && TrLengthCounter > 0)
beaglescout007 0:3dac1f1bc9e0 172 {
beaglescout007 0:3dac1f1bc9e0 173 TrLapse += TrClock;
beaglescout007 0:3dac1f1bc9e0 174 TrLapse %= TrWavePeriod;
beaglescout007 0:3dac1f1bc9e0 175 TrDac = Triangle_Table[TrLapse / TrWaveLength];
beaglescout007 0:3dac1f1bc9e0 176 TrDac -= (TrDac * DmOutLevel / 295);
beaglescout007 0:3dac1f1bc9e0 177 }
beaglescout007 0:3dac1f1bc9e0 178
beaglescout007 0:3dac1f1bc9e0 179 // Noise
beaglescout007 0:3dac1f1bc9e0 180 if (NsEnable && NsLengthCounter > 0)
beaglescout007 0:3dac1f1bc9e0 181 {
beaglescout007 0:3dac1f1bc9e0 182 NsSum += NsFreq;
beaglescout007 0:3dac1f1bc9e0 183 if (NsSum >= DACFreq)
beaglescout007 0:3dac1f1bc9e0 184 {
beaglescout007 0:3dac1f1bc9e0 185 NsSum %= DACFreq;
beaglescout007 0:3dac1f1bc9e0 186
beaglescout007 0:3dac1f1bc9e0 187 NsDac = ((APU_Reg[0xe] & 0x80) ? Rand96() : Rand32k()) * NsVol;
beaglescout007 0:3dac1f1bc9e0 188 NsDac -= (NsDac * DmOutLevel / 295);
beaglescout007 0:3dac1f1bc9e0 189 }
beaglescout007 0:3dac1f1bc9e0 190 }
beaglescout007 0:3dac1f1bc9e0 191
beaglescout007 0:3dac1f1bc9e0 192 // Mixing
beaglescout007 0:3dac1f1bc9e0 193 MixDac = (P1Dac + P2Dac + TrDac + NsDac) / 4;
beaglescout007 0:3dac1f1bc9e0 194
beaglescout007 0:3dac1f1bc9e0 195 // Output to DAC
beaglescout007 0:3dac1f1bc9e0 196 DAC_Out.write_u16(MixDac);
beaglescout007 0:3dac1f1bc9e0 197 }
beaglescout007 0:3dac1f1bc9e0 198
beaglescout007 0:3dac1f1bc9e0 199 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 200 /* Apu Initialize Function */
beaglescout007 0:3dac1f1bc9e0 201 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 202 void ApuInit()
beaglescout007 0:3dac1f1bc9e0 203 {
beaglescout007 0:3dac1f1bc9e0 204 // Setup DAC Timer
beaglescout007 0:3dac1f1bc9e0 205 TimHandle.Instance = TIMx;
beaglescout007 0:3dac1f1bc9e0 206 TimHandle.Init.Prescaler = (uint32_t) ((SystemCoreClock / 2) / 240000) - 1; // 240000Hz
beaglescout007 0:3dac1f1bc9e0 207 TimHandle.Init.Period = 10 - 1; // 240000/10=24000Hz
beaglescout007 0:3dac1f1bc9e0 208 TimHandle.Init.ClockDivision = 0;
beaglescout007 0:3dac1f1bc9e0 209 TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
beaglescout007 0:3dac1f1bc9e0 210
beaglescout007 0:3dac1f1bc9e0 211 if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
beaglescout007 0:3dac1f1bc9e0 212 Error_Handler();
beaglescout007 0:3dac1f1bc9e0 213
beaglescout007 0:3dac1f1bc9e0 214 if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
beaglescout007 0:3dac1f1bc9e0 215 Error_Handler();
beaglescout007 0:3dac1f1bc9e0 216 }
beaglescout007 0:3dac1f1bc9e0 217
beaglescout007 0:3dac1f1bc9e0 218 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 219 /* Apu Mute */
beaglescout007 0:3dac1f1bc9e0 220 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 221 void ApuMute(bool mute)
beaglescout007 0:3dac1f1bc9e0 222 {
beaglescout007 0:3dac1f1bc9e0 223 if (mute)
beaglescout007 0:3dac1f1bc9e0 224 {
beaglescout007 0:3dac1f1bc9e0 225 if(HAL_TIM_Base_Stop_IT(&TimHandle) != HAL_OK)
beaglescout007 0:3dac1f1bc9e0 226 Error_Handler();
beaglescout007 0:3dac1f1bc9e0 227 }
beaglescout007 0:3dac1f1bc9e0 228 else
beaglescout007 0:3dac1f1bc9e0 229 {
beaglescout007 0:3dac1f1bc9e0 230 if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
beaglescout007 0:3dac1f1bc9e0 231 Error_Handler();
beaglescout007 0:3dac1f1bc9e0 232 }
beaglescout007 0:3dac1f1bc9e0 233 }
beaglescout007 0:3dac1f1bc9e0 234
beaglescout007 0:3dac1f1bc9e0 235 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 236 /* Apu Write Function */
beaglescout007 0:3dac1f1bc9e0 237 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 238 void ApuWrite( WORD wAddr, BYTE byData )
beaglescout007 0:3dac1f1bc9e0 239 {
beaglescout007 0:3dac1f1bc9e0 240 APU_Reg[ wAddr ] = byData;
beaglescout007 0:3dac1f1bc9e0 241
beaglescout007 0:3dac1f1bc9e0 242 switch( wAddr )
beaglescout007 0:3dac1f1bc9e0 243 {
beaglescout007 0:3dac1f1bc9e0 244 //====================
beaglescout007 0:3dac1f1bc9e0 245 // Pulse1
beaglescout007 0:3dac1f1bc9e0 246 //====================
beaglescout007 0:3dac1f1bc9e0 247 case 0:
beaglescout007 0:3dac1f1bc9e0 248 P1Duty = (byData & 0xc0) >> 6;
beaglescout007 0:3dac1f1bc9e0 249
beaglescout007 0:3dac1f1bc9e0 250 if (byData & 0x10)
beaglescout007 0:3dac1f1bc9e0 251 {
beaglescout007 0:3dac1f1bc9e0 252 // constant volume
beaglescout007 0:3dac1f1bc9e0 253 P1Vol = byData & 0xf;
beaglescout007 0:3dac1f1bc9e0 254 }
beaglescout007 0:3dac1f1bc9e0 255 else
beaglescout007 0:3dac1f1bc9e0 256 {
beaglescout007 0:3dac1f1bc9e0 257 // envelope on
beaglescout007 0:3dac1f1bc9e0 258 P1Vol = 15;
beaglescout007 0:3dac1f1bc9e0 259 P1EnvCnt = (byData & 0xf) + 1;
beaglescout007 0:3dac1f1bc9e0 260 }
beaglescout007 0:3dac1f1bc9e0 261 break;
beaglescout007 0:3dac1f1bc9e0 262
beaglescout007 0:3dac1f1bc9e0 263 case 1:
beaglescout007 0:3dac1f1bc9e0 264 P1SwReloadFlag = true;
beaglescout007 0:3dac1f1bc9e0 265 P1SwLevel = (byData & 7);
beaglescout007 0:3dac1f1bc9e0 266 break;
beaglescout007 0:3dac1f1bc9e0 267
beaglescout007 0:3dac1f1bc9e0 268 case 2:
beaglescout007 0:3dac1f1bc9e0 269 case 3:
beaglescout007 0:3dac1f1bc9e0 270 P1Timer = APU_Reg[3] & 7;
beaglescout007 0:3dac1f1bc9e0 271 P1Timer = (P1Timer << 8) | APU_Reg[2];
beaglescout007 0:3dac1f1bc9e0 272 P1WaveLength = (P1Timer+1) * 1000;
beaglescout007 0:3dac1f1bc9e0 273 P1WavePeriod = P1WaveLength * 8;
beaglescout007 0:3dac1f1bc9e0 274
beaglescout007 0:3dac1f1bc9e0 275 if (wAddr == 3)
beaglescout007 0:3dac1f1bc9e0 276 {
beaglescout007 0:3dac1f1bc9e0 277 P1LengthCounter = LengthTable[(byData & 0xf8) >> 3];
beaglescout007 0:3dac1f1bc9e0 278
beaglescout007 0:3dac1f1bc9e0 279 // Reset sequencer
beaglescout007 0:3dac1f1bc9e0 280 P1Lapse = 0;
beaglescout007 0:3dac1f1bc9e0 281 P1EnvSeq = P1EnvCnt;
beaglescout007 0:3dac1f1bc9e0 282 P1Sweep = 0;
beaglescout007 0:3dac1f1bc9e0 283 P1SwCnt = 0;
beaglescout007 0:3dac1f1bc9e0 284 P1SwOverflow = false;
beaglescout007 0:3dac1f1bc9e0 285 }
beaglescout007 0:3dac1f1bc9e0 286 break;
beaglescout007 0:3dac1f1bc9e0 287
beaglescout007 0:3dac1f1bc9e0 288 //====================
beaglescout007 0:3dac1f1bc9e0 289 // Pulse2
beaglescout007 0:3dac1f1bc9e0 290 //====================
beaglescout007 0:3dac1f1bc9e0 291 case 4:
beaglescout007 0:3dac1f1bc9e0 292 P2Duty = (byData & 0xc0) >> 6;
beaglescout007 0:3dac1f1bc9e0 293
beaglescout007 0:3dac1f1bc9e0 294 if (byData & 0x10)
beaglescout007 0:3dac1f1bc9e0 295 {
beaglescout007 0:3dac1f1bc9e0 296 // constant volume
beaglescout007 0:3dac1f1bc9e0 297 P2Vol = byData & 0xf;
beaglescout007 0:3dac1f1bc9e0 298 }
beaglescout007 0:3dac1f1bc9e0 299 else
beaglescout007 0:3dac1f1bc9e0 300 {
beaglescout007 0:3dac1f1bc9e0 301 // envelope on
beaglescout007 0:3dac1f1bc9e0 302 P2Vol = 15;
beaglescout007 0:3dac1f1bc9e0 303 P2EnvCnt = (byData & 0xf) + 1;
beaglescout007 0:3dac1f1bc9e0 304 }
beaglescout007 0:3dac1f1bc9e0 305 break;
beaglescout007 0:3dac1f1bc9e0 306
beaglescout007 0:3dac1f1bc9e0 307 case 5:
beaglescout007 0:3dac1f1bc9e0 308 P2SwReloadFlag = true;
beaglescout007 0:3dac1f1bc9e0 309 P2SwLevel = (byData & 7);
beaglescout007 0:3dac1f1bc9e0 310 break;
beaglescout007 0:3dac1f1bc9e0 311
beaglescout007 0:3dac1f1bc9e0 312 case 6:
beaglescout007 0:3dac1f1bc9e0 313 case 7:
beaglescout007 0:3dac1f1bc9e0 314 P2Timer = APU_Reg[7] & 7;
beaglescout007 0:3dac1f1bc9e0 315 P2Timer = (P2Timer << 8) | APU_Reg[6];
beaglescout007 0:3dac1f1bc9e0 316 P2WaveLength = (P2Timer+1) * 1000;
beaglescout007 0:3dac1f1bc9e0 317 P2WavePeriod = P2WaveLength * 8;
beaglescout007 0:3dac1f1bc9e0 318 if (wAddr == 7)
beaglescout007 0:3dac1f1bc9e0 319 {
beaglescout007 0:3dac1f1bc9e0 320 P2LengthCounter = LengthTable[(byData & 0xf8) >> 3];
beaglescout007 0:3dac1f1bc9e0 321
beaglescout007 0:3dac1f1bc9e0 322 // Reset sequencer
beaglescout007 0:3dac1f1bc9e0 323 P2Lapse = 0;
beaglescout007 0:3dac1f1bc9e0 324 P2EnvSeq = P2EnvCnt;
beaglescout007 0:3dac1f1bc9e0 325 P2Sweep = 0;
beaglescout007 0:3dac1f1bc9e0 326 P2SwCnt = 0;
beaglescout007 0:3dac1f1bc9e0 327 P2SwOverflow = false;
beaglescout007 0:3dac1f1bc9e0 328 }
beaglescout007 0:3dac1f1bc9e0 329 break;
beaglescout007 0:3dac1f1bc9e0 330
beaglescout007 0:3dac1f1bc9e0 331 //====================
beaglescout007 0:3dac1f1bc9e0 332 // Triangle
beaglescout007 0:3dac1f1bc9e0 333 //====================
beaglescout007 0:3dac1f1bc9e0 334 case 0x8:
beaglescout007 0:3dac1f1bc9e0 335 LinearCounterReloadFlag = true;
beaglescout007 0:3dac1f1bc9e0 336 break;
beaglescout007 0:3dac1f1bc9e0 337
beaglescout007 0:3dac1f1bc9e0 338 case 0xA:
beaglescout007 0:3dac1f1bc9e0 339 case 0xB:
beaglescout007 0:3dac1f1bc9e0 340 TrTimer = APU_Reg[0xB] & 7;
beaglescout007 0:3dac1f1bc9e0 341 TrTimer = (TrTimer << 8) | APU_Reg[0xA];
beaglescout007 0:3dac1f1bc9e0 342 TrWaveLength = TrTimer * 1000;
beaglescout007 0:3dac1f1bc9e0 343 TrWavePeriod = TrWaveLength * 32;
beaglescout007 0:3dac1f1bc9e0 344
beaglescout007 0:3dac1f1bc9e0 345 if (wAddr == 0xB)
beaglescout007 0:3dac1f1bc9e0 346 {
beaglescout007 0:3dac1f1bc9e0 347 TrLengthCounter = LengthTable[(byData & 0xf8) >> 3];
beaglescout007 0:3dac1f1bc9e0 348 LinearCounterReloadFlag = true;
beaglescout007 0:3dac1f1bc9e0 349 }
beaglescout007 0:3dac1f1bc9e0 350 break;
beaglescout007 0:3dac1f1bc9e0 351
beaglescout007 0:3dac1f1bc9e0 352 //====================
beaglescout007 0:3dac1f1bc9e0 353 // Noise
beaglescout007 0:3dac1f1bc9e0 354 //====================
beaglescout007 0:3dac1f1bc9e0 355 case 0xC:
beaglescout007 0:3dac1f1bc9e0 356 if (byData & 0x10)
beaglescout007 0:3dac1f1bc9e0 357 {
beaglescout007 0:3dac1f1bc9e0 358 // constant volume
beaglescout007 0:3dac1f1bc9e0 359 NsVol = byData & 0xf;
beaglescout007 0:3dac1f1bc9e0 360 }
beaglescout007 0:3dac1f1bc9e0 361 else
beaglescout007 0:3dac1f1bc9e0 362 {
beaglescout007 0:3dac1f1bc9e0 363 // envelope on
beaglescout007 0:3dac1f1bc9e0 364 NsVol = 15;
beaglescout007 0:3dac1f1bc9e0 365 NsEnvCnt = (byData & 0xf) + 1;
beaglescout007 0:3dac1f1bc9e0 366 }
beaglescout007 0:3dac1f1bc9e0 367 break;
beaglescout007 0:3dac1f1bc9e0 368
beaglescout007 0:3dac1f1bc9e0 369 case 0xF:
beaglescout007 0:3dac1f1bc9e0 370 NsLengthCounter = LengthTable[(byData & 0xf8) >> 3];
beaglescout007 0:3dac1f1bc9e0 371
beaglescout007 0:3dac1f1bc9e0 372 // Reset sequencer
beaglescout007 0:3dac1f1bc9e0 373 NsEnvSeq = NsEnvCnt;
beaglescout007 0:3dac1f1bc9e0 374 break;
beaglescout007 0:3dac1f1bc9e0 375
beaglescout007 0:3dac1f1bc9e0 376 case 0xE:
beaglescout007 0:3dac1f1bc9e0 377 NsFreq = Noise_Freq[byData & 0xf];
beaglescout007 0:3dac1f1bc9e0 378 break;
beaglescout007 0:3dac1f1bc9e0 379
beaglescout007 0:3dac1f1bc9e0 380 //====================
beaglescout007 0:3dac1f1bc9e0 381 // DMC(PCM)
beaglescout007 0:3dac1f1bc9e0 382 //====================
beaglescout007 0:3dac1f1bc9e0 383 case 0x11:
beaglescout007 0:3dac1f1bc9e0 384 DmOutLevel = byData & 0x7f;
beaglescout007 0:3dac1f1bc9e0 385 break;
beaglescout007 0:3dac1f1bc9e0 386
beaglescout007 0:3dac1f1bc9e0 387 //====================
beaglescout007 0:3dac1f1bc9e0 388 // Control
beaglescout007 0:3dac1f1bc9e0 389 //====================
beaglescout007 0:3dac1f1bc9e0 390 case 0x15:
beaglescout007 0:3dac1f1bc9e0 391 if (byData & 1)
beaglescout007 0:3dac1f1bc9e0 392 {
beaglescout007 0:3dac1f1bc9e0 393 P1Enable = true;
beaglescout007 0:3dac1f1bc9e0 394 }
beaglescout007 0:3dac1f1bc9e0 395 else
beaglescout007 0:3dac1f1bc9e0 396 {
beaglescout007 0:3dac1f1bc9e0 397 P1Enable = false;
beaglescout007 0:3dac1f1bc9e0 398 P1LengthCounter = 0;
beaglescout007 0:3dac1f1bc9e0 399 }
beaglescout007 0:3dac1f1bc9e0 400
beaglescout007 0:3dac1f1bc9e0 401 if (byData & 2)
beaglescout007 0:3dac1f1bc9e0 402 {
beaglescout007 0:3dac1f1bc9e0 403 P2Enable = true;
beaglescout007 0:3dac1f1bc9e0 404 }
beaglescout007 0:3dac1f1bc9e0 405 else
beaglescout007 0:3dac1f1bc9e0 406 {
beaglescout007 0:3dac1f1bc9e0 407 P2Enable = false;
beaglescout007 0:3dac1f1bc9e0 408 P2LengthCounter = 0;
beaglescout007 0:3dac1f1bc9e0 409 }
beaglescout007 0:3dac1f1bc9e0 410
beaglescout007 0:3dac1f1bc9e0 411 if (byData & 4)
beaglescout007 0:3dac1f1bc9e0 412 {
beaglescout007 0:3dac1f1bc9e0 413 TrEnable = true;
beaglescout007 0:3dac1f1bc9e0 414 }
beaglescout007 0:3dac1f1bc9e0 415 else
beaglescout007 0:3dac1f1bc9e0 416 {
beaglescout007 0:3dac1f1bc9e0 417 TrEnable = false;
beaglescout007 0:3dac1f1bc9e0 418 TrLengthCounter = 0;
beaglescout007 0:3dac1f1bc9e0 419 }
beaglescout007 0:3dac1f1bc9e0 420
beaglescout007 0:3dac1f1bc9e0 421 if (byData & 8)
beaglescout007 0:3dac1f1bc9e0 422 {
beaglescout007 0:3dac1f1bc9e0 423 NsEnable = true;
beaglescout007 0:3dac1f1bc9e0 424 }
beaglescout007 0:3dac1f1bc9e0 425 else
beaglescout007 0:3dac1f1bc9e0 426 {
beaglescout007 0:3dac1f1bc9e0 427 NsEnable = false;
beaglescout007 0:3dac1f1bc9e0 428 NsLengthCounter = 0;
beaglescout007 0:3dac1f1bc9e0 429 }
beaglescout007 0:3dac1f1bc9e0 430 break;
beaglescout007 0:3dac1f1bc9e0 431 } // Switch( wAddr )
beaglescout007 0:3dac1f1bc9e0 432 }
beaglescout007 0:3dac1f1bc9e0 433
beaglescout007 0:3dac1f1bc9e0 434 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 435 /* 240Hz Clock */
beaglescout007 0:3dac1f1bc9e0 436 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 437 void pNesX_ApuClk_240Hz()
beaglescout007 0:3dac1f1bc9e0 438 {
beaglescout007 0:3dac1f1bc9e0 439 //====================
beaglescout007 0:3dac1f1bc9e0 440 // Pulse1 Envelope
beaglescout007 0:3dac1f1bc9e0 441 //====================
beaglescout007 0:3dac1f1bc9e0 442 if (!(APU_Reg[0] & 0x10) && P1EnvSeq > 0)
beaglescout007 0:3dac1f1bc9e0 443 {
beaglescout007 0:3dac1f1bc9e0 444 P1EnvSeq--;
beaglescout007 0:3dac1f1bc9e0 445 if (P1EnvSeq == 0)
beaglescout007 0:3dac1f1bc9e0 446 {
beaglescout007 0:3dac1f1bc9e0 447 if (P1Vol > 0)
beaglescout007 0:3dac1f1bc9e0 448 {
beaglescout007 0:3dac1f1bc9e0 449 --P1Vol;
beaglescout007 0:3dac1f1bc9e0 450 P1EnvSeq = P1EnvCnt;
beaglescout007 0:3dac1f1bc9e0 451 }
beaglescout007 0:3dac1f1bc9e0 452 else
beaglescout007 0:3dac1f1bc9e0 453 {
beaglescout007 0:3dac1f1bc9e0 454 if (APU_Reg[0] & 0x20)
beaglescout007 0:3dac1f1bc9e0 455 {
beaglescout007 0:3dac1f1bc9e0 456 P1Vol = 15;
beaglescout007 0:3dac1f1bc9e0 457 P1EnvSeq = P1EnvCnt;
beaglescout007 0:3dac1f1bc9e0 458 }
beaglescout007 0:3dac1f1bc9e0 459 }
beaglescout007 0:3dac1f1bc9e0 460 }
beaglescout007 0:3dac1f1bc9e0 461 }
beaglescout007 0:3dac1f1bc9e0 462
beaglescout007 0:3dac1f1bc9e0 463 //====================
beaglescout007 0:3dac1f1bc9e0 464 // Pulse2 Envelope
beaglescout007 0:3dac1f1bc9e0 465 //====================
beaglescout007 0:3dac1f1bc9e0 466 if (!(APU_Reg[4] & 0x10) && P2EnvSeq > 0)
beaglescout007 0:3dac1f1bc9e0 467 {
beaglescout007 0:3dac1f1bc9e0 468 P2EnvSeq--;
beaglescout007 0:3dac1f1bc9e0 469 if (P2EnvSeq == 0)
beaglescout007 0:3dac1f1bc9e0 470 {
beaglescout007 0:3dac1f1bc9e0 471 if (P2Vol > 0)
beaglescout007 0:3dac1f1bc9e0 472 {
beaglescout007 0:3dac1f1bc9e0 473 --P2Vol;
beaglescout007 0:3dac1f1bc9e0 474 P2EnvSeq = P2EnvCnt;
beaglescout007 0:3dac1f1bc9e0 475 }
beaglescout007 0:3dac1f1bc9e0 476 else
beaglescout007 0:3dac1f1bc9e0 477 {
beaglescout007 0:3dac1f1bc9e0 478 if (APU_Reg[4] & 0x20)
beaglescout007 0:3dac1f1bc9e0 479 {
beaglescout007 0:3dac1f1bc9e0 480 P2Vol = 15;
beaglescout007 0:3dac1f1bc9e0 481 P2EnvSeq = P2EnvCnt;
beaglescout007 0:3dac1f1bc9e0 482 }
beaglescout007 0:3dac1f1bc9e0 483 }
beaglescout007 0:3dac1f1bc9e0 484 }
beaglescout007 0:3dac1f1bc9e0 485 }
beaglescout007 0:3dac1f1bc9e0 486
beaglescout007 0:3dac1f1bc9e0 487 //====================
beaglescout007 0:3dac1f1bc9e0 488 // Triangle Linear Counter
beaglescout007 0:3dac1f1bc9e0 489 //====================
beaglescout007 0:3dac1f1bc9e0 490 if (LinearCounterReloadFlag)
beaglescout007 0:3dac1f1bc9e0 491 {
beaglescout007 0:3dac1f1bc9e0 492 LinearCounter = APU_Reg[0x8] & 0x7f;
beaglescout007 0:3dac1f1bc9e0 493 }
beaglescout007 0:3dac1f1bc9e0 494 else if (LinearCounter > 0)
beaglescout007 0:3dac1f1bc9e0 495 {
beaglescout007 0:3dac1f1bc9e0 496 LinearCounter--;
beaglescout007 0:3dac1f1bc9e0 497 }
beaglescout007 0:3dac1f1bc9e0 498
beaglescout007 0:3dac1f1bc9e0 499 if (!(APU_Reg[0x8] & 0x80))
beaglescout007 0:3dac1f1bc9e0 500 {
beaglescout007 0:3dac1f1bc9e0 501 LinearCounterReloadFlag = false;
beaglescout007 0:3dac1f1bc9e0 502 }
beaglescout007 0:3dac1f1bc9e0 503
beaglescout007 0:3dac1f1bc9e0 504 //====================
beaglescout007 0:3dac1f1bc9e0 505 // Noise Envelope
beaglescout007 0:3dac1f1bc9e0 506 //====================
beaglescout007 0:3dac1f1bc9e0 507 if (!(APU_Reg[0xc] & 0x10) && NsEnvSeq > 0)
beaglescout007 0:3dac1f1bc9e0 508 {
beaglescout007 0:3dac1f1bc9e0 509 NsEnvSeq--;
beaglescout007 0:3dac1f1bc9e0 510 if (NsEnvSeq == 0)
beaglescout007 0:3dac1f1bc9e0 511 {
beaglescout007 0:3dac1f1bc9e0 512 if (NsVol > 0)
beaglescout007 0:3dac1f1bc9e0 513 {
beaglescout007 0:3dac1f1bc9e0 514 --NsVol;
beaglescout007 0:3dac1f1bc9e0 515 NsEnvSeq = NsEnvCnt;
beaglescout007 0:3dac1f1bc9e0 516 }
beaglescout007 0:3dac1f1bc9e0 517 else
beaglescout007 0:3dac1f1bc9e0 518 {
beaglescout007 0:3dac1f1bc9e0 519 if (APU_Reg[0xc] & 0x20)
beaglescout007 0:3dac1f1bc9e0 520 {
beaglescout007 0:3dac1f1bc9e0 521 NsVol = 15;
beaglescout007 0:3dac1f1bc9e0 522 NsEnvSeq = NsEnvCnt;
beaglescout007 0:3dac1f1bc9e0 523 }
beaglescout007 0:3dac1f1bc9e0 524 }
beaglescout007 0:3dac1f1bc9e0 525 }
beaglescout007 0:3dac1f1bc9e0 526 }
beaglescout007 0:3dac1f1bc9e0 527 }
beaglescout007 0:3dac1f1bc9e0 528
beaglescout007 0:3dac1f1bc9e0 529 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 530 /* 120Hz Clock */
beaglescout007 0:3dac1f1bc9e0 531 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 532 void pNesX_ApuClk_120Hz()
beaglescout007 0:3dac1f1bc9e0 533 {
beaglescout007 0:3dac1f1bc9e0 534 //====================
beaglescout007 0:3dac1f1bc9e0 535 // Pulse1 Sweep
beaglescout007 0:3dac1f1bc9e0 536 //====================
beaglescout007 0:3dac1f1bc9e0 537 if (P1SwReloadFlag)
beaglescout007 0:3dac1f1bc9e0 538 {
beaglescout007 0:3dac1f1bc9e0 539 P1Sweep = ((APU_Reg[1] & 0x70) >> 4) + 1;
beaglescout007 0:3dac1f1bc9e0 540 P1SwCnt = 0;
beaglescout007 0:3dac1f1bc9e0 541 P1SwReloadFlag = false;
beaglescout007 0:3dac1f1bc9e0 542 }
beaglescout007 0:3dac1f1bc9e0 543 else if (APU_Reg[1] & 0x80 && !P1SwOverflow)
beaglescout007 0:3dac1f1bc9e0 544 {
beaglescout007 0:3dac1f1bc9e0 545 P1SwCnt++;
beaglescout007 0:3dac1f1bc9e0 546 if (P1SwCnt == P1Sweep)
beaglescout007 0:3dac1f1bc9e0 547 {
beaglescout007 0:3dac1f1bc9e0 548 P1SwCnt = 0;
beaglescout007 0:3dac1f1bc9e0 549
beaglescout007 0:3dac1f1bc9e0 550 int sweep = P1Timer >> P1SwLevel;
beaglescout007 0:3dac1f1bc9e0 551 int value = P1Timer;
beaglescout007 0:3dac1f1bc9e0 552 if (APU_Reg[1] & 8)
beaglescout007 0:3dac1f1bc9e0 553 {
beaglescout007 0:3dac1f1bc9e0 554 value = value - sweep - 1;
beaglescout007 0:3dac1f1bc9e0 555 if (value < 8)
beaglescout007 0:3dac1f1bc9e0 556 {
beaglescout007 0:3dac1f1bc9e0 557 P1SwOverflow = true;
beaglescout007 0:3dac1f1bc9e0 558 return;
beaglescout007 0:3dac1f1bc9e0 559 }
beaglescout007 0:3dac1f1bc9e0 560 }
beaglescout007 0:3dac1f1bc9e0 561 else
beaglescout007 0:3dac1f1bc9e0 562 {
beaglescout007 0:3dac1f1bc9e0 563 value = value + sweep;
beaglescout007 0:3dac1f1bc9e0 564 if (value > 0x7ff)
beaglescout007 0:3dac1f1bc9e0 565 {
beaglescout007 0:3dac1f1bc9e0 566 P1SwOverflow = true;
beaglescout007 0:3dac1f1bc9e0 567 return;
beaglescout007 0:3dac1f1bc9e0 568 }
beaglescout007 0:3dac1f1bc9e0 569 }
beaglescout007 0:3dac1f1bc9e0 570 P1Timer = value;
beaglescout007 0:3dac1f1bc9e0 571
beaglescout007 0:3dac1f1bc9e0 572 APU_Reg[3] &= 7;
beaglescout007 0:3dac1f1bc9e0 573 APU_Reg[3] |= value >> 8;
beaglescout007 0:3dac1f1bc9e0 574 APU_Reg[2] = value & 0xff;
beaglescout007 0:3dac1f1bc9e0 575
beaglescout007 0:3dac1f1bc9e0 576 P1WaveLength = (value + 1) * 1000;
beaglescout007 0:3dac1f1bc9e0 577 P1WavePeriod = P1WaveLength * 8;
beaglescout007 0:3dac1f1bc9e0 578 }
beaglescout007 0:3dac1f1bc9e0 579 }
beaglescout007 0:3dac1f1bc9e0 580
beaglescout007 0:3dac1f1bc9e0 581 //====================
beaglescout007 0:3dac1f1bc9e0 582 // Pulse1 Sweep
beaglescout007 0:3dac1f1bc9e0 583 //====================
beaglescout007 0:3dac1f1bc9e0 584 if (P2SwReloadFlag)
beaglescout007 0:3dac1f1bc9e0 585 {
beaglescout007 0:3dac1f1bc9e0 586 P2Sweep = ((APU_Reg[5] & 0x70) >> 4) + 1;
beaglescout007 0:3dac1f1bc9e0 587 P2SwCnt = 0;
beaglescout007 0:3dac1f1bc9e0 588 P2SwReloadFlag = false;
beaglescout007 0:3dac1f1bc9e0 589 }
beaglescout007 0:3dac1f1bc9e0 590 else if (APU_Reg[5] & 0x80 && !P2SwOverflow)
beaglescout007 0:3dac1f1bc9e0 591 {
beaglescout007 0:3dac1f1bc9e0 592 P2SwCnt++;
beaglescout007 0:3dac1f1bc9e0 593 if (P2SwCnt == P2Sweep)
beaglescout007 0:3dac1f1bc9e0 594 {
beaglescout007 0:3dac1f1bc9e0 595 P2SwCnt = 0;
beaglescout007 0:3dac1f1bc9e0 596
beaglescout007 0:3dac1f1bc9e0 597 int sweep = P2Timer >> P2SwLevel;
beaglescout007 0:3dac1f1bc9e0 598 int value = P2Timer;
beaglescout007 0:3dac1f1bc9e0 599 if (APU_Reg[5] & 8)
beaglescout007 0:3dac1f1bc9e0 600 {
beaglescout007 0:3dac1f1bc9e0 601 value = value - sweep;
beaglescout007 0:3dac1f1bc9e0 602 if (value < 8)
beaglescout007 0:3dac1f1bc9e0 603 {
beaglescout007 0:3dac1f1bc9e0 604 P2SwOverflow = true;
beaglescout007 0:3dac1f1bc9e0 605 return;
beaglescout007 0:3dac1f1bc9e0 606 }
beaglescout007 0:3dac1f1bc9e0 607 }
beaglescout007 0:3dac1f1bc9e0 608 else
beaglescout007 0:3dac1f1bc9e0 609 {
beaglescout007 0:3dac1f1bc9e0 610 value = value + sweep;
beaglescout007 0:3dac1f1bc9e0 611 if (value > 0x7ff)
beaglescout007 0:3dac1f1bc9e0 612 {
beaglescout007 0:3dac1f1bc9e0 613 P2SwOverflow = true;
beaglescout007 0:3dac1f1bc9e0 614 return;
beaglescout007 0:3dac1f1bc9e0 615 }
beaglescout007 0:3dac1f1bc9e0 616 }
beaglescout007 0:3dac1f1bc9e0 617
beaglescout007 0:3dac1f1bc9e0 618 P2Timer = value;
beaglescout007 0:3dac1f1bc9e0 619
beaglescout007 0:3dac1f1bc9e0 620 APU_Reg[7] &= 7;
beaglescout007 0:3dac1f1bc9e0 621 APU_Reg[7] |= value >> 8;
beaglescout007 0:3dac1f1bc9e0 622 APU_Reg[6] = value & 0xff;
beaglescout007 0:3dac1f1bc9e0 623
beaglescout007 0:3dac1f1bc9e0 624 P2WaveLength = (value + 1) * 1000;
beaglescout007 0:3dac1f1bc9e0 625 P2WavePeriod = P2WaveLength * 8;
beaglescout007 0:3dac1f1bc9e0 626
beaglescout007 0:3dac1f1bc9e0 627 }
beaglescout007 0:3dac1f1bc9e0 628 }
beaglescout007 0:3dac1f1bc9e0 629 }
beaglescout007 0:3dac1f1bc9e0 630
beaglescout007 0:3dac1f1bc9e0 631 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 632 /* 60Hz Clock */
beaglescout007 0:3dac1f1bc9e0 633 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 634 void pNesX_ApuClk_60Hz()
beaglescout007 0:3dac1f1bc9e0 635 {
beaglescout007 0:3dac1f1bc9e0 636 // Pulse1
beaglescout007 0:3dac1f1bc9e0 637 if (!(APU_Reg[0] & 0x20) && P1LengthCounter > 0)
beaglescout007 0:3dac1f1bc9e0 638 {
beaglescout007 0:3dac1f1bc9e0 639 P1LengthCounter--;
beaglescout007 0:3dac1f1bc9e0 640 }
beaglescout007 0:3dac1f1bc9e0 641
beaglescout007 0:3dac1f1bc9e0 642 // Pulse2
beaglescout007 0:3dac1f1bc9e0 643 if (!(APU_Reg[4] & 0x20) && P2LengthCounter > 0)
beaglescout007 0:3dac1f1bc9e0 644 {
beaglescout007 0:3dac1f1bc9e0 645 P2LengthCounter--;
beaglescout007 0:3dac1f1bc9e0 646 }
beaglescout007 0:3dac1f1bc9e0 647
beaglescout007 0:3dac1f1bc9e0 648 // Triangle
beaglescout007 0:3dac1f1bc9e0 649 if (!(APU_Reg[0x8] & 0x80) && TrLengthCounter > 0)
beaglescout007 0:3dac1f1bc9e0 650 {
beaglescout007 0:3dac1f1bc9e0 651 TrLengthCounter--;
beaglescout007 0:3dac1f1bc9e0 652 }
beaglescout007 0:3dac1f1bc9e0 653
beaglescout007 0:3dac1f1bc9e0 654 // Noise
beaglescout007 0:3dac1f1bc9e0 655 if (!(APU_Reg[0xc] & 0x20) && NsLengthCounter > 0)
beaglescout007 0:3dac1f1bc9e0 656 {
beaglescout007 0:3dac1f1bc9e0 657 NsLengthCounter--;
beaglescout007 0:3dac1f1bc9e0 658 }
beaglescout007 0:3dac1f1bc9e0 659
beaglescout007 0:3dac1f1bc9e0 660 }
beaglescout007 0:3dac1f1bc9e0 661
beaglescout007 0:3dac1f1bc9e0 662 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 663 /* Status */
beaglescout007 0:3dac1f1bc9e0 664 /*-------------------------------------------------------------------*/
beaglescout007 0:3dac1f1bc9e0 665 BYTE ApuRead( WORD wAddr )
beaglescout007 0:3dac1f1bc9e0 666 {
beaglescout007 0:3dac1f1bc9e0 667 if (wAddr == 0x15)
beaglescout007 0:3dac1f1bc9e0 668 {
beaglescout007 0:3dac1f1bc9e0 669 return (P1LengthCounter > 0) | (P2LengthCounter > 0) << 1 | (TrLengthCounter > 0) << 2 | (NsLengthCounter > 0) << 3;
beaglescout007 0:3dac1f1bc9e0 670 }
beaglescout007 0:3dac1f1bc9e0 671
beaglescout007 0:3dac1f1bc9e0 672 return APU_Reg[ wAddr ];
beaglescout007 0:3dac1f1bc9e0 673 }
beaglescout007 0:3dac1f1bc9e0 674