Getting started with N64 development? by breadcrust at 7:26 PM EDT on June 5, 2005
hello all, i stumbled onto this site while checking websites of users online at ZMD. :-)

Anyway, Ive been interested in developing some stuff for N64 for a while now, and found Neon64 here, decided that seems pretty cool, so you guys must [hopefully] know what your doing(? ^^)

So, where should I get started with this? What software is available (prefably that works on Linux). What hardware should I try and get? I've had a quick look at Dextrose and some other sites, but I'd like to hear it from you guys.

My programming skills: lots of experience with Tcl (and *shivers*, BASIC), a little bit with C and PHP. (Also XHTML/CSS/Javascript, but that doesnt count).
My hardware: A PAL N64, which I may or may not overclock soon. A couple of computers ;-) (Hopefully a Passport III soon too).

Thanks for any help.
by hcs at 7:20 AM EDT on June 6, 2005
All the real development I've ever done for the N64 has been in assembly. I've never gotten any of the free compilers to work to my satisfaction. While I haven't used anything but my own assembler for a while, I first learned N64 programming by studying and modifying CZN's trainer intros. (Here and here
are some you can make without any effort, just type "make" at a DOS prompt. It was with these in mind that I built my own assembler's demo which will work right out of the box.
I learned how to use the RSP by examining Destop's Heavy64 source and disassembling the ucode it came with. My assembler's demo includes code that runs on the RSP so you can look through them if that interests you.
I am certain that you can use a GNU MIPS assembler to build N64 ROMs, all you need to do is affix the proper headers and calculate the checksum (my favorite is Checksum 64 which includes source). If you use the header file contained in the aforementioned CZN demos set your origin to 0x80000400 and simply concatenate your code onto the header, then compute the checksum (assuming you have less than 0x100000 bytes of code+data, otherwise you'll have to manually DMA stuff out of ROM, the header will only load the first 0x100000 bytes).
The thing to know is how to use all the hardware registers to get your way. If you're feeling ambitious check out my sources for Neon64, as I use just about everything (VI, AI, ROM and controller (both joystick and controller pack) RSP, RDP (to some extent)) more or less correctly. Or you could look through this collection. N64OPS#H.TXT gives a full breakdown of the registers, and the opcode lists are what I used to write my assembler (before I finally went and bought the MIPS R4000 user manual).

If you want to do development in a higher level language such as C you probably can, I just don't know myself how to configure compilers to generate chunks of code as are needed. Most real N64 development was done in C using GCC or SN Systems' compiler, to my knowledge. You might want to write your own libraries for hardware access (it's fun!) or you could try to use the official libraries if you can find them (which a good many "public domain" demos do, shame on them).

Good luck and feel free to ask for further clarification or help.
by hcs at 7:26 AM EDT on June 6, 2005
Ha, only made one important mistake, the first link should be:

my assembler (N64 Development Starter Kit)
by breadcrust at 12:21 AM EDT on June 7, 2005
thanks for the help.

i think ill look into a GNU MIPS assembler, and then into compling with GCC for N64.

I'm very much a high level language person, and have barely touched any asm, so I'm not too sure what I'll be like there, I'll just have to try it out and see. (its not that i havent tryed low[ish] level languages, i just prefer the flexibility of scripting languages)

i also need some hardware to transfer the rom from my PC to the N64. theres nothing i could use on ebay.com.au. the only place i found backup units in australia is at http://www.blade.cc/. anyway, what would you recommend i try and get?
by hcs at 3:30 AM EDT on June 7, 2005
If you want to go through a lot of trouble you can try loading programs with a Game Shark via the method I pioneered, but it makes the testing cycle so much longer that I feel it isn't worth it. I'd be glad to give you some direction if you want to give it a try, though, as I've wanted to make this a valid alternative for a while. I need to get back to work on my GSCC2k replacement...
Personally I use a 512 mbit Dr V64 Jr. I bought it because I wanted the flexibility of being able to play absolutely any game, not because of its convenience for development, though it has served me very well over the past fiveish years. I bought it from someone I found on gametz.com.
Check out Nintendo 64 Tech for info on various devices for guidance; I can't give you anything from first-hand experience. Your best bet is to get one used, and the Dextrose forums are probably the best place for that.
eBay is useless for backup units, they remove the listings for them as soon as they can find them. Before my current v64jr I bought a 256 mbit version from eBay and it broke within a week.

If you do want to learn assembly MIPS is a good choice, as it is RISC and thus has few instructions to learn.
by hcs at 7:28 PM EDT on June 10, 2005
I'm having some luck with GCC and binutils, though building a MIPS cross compiler has proven to be a pain (I've had to refer to three different web sites on the subject to get all the info I needed). When I'm confident this is working well I'll post instructions and my makefile.
by hcs at 2:14 PM EDT on June 11, 2005
Whew, I was about to complain about how inefficient GCC generates code compared to my hand-written assembly (which I thought was odd because I'd heard a lot about how efficient MIPS compilers are), but then I remembered to throw in the -O2 flag. Now completely readable C code is as good as what I've written, without the need to write loops in freaky ways and explicitly make every variable a register.

If you've never witnessed it before (as I haven't) it's a thing to behold. Consider this simple function:

void fillscreen1(unsigned short int color) {
unsigned int c;
for (c=0; c < sizeof(scrbuffer)/2; c++) scrbuffer[c]=color;
}

without optimization it comes out as:
fillscreen1:
addiu $sp, -0x10
sw $fp, 0x10+var_8($sp)
daddu $fp, $sp, $0
daddu $v0, $a0, $0
sh $v0, 0x10+var_10($fp)
sw $0, 0x10+var_C($fp)
loc_144:
lw $v0, 0x10+var_C($fp)
li $v1, 0x257FF
sltu $v0, $v1, $v0
beqz $v0, loc_164
nop
j loc_194
nop
loc_164:
lw $v0, 0x10+var_C($fp)
daddu $v1, $v0, $0
sll $v0, $v1, 1
la $v1, scrbuffer
addu $v0, $v1, $v0
lhu $v1, 0x10+var_10($fp)
sh $v1, 0($v0)
lw $v0, 0x10+var_C($fp)
addiu $v1, $v0, 1
j loc_144
sw $v1, 0x10+var_C($fp)
loc_194:
daddu $sp, $fp, $0
lw $fp, 0x10+var_8($sp)
jr $ra
addiu $sp, 0x10

eww... with -02, however, it becomes:

fillscreen1:
andi $a0, 0xFFFF
daddu $a2, $0, $0
li $v1, 0x257FF
la $a1, scrbuffer
loc_CC:
sh $a0, 0($a1)
addiu $a2, 1
sltu $v0, $v1, $a2
beqz $v0, loc_CC
addiu $a1, 2
jr $ra
nop

The only way I could think of making this better (other than writing in units bigger than halfwords) is to reverse the order of the loop so it ends when the counter == zero, that way you could save the sltu instruction.
Cool stuff. And it's all running nicely on the N64. I'm going to work on writing some basic libraries, hopefully something more useful than my assembler's demos or g0dev (which is a very similar project that never achieved it's potential) will come out of this. Unlike g0dev I'm only using the GNU tools (with the exception of chksum64, which is open source in portable C) so this can all be used on any GNU system (cygwin for me at the moment).
by hcs at 2:30 PM EDT on June 11, 2005
tab test:

fillscreen1:
    andi $a0, 0xFFFF
    daddu $a2, $0, $0
    li $v1, 0x257FF
    la $a1, scrbuffer
loc_CC:
    sh $a0, 0($a1)
    addiu $a2, 1
    sltu $v0, $v1, $a2
    beqz $v0, loc_CC
    addiu $a1, 2
    jr $ra
    nop
by hcs at 2:32 PM EDT on June 11, 2005
Ha!
HCS Forum: now featuring working indentation.

moo
    mooo
        moooo
            moooooooooo

If you can figure out how to enter a tab character in your browser :)
by hcs at 4:15 PM EDT on June 11, 2005
A word of warning regarding the GNU MIPS binutils:
type in elf32-mips.c.
I don't know what version this persists until but it was present in mine which is well after the date on this post.
by hcs at 4:16 PM EDT on June 11, 2005
And by type I meant typo.
Ironic.
by hcs at 8:48 PM EDT on June 11, 2005
I should have known something was wrong when everything seemed to be going so well.

