6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed Nov 13, 2024 4:58 am

All times are UTC




Post new topic Reply to topic  [ 30 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Sun May 09, 2021 8:25 pm 
Offline

Joined: Thu May 06, 2021 7:07 pm
Posts: 14
Quote:
The same data has to appear twice in the memory map, because that's how the machine works.


You are right
I have used a simple disassembler on my .nes file , I found the following :

Mapper
-------------------------------
NMI vector $C0C0
Reset vector $C000
IRQ vector $FFF9

-------------------------------
PRG-ROM low page (bank 0)
8000: 4C
8001: 94
8002: C0
8003: 20
8004: 20
8005: 56
8006: 45
8007: 52
8008: 53
8009: 49
------------------------------
PRG-ROM high page (bank 1)
C000: 4C; JMP $C094 ; the reset vector is at $C000 ! , the following 2 bytes holds the values 94 and C0 , combining them gives $C094 (Little Endian)
C001: 94
C002: C0
C003: 20
C004: 20
C005: 56
C006: 45
C007: 52
C008: 53
C009: 49

PRG-ROM high page (bank 1) contains the reset vector's address


Top
 Profile  
Reply with quote  
PostPosted: Mon May 10, 2021 8:23 pm 
Offline

Joined: Thu May 06, 2021 7:07 pm
Posts: 14
Thanks guys for your explanations

I make my conclusions as the following :

1. The 16 bytes of Nes header contains some information about the nes file (size of prg-rom , size of chr-rom , mappers , ...)
2. reset vector location is vary (I have no idea how to make my emulator get it)
3. prg-rom should be mapped at a specific addresses ($C000 and mirrored at $8000)
4. I don't know whether the start of the prg-rom starts immediately after the header bytes or not


Top
 Profile  
Reply with quote  
PostPosted: Mon May 10, 2021 10:56 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
Santa-Fe wrote:
JimBoyd wrote:
Hexadecimal $C000 = 49152 decimal.
Hexadecimal $C0000 = 786432 decimal.

Still larger than my 24 kb rom addresses .


I hadn't researched programming the NES yet.
I thought that conversion error could cause problems so I wanted to point it out right away. Before I could get back to the forum, Martin A and BigEd provided useful information.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 7:23 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
Santa-Fe wrote:
2. reset vector location is vary (I have no idea how to make my emulator get it)

What's the problem? You already have the answer in this thread.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 10:55 am 
Offline

Joined: Thu May 06, 2021 7:07 pm
Posts: 14
BigEd wrote:
What's the problem? You already have the answer in this thread.


You've mentioned that the reset-vector at $FFFC
but it was at $C000 according to the disassembler I've used

It's location is vary , each nes file has it's own location for it , and some are equal
I have to find a formula to find it , a simple example would explain it


Martin A wrote:
If your file is 16 bytes longer than 24k, then as, there's likely a 16 byte header. Unless you know the format of the header, ignore it ! it's very unlikely to be part of the orignal game.

If you're expexting data from 2 chips one 8k for graphic definitions one 16k for the game code, then there's 2 options, 8k first or 16k first.

What you're interested in is the last bytes of the code rom, as they will be most likely be the 6502 hardware vectors.

If the 8k graphic one is first, then the last 6 bytes of the 16k rom will be the very last 6 bytes of the file.
Code:
Option 1 - file offsets
0000-000F - Header
0010-200F - Graphic data
2010-6009 - game code
600A-600F - 6502 Vectors

If the 16k rom is first, then the last 6 bytes of the 16k rom will be at offset 0x400A
Code:
Option 2 - file offsets
0000-000F - Header
0010-4009 - game code
400A-400F - 6502 Vectors
4010-600F - Graphic data


If all 3 vectors look sensible, then you could have the right spot. If they don't make sense, you could be looking at graphic data. Where the vecors jump too should give you clues as to where the rom expects to be run from.

For example reset or interrupt vector of 0xBXXX wouldn't be in a rom located at 0xC000 to 0xFFFF so the rom in that case would probably expect to be 0x8000 to 0xFFFF.


1. Is it possible the CHR-Rom appears before the PRG-Rom ?
2. I don't need to find these vectors manually , I need some formula to be used by my emulator to find them


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 11:31 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
At reset the 6502 reads two bytes starting at FFFC. Once you've mapped the ROM - twice - those two bytes come from the ROM. Those two bytes give the address of the first opcode to be run. That's how the 6502 works. Any emulator will need to know how to do that.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 11:45 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
The 6502's reset vector is always at $FFFC-$FFFD. Always.

To find out what data is at that location, you're going to have to understand the format of the file that you have. There appear to be a number of different file formats for NES simulators. It looks like you can determine which one you have by examining the first few bytes of the header. The header should tell you what's in the file, how big each part is, and various options that you'd have to know a lot more about NES hardware than I do to understand.

Determining which parts of the data appear at which locations in the CPU's address space appears to be the job of a "mapper", which is hardware that's specific to a particular cartridge. The header will hopefully tell you which mapper you've got, and the maze of documentation on the Nesdev wiki will tell you what it does.

For example, mapper 0 places 16K or 32K of PRG ROM at $8000-$FFFF. If there is only 16K of ROM, then it appears twice (so $C000-$FFFF is a copy of $8000-$BFFF). Other mappers do other things. There are a lot of them.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 12:23 pm 
Offline

Joined: Thu May 06, 2021 7:07 pm
Posts: 14
I am sure you are all completely right , the problem is that I am new to that stuff
I just cant understand why the disassembler gives me these results

may I ask you guys to have a look at that page and tell me if its any good ?

https://xem.github.io/nes/

I have attached the rom I am working on (Nuts & Milk) .


Attachments:
N&M.zip [13.82 KiB]
Downloaded 53 times
Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 12:31 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
If the disassembler tells you that the program code begins at C000, it's because it is smart enough to read the two bytes at FFFC.

In the *.nes file, the 16 byte header is followed directly by the 16k PRG ROM, and you'll see towards the end of that 16k ROM the bytes
ffff ffff ffff ffff ff40 c0c0 00c0 f9ff
wherein you'll see the three vectors in this case: FFF9, C000, C0C0.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 1:35 pm 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
The header of that file is
4E 45 53 1A 01 01 01 00 00 00 00 00 00 00 00 00

The first 4 bytes tell us that it's either iNES or NES2.0 format. Which one doesn't really matter in this case, as NES2.0 is backwards compatible, and this file doesn't use any of its extended features. I'll assume iNES because it's simpler.

The next two bytes are $01 and $01, which mean 16K PRG ROM and 8K CHR ROM. The mapper number is scattered through a few of the other bytes, which are all 0, so it's mapper 0.

The next 16K ($0010 - $400F) is PRG ROM. That appears in the 6502's memory space at locations $8000-$BFFF and also at $C000-$FFFF (because that's what mapper 0 does with 16K ROMs). It looks like the copy at $8000-$BFFF isn't used, but it'll still be there.

