NESDev and Strangulation Records messageboards
Forum Index | FAQ | New User | Login | Search

Previous ThreadView All ThreadsNext Thread*Show in Threaded Mode


SubjectImporting and another question  
Posted byAnonymous
Posted on9/13/04 00:07 AM
From IP68.54.162.196  



I recently got the "Hey why don't I expand my horizons and create an emulator" ideas and so far so good. I'm using my SDL/OpenGL/OpenAL engine as a basis for the emulator (like window management, keyboard management, sound, graphics etc). One problem I've had is getting the actual PRG code to import into something readable. I got the iNES header to import correctly however. I don't usually work with binary files (my engine uses a library called SDL_IMAGE so I didn't have to worry about reading in binary the textures for my engine) so this is kind of new to me.

Also another question (also completely different from what I'm used to), what am I going to be left with after the code is imported into an array?

Is it going to be in hex? In which I'll have a switch statement and then it'll process whatever based on the imput.

With all my C++, PHP, ASM and MySQL work I've done this is entirely new, which is really kind of sad, it's like re-learning how to drive.




SubjectRe: Importing and another question new  
Posted byMemblers
Posted on9/13/04 11:20 AM
From IP68.58.99.218  



Yeah, hex it is. Working with bytes ('unsigned char' in C, right? I'm still learning that stuff).

If a switch table translates to something like a jump table, then yeah, that sounds like it'd be best for doing CPU emulation.




SubjectRe: Importing and another question new  
Posted byDisch
Posted on9/13/04 3:32 PM
From IP66.82.9.82  



SDL Image won't help you in any way when making an NES emu. Also, I don't think OpenGL has anything to offer, either. Just the basic SDL library is really all you need. You won't need/have any textures/surfaces other than the back buffer (your best bet is to redraw the entire screen pixel by pixel every frame, rather than blit 8x8 tiles to the screen.. this way mid-scanline and mid-frame writes can be properly emulated).

I'm not really familiar with OpenAL, but I think the Sound streaming functions in SDL should more than suffice for your needs.


The hardest part about emulating the NES is running the PPU, main CPU, and pAPU all at the same time (as time passes in one of them, time is also passing in the 2 other ones, and you have to keep them all updated). Games often use timing tricks for some visual effects, so you have to manage the 3 areas properly.

In my emu I kept 3 different cycle counters, (one for CPU, PPU, and APU). I based EVERYTHING in PPU cycles (since 1 PPU cycle is a third of a CPU cycle... this avoids having to deal with fractions of cycles). I'd recommend doing something like this (which has worked well for me in the past):

1) Lock the back buffer, hand off the pointer to the buffer to your PPU emu.

2) Run the CPU for a frame.. or until the nearest IRQ (whichever comes first)

--a) whenever the CPU makes a write/read to PPU/APU regs, have the PPU/APU 'catch up' to the current CPU cycle (in the case of the PPU, this means rendering pixels up to the current time, in the APU it means generating sound samples). Also update the PPU on CHR-bank swaps... and update the APU on PRG-bank swaps.

--b) when the CPU strobes the joypads, poll user input (makes it pretty simple ^^)

--c) when the CPU does anything IRQ related, re-evaluate when the next IRQ is going to occur

3) Repeat #2 until a full frame has passed

4) Catch the PPU and APU up to the CPU

5) Unlock back buffer, wait until ~1/60th of a second has passed, then swap the image to the screen (this is probably where you could check for SDL events like exit messages and stuff).


For CPU emulation... a big switch statement is the best way to go. Most if not all compilers will convert a large switch statement to a jump table after it's compiled, and that's really the best you can get (unless maybe you put inline assembly... but that would destroy the portability I'd assume you're going for with SDL).




SubjectRe: Importing and another question new  
Posted byFx3
Posted on9/13/04 8:41 PM
From IP201.1.134.95  



You'll have problems this way. I don't use cycle counters, only a pixel counter that clocks at every 341 pixels. A clock changes the scanline and process any event (VINT start/end and such). Since I use pixel-by-pixel emulation, i stop here ;)




SubjectRe: Importing and another question new  
Posted byDisch
Posted on9/13/04 10:05 PM
From IP66.82.9.64  



Well a pixel counter is essentially the same thing as a cycle counter. Instead of doing 341 pixels per scanline, I do 341 cycles per scanline (and render 1 pixel each cycle).




SubjectRe: Importing and another question new  
Posted byAnonymous
Posted on9/14/04 00:41 AM
From IP68.54.162.196  



I was going to load in the sprites as texture surfaces and then I would be able to do shader effects on them.

No one has answered my question about how to import the NES rom files properly though.




SubjectRe: Importing and another question new  
Posted byFx3
Posted on9/14/04 02:15 AM
From IP201.1.132.182  



I already knew that the sprites would be used as textures, that's it.
What do you mean by "importing"? The file data loading in a cache?




SubjectRe: Importing and another question new  
Posted byAnonymous
Posted on9/14/04 03:00 AM
From IP68.54.162.196  



Reading the file data, I have the iNes Header reading in properly but I don't know what data type to use for the prg or chr sections. Maybe you or some one could post their loading code?




SubjectUnsigned charmander go! new  
Posted bytepples
Posted on9/14/04 03:53 AM
From IP68.53.188.30  



Short answer
When in doubt, read binary files such as the PRG and CHR sections of a UNIF or iNES file into an array of unsigned char.

Long answer
Extremely simplified, with no error checking (you'll need to test that fopen, fread, and malloc don't return 0), and untested, but hopefully enough to give the gist:

unsigned char *prg_data, *chr_data;
unsigned long int prg_data_size, chr_data_size;
char chr_writable;
FILE *infile;

infile = fopen("Tetramino.nes", "rb");
fread(iNES_header, 16, 1, infile);
unsigned long int prg_data_size = iNES_header.prg_size * 16384;
unsigned char *prg_data = malloc(prg_data_size);
fread(prg_data, prg_data_size, 1, infile);
if(iNES_header.chr_size > 0) {
chr_data_size = iNES_header.chr_size * 8192;
chr_data = malloc(chr_data_size);
fread(chr_data, chr_data_size, 1, infile);
chr_writable = 0;
}
else {
chr_data_size = 8192;
chr_data = malloc(chr_data_size);
chr_writable = 1;
}
fclose(infile);

____________________
My English is better than your Geberquen.


SubjectRe: Unsigned charmander go! new  
Posted byFx3
Posted on9/14/04 03:59 AM
From IP201.1.128.161  



this won't be enough to him, i suppose :D
-For my best, unless someone is God, NES data must be "unsigned char".
-Files must be opened in binary mode, instead of text mode.




SubjectRe: Unsigned charmander go! new  
Posted byAnonymous
Posted on9/14/04 11:49 AM
From IP68.54.162.196  



Alright thanks, that's all I needed. I had a similar setup for grabbing the data but your way is much more efficient.

If I have more questions, I'll be back :)




SubjectRe: Importing and another question new  
Posted byAnonymous
Posted on9/14/04 2:44 PM
From IP83.226.103.194  



I don't know what data type to use for the prg or chr sections
how about, uhm... "BYTE"?




Previous ThreadView All ThreadsNext Thread*Show in Threaded Mode
Jump to

Memblers' homepage             Contact Me

Forums powered by WWWThreads Demo