What's new

Nes

|\/|-a-\/

Uli Hecht
i think the greatest problem in writing an emu is the bugfixing, if i change the source of other emus and compile, it won't work anything, although i changed not much (sometimes i thought i found bugs in other emus, while comparing docs and emu).
My emu shows the first gfx, it's just the first pattern table entry repeated the whole screen, because name table contains only zeros.
I tried with a few small demos, but they don't work.
I'm getting tired with bugfixing (but i find enough of them).
Do you know a VERY easy nes demo i can start with? (i used pacman, wall.nes, pong.nes, zeropong.nes, jumpy.nes and one which shows the "peace" logo (i don't remember the strange name now))
uli


it seems, html doesn't work anylonger on this board (<p align...)
|
V
 

hap

New member
I don't know really, when my emulator showed its first graphics, lots of mapper 0 roms were booting fine... Amiga Demo and Zelda Simulator look to be very 'easy' to me.
 

Jsr

New member
|\/|-a-\/ said:
i think the greatest problem in writing an emu is the bugfixing, if i change the source of other emus and compile, it won't work anything, although i changed not much (sometimes i thought i found bugs in other emus, while comparing docs and emu).
My emu shows the first gfx, it's just the first pattern table entry repeated the whole screen, because name table contains only zeros.
I tried with a few small demos, but they don't work.
I'm getting tired with bugfixing (but i find enough of them).
Do you know a VERY easy nes demo i can start with? (i used pacman, wall.nes, pong.nes, zeropong.nes, jumpy.nes and one which shows the "peace" logo (i don't remember the strange name now))
uli


it seems, html doesn't work anylonger on this board (<p align...)
|
V

Try Chris Covells rgb.nes.
It won't work perfectly on a real NES, but at least it's good for testing.
 

|\/|-a-\/

Uli Hecht
thanks, i'll try them out!

cpu works not bad now, every rom ends now with a stack overflow (if there were more bugs, some roms would crash because of other bugs)

maybe i emulated TXS as TSX and TSX as TXS... ( i saw that the most roms are setting the stack pointer to 0xFF), i'm going to check this after school today.

the gfx show "something" strange, but the nametable is not completeley set to zero during emulating.

but i don't understand the attribute table stuff, every doc describes squares (i think you know what i mean), but what the hell is meant?
An attribute table has 0x40 bytes, 0x3C0 (960 nametable entries) devided through 0x40 is 15. Which attribute table entries do the first 15 nametable entries use???
 

hap

New member
I explained the attribute table a bit to aprentice on page 4 of this thread. I'd emulate the basics before that though (nametables and bg tiles), my early black n white pics in this thread were made without emulation of the attribute table.
 

|\/|-a-\/

Uli Hecht
yes, i also emulate without attribute table, but wasn't sure whether it works after having some strange graphics on the screen (maybe the ppu screen drawing function is wrong...)

(emu is written with GTK+ window library, MemCpu and MemPpu are instances of MEMCPU and MEMPU class with overloaded operators [], = and type conversion, operator[] saves the address to private member variable nDest, "operator char() const" type conversion returns the value using nDest. So don't worry about the syntax (MemCpu[...]))

Code:
void PpuUpdateScr() {
   unsigned int  x, y;              //position
   unsigned char Pattern1, Pattern; //pattern table color bits
   unsigned int  nindex;            //nametable index
   unsigned int width, height, rowstride, n_channels;
   guchar *pixels, *p;

   width =      gdk_pixbuf_get_width(GuiPbScr);
   height =     gdk_pixbuf_get_height(GuiPbScr);
   n_channels = gdk_pixbuf_get_n_channels(GuiPbScr);
   rowstride =  gdk_pixbuf_get_rowstride(GuiPbScr);
   pixels =     gdk_pixbuf_get_pixels(GuiPbScr);
   
   unsigned int nused = RegFnNameTableSel(); //name table base address
   unsigned int pused = ((char) MemCpu[(unsigned int) 0x2000] & 4) << 0xB;
   for(y = 0; y < CpuScanline; y++) {
      for(x = 0; x < 255; x++) {
         nindex = (unsigned int) (char) MemPpu[(y / 8) * 32 + x / 8 + nused] & 0xFF;

         Pattern1 = (char) MemPpu[nindex                                //nametable index
            * 0xF + pused + (y % 8)] >> (x % 8);                        //patterntable index
         Pattern = Pattern1 + ((char) MemPpu[nindex                     //nametable index
            * 0xF + pused + (y % 8) + 1] >> ((x % 8) - 1));             //patterntable index
      
         //writing to video buffer
         p = pixels + y * rowstride + x * n_channels;
         p[0] = 64 * Pattern;
         p[1] = 64 * Pattern;
         p[2] = 64 * Pattern;
      }
   }
   gdk_draw_pixbuf(GuiWgImgScr->window, NULL, GuiPbScr, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 
      0, 0);
   PpuLastCycle = cycle++;
}
 

hap

New member
Sorry, I haven't kept myself busy with NES emulation for well over a month, so I can't easily find errors in your code, let alone my own code.

Are you updating the screen per frame ? I strongly suggest to at least switch to a per-scanline engine. Also, use AND instead of modulo, and logic shifts instead of mul and div (when using y */ 2^x calculations).
 

|\/|-a-\/

Uli Hecht
found the bug: i have to mask Pattern1 with 1 and Pattern with 2...

you've explained the use of attribute table very well, but the screen has 30 rows of tiles. i would unterstand the square stuff if there were 32 rows (then i can use 8*8 squares)

|+|+|
|-|-|
|+|+|
|-|-|
'-'-' <-- ???
 

hap

New member
The bottom part of the available attribute 8*8 'rectangle' is just unused, don't worry about that.
 

|\/|-a-\/

Uli Hecht
thanks :) !!!

@hap:
hm, is the attribute table in dependence of the nametable or the pattern table, i saw some emus showing the tiles stored in patterntable separatly (in a vram debugging window), if the attribute table is in dependence of the nametable (as explained on page 4 of this thread), i wonder how the debugger can draw the pattern tables tiles colored ?!
 

hap

New member
A background pixel 'is' 4 bits, 2 low bits from the tiles, 2 high bits from the attribute. A debugger's pattern table viewer will probably show the 2 low bits only, and if you're lucky, the used attribute bits are 0, and colours will be correct.
 

|\/|-a-\/

Uli Hecht
no, the answer is simplier: the debugger is smart and uses an assumed palette (verifies, how the colors for tiles are set in the name table (i think))

still worry about that strange colored pic:
View attachment 28588

why are there squares and not just rects like expected in the middle part of the screen background...
 

hap

New member
Looks like the attribute bits are ignored sometimes. I'm not sure about the squares.

could you post a pic of the zelda title screen simulator ? :p
 

hap

New member
I've got preliminary sound working; just the DMC (eg. used for those digi drums in mario3), and 2 square channels with hanging notes, no volume envelopes, and no sweeps.. but melodies in most games can be heard fine. The DirectSound part is working nicely.
 

aprentice

Moderator
hap said:
I've got preliminary sound working; just the DMC (eg. used for those digi drums in mario3), and 2 square channels with hanging notes, no volume envelopes, and no sweeps.. but melodies in most games can be heard fine. The DirectSound part is working nicely.

used any specific direct sound tutorials that would be of any help?
 

hap

New member
WhiteX: I can't wait for Grand Theftendo

aprentice: I used some tutorials a few months ago when building the framework, but don't remember which... and I used MSDN

This is basically what I do..
init:
- DirectSoundCreate
- SetCooperativeLevel (I use the DSSCL_PRIORITY flag)
- create the primary sound buffer
- set the format of the primary sound buffer (I use 1 channel, 16 bit, 44100hz samplerate)
- create the secondary sound buffer (I use the flags DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2 and a buffer size of 4410*2: 100ms)
- lock the whole secondary sound buffer, write 0 to it to prevent it from playing garbage, and unlock it
- play the secondary sound buffer with DSBPLAY_LOOPING
- at the start of emulation, use a variable to remember where the play cursor is, with GetCurrentPosition

emu:
It was very easy to preliminarily emulate the square wave channels, so it just played the melody with a constant volume, and notes hanging.. about 20 lines of code (it's working better now by the way :p )
The NES, and probably many old consoles, plays 1 sample per cpu cycle. This means that instead of 44100hz, it's played at 1.79Mhz, so it should be downsampled with slices of 1.79mhz/44100hz=approx 40.58.
I use a 1.79mhz/~60fps=approx 30000 byte buffer per sound channel, and fill it each frame.
When the frame is finished, I downsample and mix the channels and end up with a buffer of about 750 samples (2 bytes per sample, so it's 1500 bytes).

dsound (end of each frame):
- GetCurrentPosition in a loop, until the difference between the previous and current play cursor is larger than the number of samples you're going to write (1500 in this case). Use Sleep(1) in between when you can see there's plenty of time left. As a bonus, you'll have perfect frame timing now.
- lock 1500 bytes in the secondary sound buffer, starting at the previous play cursor, copy the 1500 bytes, and unlock it. You might have to write twice if previous play cursor+locked size is larger than the buffer size.
- previous play cursor=(previous play cursor+1500)%buffer size
 
Last edited:

ShizZy

Emulator Developer
Hey hap,
Question for you. Seeing as you have had success with sound (in general), can you give me some advice on sound emulation? I don't know where to start at all, I've never worked with sound before. Do you know of any documents that explain the important concepts? This isn't for a NES emulator, but rather GB - though the same idea. (the two APU's are pretty similiar though anyway I believe)
 

Top