For the record, nothing is ever easy.
by DeadAwake at 9:07 PM EDT on June 11, 2005
> eww...

Heh. Two nop's.

Good luck with the library. If it turns out, I would like to use it some day.

    (This tab is brought to you by the letters H, C, and S.)
by hcs at 9:53 PM EDT on June 12, 2005
OK, got the linker script sorted out (g0dev's wasn't 100% perfect for what I'm doing) and things seem, once again, to be working well. I'm now working on building newlib.
by hcs at 9:16 PM EDT on June 13, 2005
Most of newlib is up and running, thanks to a friend who got it on broadband and converted it from gzip to 7zip (a savings of about 4 MB IIRC). I still have to handle some syscall things but I have a nice demo running with sines and square roots.
I rebuilt the whole toolchain (several times) for a mips64vr4300 target.
Actually the target was just mips64, gcc won't build with mips64vr4300 though newlib and the binutils will, so I manually specify the CPU as vr4300 (though it probably isn't worth the trouble). It's nice to see all 64 bits in use.
by hcs at 9:34 PM EDT on June 13, 2005
Why must sprintf require any syscalls at all?
by hcs at 11:49 PM EDT on June 13, 2005
And don't try to explain it to me, I've been through the source so I know.
by hcs at 12:20 AM EDT on June 14, 2005
What code I have is now up:
n64test5.zip

