Using a 2A03 by itself + programming

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

If you're only making a music engine, I'd bet a 6502 C compiler would be fast enough.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
skrasms
Posts: 45
Joined: Mon Jan 14, 2008 7:20 pm
Location: Portland, OR

Post by skrasms »

Dwedit wrote:If you're only making a music engine, I'd bet a 6502 C compiler would be fast enough.
The problem is that it's not only a music engine; it's made to interface with CV signals on a modular synthesizer, in addition to reading rotary encoders. For example, synth modules use a standard pitch control format of +1V = +1 octave. So I need to sample an analog voltage and scale the digital result to be base 2 logarithmic before it can set the pitch of an NES channel. I would not know where to begin doing that math in assembly, but I can write it out quickly in C :)

Sorry I have been quiet for a while. I put the NES project on a little break while I worked on an Atari synth module. A lot of the microcontroller code will be the same for both. The Atari synth is almost done except for a single algorithm speed problem.

Speaking of which, is there a fast method to calculate 2 to a rational power? The C pow(2, x) compiled on my micro takes almost a full millisecond to execute! I wrote my own function that's accurate to 0.06% using a mix of math and small lookup tables, but it still takes around 200 micro seconds. I hope asking about such is not going too far off topic on this forum.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

skrasms wrote:The problem is that it's not only a music engine; it's made to interface with CV signals on a modular synthesizer, in addition to reading rotary encoders. For example, synth modules use a standard pitch control format of +1V = +1 octave.
Or 1/1200 V per cent of pitch.
So I need to sample an analog voltage and scale the digital result to be base 2 logarithmic before it can set the pitch of an NES channel. I would not know where to begin doing that math in assembly
Lookup tables. Lots of lookup tables.
skrasms
Posts: 45
Joined: Mon Jan 14, 2008 7:20 pm
Location: Portland, OR

Post by skrasms »

tepples wrote:
skrasms wrote:So I need to sample an analog voltage and scale the digital result to be base 2 logarithmic before it can set the pitch of an NES channel. I would not know where to begin doing that math in assembly
Lookup tables. Lots of lookup tables.
I wanted to make a lookup table that covered all 12 bits, but I cannot really fit more than a couple hundred values into the micro's RAM. Right now my code is based on table lookups and somewhat simple math. It takes the exponent and breaks it into individual digits, then uses lookup tables to get 2 to that digit.

For example, 2^3.124
= (2^3)*(2^0.1)*(2^0.02)*(2^0.004)
= two1[3] * two01[1] * two001[2] * two0001[4]

Code: Select all

double two1[] = {1.000000000000000, 2.000000000000000, 4.000000000000000, 8.000000000000000, 16.000000000000000, 32.000000000000000, 64.000000000000000, 128.000000000000000, 256.000000000000000, 512.000000000000000};
double two01[] = {1.000000000000000, 1.071773462536293, 1.148698354997035, 1.231144413344916, 1.319507910772894, 1.414213562373095, 1.515716566510398, 1.624504792712471, 1.741101126592248, 1.866065983073615};
double two001[] = {1.000000000000000, 1.006955550056719, 1.013959479790029, 1.021012125707193, 1.028113826656067, 1.035264923841378, 1.042465760841121, 1.049716683623067, 1.057018040561380, 1.064370182453360};
double two0001[] = {1.000000000000000, 1.000693387462581, 1.001387255711335, 1.002081605079633, 1.002776435901078, 1.003471748509503, 1.004167543238973, 1.004863820423785, 1.005560580398468, 1.006257823497782};
double two00001[] = {1.000000000000000, 1.000069317120377, 1.000138639045616, 1.000207965776052, 1.000277297312018, 1.000346633653845, 1.000415974801869, 1.000485320756421, 1.000554671517834, 1.000624027086444};

double mypow(double val);

double mypow(double val)
{
  unsigned dig[5];
  double old = val;
  if(val<0) val = -val;

  dig[0] = (unsigned)val;
  dig[1] = ((unsigned)(val*10))%10;
  dig[2] = ((unsigned)(val*100))%10;
  dig[3] = ((unsigned)(val*1000))%10;
  dig[4] = ((unsigned)(val*10000))%10;
  if(old<0) return(1 / two1[dig[0]] / two01[dig[1]] / two001[dig[2]] / two0001[dig[3]] / two00001[dig[4]]);
  else return(two1[dig[0]] * two01[dig[1]] * two001[dig[2]] * two0001[dig[3]] * two00001[dig[4]]);
}
The debugger shows that extracting digits from the input the way I am doing it takes 25+ usec per digit, though, so that's a bit of a bottleneck.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

skrasms wrote:I wanted to make a lookup table that covered all 12 bits, but I cannot really fit more than a couple hundred values into the micro's RAM. Right now my code is based on table lookups and somewhat simple math. It takes the exponent and breaks it into individual digits, then uses lookup tables to get 2 to that digit.
I noticed that your code extracts the decimal digits. Try extracting hexadecimal digits instead; division by 16 is usually much faster than division by 10 on cheap processors. In addition, double is slower than a fixed-point data type unless your processor has specific circuitry (called an FPU) for handling doubles.
skrasms
Posts: 45
Joined: Mon Jan 14, 2008 7:20 pm
Location: Portland, OR

Post by skrasms »

I had to take a break from this project because of school and graduation, but I'm back on it now :)

Now that I can write registers, I am able to get sound out from the Triangle, Noise, and DMC channels. I tried this order for using the triangle channel:

Write 0x7F to $4008
Write 0x11 to $400A
Write 0x30 to $400B

Any time I write to $400A the triangle channel goes silent. Is that supposed to happen? Writing to $400B brings it back at the updated frequency.

In the same way, after I write to $400E the noise channel goes silent. It comes back when I write any arbitrary data to $400F.

So this process works:

Write 0x1F to 0x400C
Write 0x88 to 0x400E
Write 0xXX (any value) to 0x400F

But this process does not:

Write 0x1F to 0x400C
Write 0x88 to 0x400E

Is that normal behavior?
skrasms
Posts: 45
Joined: Mon Jan 14, 2008 7:20 pm
Location: Portland, OR

Post by skrasms »

Oops, it looks like my writing process was also writing some garbage data between iterations. It seems to be working now :)
Post Reply