SNES SDK

12. January 2013 20:21 by Cameron in   //  Tags: , , , ,   //   Comments

Over the past few days, I have been playing around with the SNES SDK that compiles C code to SNES ROMs for running in emulators or on real hardware. The SDK supports floating point emulation, 16-bit integers, controller input, and a basic graphics system. There is no sound support in the SDK for the SPC of the SNES (yet). Libraries can be added to the SDK pretty easily by writing C code and compiling to assembly to be linked with other programs.

In playing with the SNES SDK, I noticed that in math.h, a lot of the ANSI C math functions were left out due to hardware limitations of the SNES. However, without much effort, I was able to create working functions for the six basic trig functions and a square root function.

In mathematics, sine and cosine can be approximated by Taylor polynomial expansions. This makes it easy to implement functions in C to compute the sine and cosine of a value to a certain degree of precision. The following is the Taylor expansion functions for sine and cosine:

// taylor series expansion of the sin function
float sin(float x)
{
return x - (mult(x,  3) / fact(3)) + (mult(x, 5) / fact(5)) - (mult(x, 7) / fact(7))+ (mult(x, 9) / fact(9)) - (mult(x, 11) / fact(11)) + (mult(x, 13) / fact(13));
}

// taylor series expansion of the cos function
float cos(float x)
{
return 1 - (mult(x,  2) / fact(2)) + (mult(x, 4) / fact(4)) - (mult(x, 6) / fact(6)) + (mult(x, 8) / fact(8)) - (mult(x, 10) / fact(10)) + (mult(x, 12) / fact(12));
}

I had to create helper functions for x^n and x! (x factorial) since those aren't built into the compiler. The function, mult(x, n), raises x to the power n. The function, fact(x), computes the factorial of x. There is a pow(x, n) function implemented in the SDK, but it doesn't produce as accurate of results as my mult(x, n) function. The result can be seen when running pow(2, 12) versus mult(2, 12). The pow function returns 4095 while mult returns 4096 (the correct result).

The other trig functions were built on the sin and cos functions. There is a Taylor expansion for tan(x), but I decided to go with sin(x)/cos(x) since I couldn't properly expand tan(x) for enough accuracy. Below is the rest of the trig functions:

float tan(float x)
{
return sin(x) / cos(x);
}

float sec(float x)
{
return 1 / cos(x);
}

float csc(float x)
{
return 1 / sin(x);
}

float cot(float x)
{
return 1 / tan(x);
}

I understand the practicality of computing trig values on the SNES might not be huge for everyday use. However, this was more of a "Can I do this?" type of exercise. Games like Starfox for the SNES may have used trig calculations on the Super FX co-processor, but I doubt many games needed cosine or sine functions calculated on the main CPU. Perhaps game demos with oscillating text used sine or cosine as a function of time.

The square root function is based on Newton's method. I found the code for this method here: http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi

// babylonian method for square roots
float sqrt(int n)
{
// double a = (eventually the main method will plug values into a)
float a = (float) n;
float x = 1;
int i;

// For loop to get the square root value of the entered number.
for( i = 0; i < n; i++)
{
x = 0.5 * ( x+a / x );
}

return x;
}

double newton_sqrt(double n)
{
double x = 0.0;
double xn = 0.0;
int iters = 0;
int i;
for (i = 0; i <= (int)n; ++i)
{
double val = i*i-n;
if (val == 0.0)
return i;
if (val > 0.0)
{
xn = (i+(i-1))/2.0;
break;
}
}
while (!(iters++ >= 100 || x == xn))
{
x = xn;
xn = x - (x * x - n) / (2 * x);
}

return xn;
}

There are tons of different ways to compute an approximation to the square root, but I was more concerned with precision vs. speed.

Here's the code I used including the SNES SDK:

snessdk.zip (1.27 mb)

Here is where I found the SNES SDK Win32 binary:

http://forums.nesdev.com/viewtopic.php?f=12&t=6253

You will need Windows XP or higher for the SDK. The source for the SDK may be found here: http://code.google.com/p/snes-sdk/source/checkout

Here's a screenshot of my test program running in ZSNESW: 