My configure parameters:
../binutils-2.16/configure --target=mips64 --with-cpu=mips64vr4300

../gcc-3.3.6/configure --target=mips64 --with-cpu=mip64vr4300 --disable-threads --with-newlib

../newlib-1.13.0/configure --target=mips64 --with-cpu=mips64vr4300 --prefix=/usr/local --disable-multilib --disable-threads

I'm not sure if the --with-cpu in binutils and newlib actually does anything, ditto for --disable-threads.

The demo draws a moving sine wave, prints text, and scales the screen, all through my VI lib and newlib. I haven't been able to get it working in an emulator but it works great on the hardware.
This is still very much in development, I'd just like to see if someone can follow my path so far...
by hcs at 12:23 AM EDT on June 14, 2005
One more thing: there seems to be a problem wherein the console doesn't reset more often than not and I have to cycle the power. I haven't looked into exception handlers yet, or it may be a hardware problem, I don't know.
Good night.
by hcs at 11:11 PM EDT on June 14, 2005
More suckage: I have nice controller access functions written but they don't seem to work consistently and the thing crashes a lot.
by hcs at 9:21 PM EDT on June 15, 2005
Found the source of the unreliability (apparently I didn't understand structs as well as I thought) but the crashes still perplex me.
I have the problem down to cause and effect: if I don't fill the frame buffer before I call my controller reading function (in a continuous loop so it updates) the program eventually crashes. This makes no sense to me, however, as all the frame buffer filling function does it write a bunch of data, uncached, directly to RAM. If it was cached writes there might be something to it, like maybe something gets written back when the cache is full, but there isn't any uncache to speak of to write back... it's really got me up a wall.
by hcs at 11:39 PM EDT on June 15, 2005
New version up, now with a build script that pratically runs itself.
Basic controller reading support joins video support. The demo displays controller status (plugged in or not, x and y axis, buttons) and some profiling info I pull from the COP0 count register.
The sine wave is controlled by the controller 1 joystick. Pressing start on controller 1 makes the background red.

Be advised I haven't found the cause of the bug which causes controller_Read() to crash when it is called before VI_FillScreen(), so if you want to write anything at this point do a VI_FillScreen() to black first.
by hcs at 11:40 PM EDT on June 15, 2005
forgot the link:
n64test7.zip

I'm considering moving the development of this library to sourceforge so it won't be able to fall off the net and I can maybe get some help.
corrected link by hcs at 11:41 PM EDT on June 15, 2005
n64test7.zip
'bout time I added an editing feature, isn't it...
by hcs at 8:56 PM EDT on June 16, 2005
As you may or may not know, there are two checksumming systems on the N64, one is built into the system in the form of the elusive PIF boot ROM, which the CPU actually runs before even looking at the cartridge, the other is in the 0x1000 byte header in front of a ROM that calculates the checksum of the first 0x100000 bytes of the ROM (after the header, that is), and sets things up. While the latter (CRC within the header) is thoroughly understood the PIF checksum algorithm is currently unknown.
I'd like to write N64 programs without having to rely on headers pulled from existing games, thus I want to write my own header. The problem is that the header is checked by the unknown boot ROM checksumming algorithm. It is therefore my intention to understand the checksum well enough to allow use of my own code. Then I can release the source code to a library which represents the whole ROM, without an illegally copied bit at the beginning.

I've been informed by people in the N64 scene longer than me that this has been attempted but never completed, and CRC algorithms aren't exactly my strong point, but I'm going to see what I can do.
by hcs at 10:31 PM EDT on June 23, 2005
The checksum routine is rather straightforward (though I'd certainly never call it simple), I've recoded it in C here (why is the extension asm? er, whoops)
The result is then fed to some undocumented registers which I presume map to the CIC chip, so it has the final say in checking. I should be able to spoof this by providing a known checksum value. Haven't been able to test yet, though.
by hcs at 9:13 AM EDT on July 5, 2005
Note to self (and anyone else interested):

It is very important to invalidate the instruction cache if you're writing instructions somewhere that you actually want executed (like, say, an exception handler).
Cache instruction 0x10 does this. The appropriate line in GNU asm is:

cache 0x10,($9)

or in U64ASM:

cache $10,(t1)
by hcs at 8:26 AM EDT on July 7, 2005
I took some time off from trying to figure out the boot situation and finally disassebled an N64 Game Shark uploader. I've now got a Windows XP-compatible command line uploader, which I currently have set up to take an NES ROM on the command line and send it with Neon64. Cool stuff. Now I'm working on figuring out the reading bits so I can detect the ROM version (US, Europe, and maybe I'll get around to implementing support for the Japanese version now) and avoid reuploading the emulator itself if it's already running.
It'll be open source, of course, which will make it the only open source GS uploader I know of.
by hcs at 12:35 PM EDT on July 7, 2005
No detection yet, reading is a bit confusing...
Here's the uploader, which includes Neon64.
by hcs at 12:56 PM EDT on July 7, 2005
Now this is odd, the uploader works well in Windows XP but not in Win98 or in a direct port to Linux. Maybe the inpout32 driver is doing something special with the data when it's actually handling it under XP.
by hcs at 8:51 PM EDT on July 10, 2005
Changed the initial handshake/sync thingy and now it works on Windows XP, Windows 98, and in a Linux port. The current source for this and some other projects runderwo and I have collected are in the n64dev SourceForge project CVS.
I'm glad to get that out of the way, now I can focus on actually writing stuff for the N64.
by hcs at 9:10 AM EDT on July 11, 2005
Oh, delicious irony:
The guy who wrote the program I first disassembled (because he refused to give me the source) now wants to incorporate my improved version into his own project.
Well, the source is out there now, anyone's welcome to it (I've got to get a license on it sometime...)
by Mouser X at 11:56 AM EDT on July 11, 2005
Hah. If it was me, I'd be thinking "If you had given me your source in the first place, it would have been faster/better." Though in truth, all I'd say is something like "I'll let you use it if you give me help next time I ask for it."

Then again, I might say nothing at all, and they use it anyway. But yes, that is rather funny. That's what you get when you mess with HCS! See your program? Can I use your source? No? Well, I'll figure out myself. What's this? Mine is better than yours, and you wouldn't even let me see your source? Well, hopefully it helps out. (My reply would probably be closer to "Geez. Thanks for the help!").

Anyway, there's my 2 cents. Mouser X over and out.
by hcs at 12:55 PM EDT on July 11, 2005
Well, he had a legitimate reason not to give it to me. I told him I'd be releasing whatever source I end up with and his apparently came from official Datel/Interact sources, so he wasn't really at liberty to distribute it anyway.


Go to Page 0

Search this thread

Show all threads

Reply to this thread:

User Name Tags:

bold: [b]bold[/b]
italics: [i]italics[/i]
emphasis: [em]emphasis[/em]
underline: [u]underline[/u]
small: [small]small[/small]
Link: [url=http://www.google.com]Link[/url]

[img=https://www.hcs64.com/images/mm1.png]
Password
Subject
Message

HCS Forum Index
Halley's Comet Software
forum source