/* ** All my chip simulator noobits. But remember this is just me screwing around. */ #include #include #include namespace ChipSym { class CPUStepper { private: int sampleRateInHz; double chipFrequencyInMHZ; unsigned int ticksPerSample; double tickFractionPerSample; double accruedTickFraction; public: CPUStepper( unsigned int _sampleRateInHz, double _chipFrequencyInMHZ ) : sampleRateInHz( _sampleRateInHz ), chipFrequencyInMHZ( _chipFrequencyInMHZ ), accruedTickFraction( 0 ) { double tpsD = chipFrequencyInMHZ * 1000000 / sampleRateInHz; double tpsdi; tickFractionPerSample = modf( tpsD, &tpsdi ); ticksPerSample = (unsigned int)tpsdi; } /* ** Take one step and tell me how many CPU ticks I would have seen if I am sampling at sampleRate. ** This won't be a constant of course since sometimes we get an extra to catch up */ unsigned int nextStepCPUTicks() { accruedTickFraction += tickFractionPerSample; if( accruedTickFraction > 1 ) { accruedTickFraction -= 1; return ticksPerSample + 1; } return ticksPerSample; } }; static double NESNTSCCPURate = 1.789773; class NESBase { protected: int digWavelength; // this is the 2^11 which sets frequency time int t, currPos; float wfMin, wfMax, wfMinToMax; public: NESBase( float imin, float imax ) : wfMin( imin ), wfMax( imax ) { digWavelength = 1 << 7; // Callibrate this later t = digWavelength; currPos = 0; wfMinToMax = wfMax - wfMin; } void setDigWavelength( int df ) // 0 -> 2^11 { digWavelength = df; } }; class NESTriangle : public NESBase // http://wiki.nesdev.com/w/index.php/APU_Triangle { protected: float waveForm[ 32 ]; CPUStepper cpu; public: NESTriangle( float imin, float imax, unsigned int sampleRate ) : NESBase( imin, imax ), cpu( sampleRate, NESNTSCCPURate ) { for( int i=0; i<16; ++i ) { waveForm[ 15 - i ] = i / 15.0f; waveForm[ 16 + i ] = i / 15.0f; } } float step() { int ticks = cpu.nextStepCPUTicks(); t -= ticks; if( t < 0 ) { currPos ++; t += digWavelength; if( currPos >= 32 ) currPos = 0; } return waveForm[ currPos ] * wfMinToMax + wfMin; } void setWavelengthInSeconds( float seconds ) { setDigWavelength( (unsigned int)( seconds * NESNTSCCPURate * 1000 * 1000 / 32 ) ); } }; class NESArbitraryWaveform : public NESTriangle { public: NESArbitraryWaveform( float imin, float imax, unsigned int sampleRate ) : NESTriangle( imin, imax, sampleRate ) { } void setWaveformPoint( unsigned int pos, // 0->31 unsigned int val ) // 0->15 { waveForm[ pos ] = val / 15.0f; } unsigned int getWaveformPoint( unsigned int pos ) { return waveForm[ pos ] * 15.0f; } }; class NESPulse : public NESBase // http://wiki.nesdev.com/w/index.php/APU_Pulse { private: int dutyCycle; float **waveForms; int nDutyCycles; int wfLength; CPUStepper cpu; public: NESPulse( float imin, float imax, int sampleRate ) : NESBase( imin, imax ), cpu( sampleRate, NESNTSCCPURate / 2 ) { wfLength = 8; nDutyCycles = 4; dutyCycle = 1; waveForms = new float*[ 4 ]; for( int i=0; i= wfLength ) currPos = 0; } return waveForms[ dutyCycle ][ currPos ] * wfMinToMax + wfMin; } }; class NESNoise : public NESBase { public: typedef enum ShortPeriods { SHORT_31, SHORT_93 } ShortPeriods; private: CPUStepper cpu; unsigned short shiftRegister; unsigned short currentOutput; unsigned short xorBit; unsigned short curr93key; std::vector< unsigned short > starts_for_93s; ShortPeriods currShortPeriods; public: NESNoise( float imin, float imax, int sampleRate ) : NESBase( imin, imax ), cpu( sampleRate, NESNTSCCPURate / 2 ) { setPeriod( 8 ); shiftRegister = 0x07; currentOutput = shiftRegister & 1; xorBit = 1; curr93key = 17; init93(); currShortPeriods = SHORT_93; } void init93() { // To generate this, see ../standalone/chipNoisePeriod.cpp unsigned short calc_start_for_93s[] = { 1, 3, 5, 7, 11, 13, 15, 17, 19, 21, 23, 25, 29, 31, 33, 35, 37, 39, 41, 43, 47, 49, 51, 53, 55, 57, 59, 61, 66, 68, 70, 74, 76, 78, 80, 84, 86, 88, 90, 92, 94, 96, 98, 102, 104, 106, 108, 110, 112, 114, 116, 120, 122, 124, 126, 129, 131, 133, 135, 139, 141, 143, 145, 147, 149, 151, 153, 157, 159, 161, 163, 165, 167, 169, 171, 175, 177, 179, 181, 183, 185, 187, 189, 194, 196, 198, 200, 202, 204, 206, 208, 212, 214, 218, 220, 222, 224, 226, 230, 232, 234, 236, 238, 240, 242, 244, 248, 250, 252, 254, 259, 263, 267, 271, 273, 275, 277, 279, 281, 285, 287, 291, 295, 299, 303, 305, 307, 309, 311, 313, 315, 317, 322, 326, 330, 334, 336, 340, 342, 344, 346, 348, 350, 354, 358, 362, 366, 368, 370, 372, 376, 378, 380, 382, 387, 389, 395, 397, 399, 401, 403, 405, 407, 409, 413, 415, 417, 419, 421, 423, 425, 427, 431, 435, 437, 443, 445, 450, 452, 454, 456, 458, 460, 464, 468, 470, 472, 474, 478, 482, 486, 488, 490, 492, 494, 498, 500, 506, 535, 543, 547, 551, 555, 559, 563, 565, 571, 573, 598, 606, 610, 614, 618, 622, 626, 628, 634, 636, 645, 647, 653, 655, 661, 663, 669, 671, 673, 677, 679, 681, 687, 689, 691, 693, 699, 701, 710, 716, 718, 724, 726, 732, 734, 742, 744, 750, 752, 756, 760, 762, 764, 775, 779, 785, 787, 789, 793, 797, 799, 803, 811, 815, 819, 821, 823, 827, 829, 834, 838, 842, 852, 858, 860, 862, 870, 874, 880, 882, 884, 888, 892, 894, 901, 907, 913, 915, 919, 927, 931, 933, 935, 947, 962, 970, 982, 988, 990, 994, 1000, 1004, 1012, 1018, 1057, 1059, 1061, 1063, 1065, 1067, 1075, 1077, 1079, 1081, 1083, 1100, 1110, 1116, 1130, 1132, 1134, 1138, 1144, 1185, 1187, 1189, 1191, 1195, 1201, 1209, 1211, 1228, 1238, 1244, 1264, 1274, 1293, 1311, 1313, 1335, 1354, 1392, 1415, 1419, 1425, 1455, 1467, 1510, 1524, 1569, 1620, 1638, 1671, 1868, 0 }; unsigned short* curr = calc_start_for_93s; while( *curr != 0 ) { starts_for_93s.push_back( *curr ); ++curr; } } void set93Key( int sp ) { if( sp != curr93key ) { setRegister( starts_for_93s[ sp ] ); } curr93key = sp; } void setModeFlag( bool mf ) { if( mf ) { xorBit = 6; // set register based on cached shortlen setShortLength( currShortPeriods ); } else xorBit = 1; } void setShortLength( ShortPeriods p ) { currShortPeriods = p; if( p == SHORT_31 ) { setRegister( 0x0737 ); } else { // A little state so we don't always land on the same one setRegister( starts_for_93s[ curr93key ] ); } } void setPeriod( unsigned int c ) // 0 - 15 { if( c > 15 ) c = 8; switch( c ) { case 0: digWavelength = 4; break; case 1: digWavelength = 8; break; case 2: digWavelength = 16; break; case 3: digWavelength = 32; break; case 4: digWavelength = 64; break; case 5: digWavelength = 96; break; case 6: digWavelength = 128; break; case 7: digWavelength = 160; break; case 8: digWavelength = 202; break; case 9: digWavelength = 254; break; case 10: digWavelength = 380; break; case 11: digWavelength = 508; break; case 12: digWavelength = 762; break; case 13: digWavelength = 1016; break; case 14: digWavelength = 2034; break; case 15: digWavelength = 4068; break; } } void advanceRegister() { // Do the LFSR Shift unsigned short bit = ((shiftRegister >> 0) ^ (shiftRegister >> xorBit)) & 1; shiftRegister = (shiftRegister >> 1) | (bit << 14); // thanks https://github.com/baconpaul/BaconPlugs/issues/6 } float step() { int ticks = cpu.nextStepCPUTicks(); t -= ticks; if( t < 0 ) { t += digWavelength; advanceRegister(); currentOutput = shiftRegister & 1; } return currentOutput * wfMinToMax + wfMin; } void setRegister( unsigned short r ) { shiftRegister = r; } unsigned short getRegister() { return shiftRegister; } }; #if 0 class LFSRGeneralImpl { public: typedef std::bitset< 24 > bits; private: public: void setActivetBits( size_t aBits ) // < 24 please { } void setTapsAsInt( unsigned int taps ) // so 1 << 16 & 1 << 14 & 1 << 7 type thing { } }; #endif };