On power-up the 6502 reads the interrupt vector at $FFFC and starts execution at the address it points to. $FFFC is at $400C in the file, and those two bytes are 00 C0. So we expect to see code at $C000 in the 6502's memory space, which is $0010 in the file. At those locations we see 4C 94 C0, which is JMP $C094. And at $C094 ($00A4 in the file) we get A2 FF 9A A9 00 ..., which translates to
Code:
LDX #$FF
TSX
LDA #$00
...

which is the sort of thing you'd expect reset code to do.

You say
Quote:
You've mentioned that the reset-vector at $FFFC
but it was at $C000 according to the disassembler I've used

which makes me think you might not know what a vector is. In the 6502 world, a vector is two bytes in memory that contain the address of some code. The disassembler is showing you the code, not the vector.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 3:53 pm 
Offline

Joined: Thu May 06, 2021 7:07 pm
Posts: 14
BigEd wrote:
If the disassembler tells you that the program code begins at C000, it's because it is smart enough to read the two bytes at FFFC.

In the *.nes file, the 16 byte header is followed directly by the 16k PRG ROM, and you'll see towards the end of that 16k ROM the bytes
ffff ffff ffff ffff ff40 c0c0 00c0 f9ff
wherein you'll see the three vectors in this case: FFF9, C000, C0C0.


I found it when I viewed the nes file in hex viewer , exactly as you have mentioned.

@John West , BigEd

that was a great explanation

to make a simple test I filled the buffer (the array of my prg-rom) at the location ($C000) as the following :
Code:
fread (0xC000+buffer,sizeof(unsigned char),24592,fp);

Now buffer [0C010] (I've shifted it 16 bytes to remove the header) is the first byte of code , and that's right as I tested it

I am trying to test if buffer [0xFFFC] will point to the reset-vector in my new mapped rom
but have no Idea how to do so , should I add 0x10 to 0xFFFC ? that's wrong for sure
So 0xFFFC - 0xC000 + 0x10 ?


Image


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 5:09 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
yes, those two bytes you've highlighted are the ones which determine the first instruction at reset.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 11, 2021 9:13 pm 
Offline

Joined: Thu May 06, 2021 7:07 pm
Posts: 14
Is there a common way to map the prg-rom ?
the following method works fine for the beginning of the buffer , but it doesn't give the right values at the end of the buffer
Code:
fread (0xC000+buffer,sizeof(unsigned char),24592,fp);


Top
 Profile  
Reply with quote  
PostPosted: Wed May 12, 2021 8:26 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
Santa-Fe wrote:
Is there a common way to map the prg-rom ?
the following method works fine for the beginning of the buffer , but it doesn't give the right values at the end of the buffer
Code:
fread (0xC000+buffer,sizeof(unsigned char),24592,fp);

What you're doing here is loading the entire file into a single buffer. That might be what you want - I don't know what you do with it later - but it's probably not.
The file contains three independent blocks of data. It will be less confusing if you treat them as such:
Code:
uint8_t header[16];
uint8_t cpuMemory[65536];
uint8_t chrBuffer[8192];

fread( header, 1, 16, fp);
fread( cpuMemory + 0xc000, 1, 16384, fp );
memcpy( cpuMemory + 0x8000, cpuMemory + 0xc000, 16384 );  // because 16K ROMs are mirrored
fread( chrBuffer, 1, 8192, fp );

Then PRG ROM will be at the locations in cpuMemory that the CPU expects to find it. The reset vector is at cpuMemory[0xfffc] and cpuMemory[0xfffd], and the reset code starts at cpuMemory[0xc000].

(Of course, hard-coding all of the numbers like this will only work for this particular file. In general, you'd read the header first, examine its contents, and use that to decide how to handle the rest. But for an initial "just make something work", this will do)


Top
 Profile  
Reply with quote  
PostPosted: Wed May 12, 2021 2:50 pm 
Offline

Joined: Thu May 06, 2021 7:07 pm
Posts: 14
Hi John West , you made things very easy for me to understand
Actually , mapping that way is awesome , though it shows some errors
I am sure the general idea is fine , you've gave me the proper method
I made some modifications as bellow :
Quote:
header=(uint8_t*)malloc(0x10); // header of the Nes file
tmp=(uint8_t*)malloc(0x4000); // temporary variable for hold 16k program rom
prg=(uint8_t*)malloc(0xFFFF); // program variable to be mapped at addresses C000 & 8000
//-------------------------------------------
fread( header, 1, 0x10, fp); // reading 16 bytes , (header contents)
fread( tmp, 1, 0x4000, fp ); // reading 16k (program rom) into tmp
//-------------------------------------------
memcpy( &prg[0xC000], &tmp[0], 0x4000 ); // fill the prg-rom starting at address C000 , using the tmp variable
memcpy( &prg[0x8000], &prg[0xC000], 0x4000 );// mirroring prg-rom at address 8000
//--------------------------------------------
printf ("%02X",prg[0xFFFC] | (prg[0xFFFD] << 8 )) ; // result is C000 (The reset-vector of my Nes file)
fclose (fp);
free (tmp) ;

Many Thanks for all of you guys .


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 30 posts ]  Go to page Previous  1, 2

All times are UTC


Who is online

Users browsing this forum: No registered users and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: