Hello World

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

FinalZero wrote:1) What does the ".segment "INESHDR" do? There's no predefined segment by that name, so I'm confused. What would happen if it was left out?
You wouldn't get a valid iNES header
2) Does "number of 16 KB program segments" mean that one has go through one's source and count how many segments there are?
Usually your link script template will specify how much PRG ROM it'll create. For example, an NROM-128 template will always make 16400 bytes (16 bytes of header and 16384 bytes of PRG ROM), an NROM-256 or CNROM template will always make 32784 bytes (16 bytes of header and 32768 bytes of PRG ROM), and a template for UNROM, BNROM, or ANROM will probably make 131088 bytes (16 header, 131072 PRG ROM).
3) What is a mapper? Why do different games use different ones? I keep finding lists of them, but nothing that actually explains what they are and do.
They turn the page in the ROM, so to speak. Without them, the NES can't see more than 32 KiB of program and 8 KiB of graphic tiles. Some mappers have smaller "pages", which lets them have more than one active at once, and some have extra timing circuitry to make a few scrolling tricks easier.
4) What is a nametable? What's stored in them?
In List of background topics, please see Text mode and Text user interface. The nametables are a lot easier to explain if you're familiar with those.
Does that mean it's used for games that scroll horizontally or not?
Vertical mirroring is used by some games that scroll horizontally, such as the original Super Mario Bros. and Super Mario Bros. 2.
Also, why doesn't one need ".org $0000" at the beginning of the header? Is it implied?
ca65 delegates placement of code in the binary image to the linker.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

You wouldn't get a valid iNES header.
Ok. Give me some time to figure out the linker...
Usually your link script template will specify how much PRG ROM it'll create. For example, an NROM-128 template will always make 16400 bytes (16 bytes of header and 16384 bytes of PRG ROM), an NROM-256 or CNROM template will always make 32784 bytes (16 bytes of header and 32768 bytes of PRG ROM), and a template for UNROM, BNROM, or ANROM will probably make 131088 bytes (16 header, 131072 PRG ROM).
Ok.
They turn the page in the ROM, so to speak. Without them, the NES can't see more than 32 KiB of program and 8 KiB of graphic tiles. Some mappers have smaller "pages", which lets them have more than one active at once, and some have extra timing circuitry to make a few scrolling tricks easier.
Ok.
In List of background topics, please see Text mode and Text user interface. The nametables are a lot easier to explain if you're familiar with those.
Vertical mirroring is used by some games that scroll horizontally, such as the original Super Mario Bros. and Super Mario Bros. 2.
I've read up on nametables and mirroring, and I think I understand what they are, and what kind of games would use different types of the latter.

As a side note, looking at http://tuxnes.sourceforge.net/nesmapper.txt , it gets Dragon Warrior 1, 3, and 4 wrong. I've just fired those games up myself with FCEUX and they all have vertical mirroring. Also, interestingly, Double Dragon 2 has a vertical mirroring for it's intro/title screen, but horizontal mirroring for everything else.
ca65 delegates placement of code in the binary image to the linker.
I see. All this makes me wonder what nbasic is programmed to do...
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

FinalZero wrote:As a side note, looking at http://tuxnes.sourceforge.net/nesmapper.txt , it gets Dragon Warrior 1, 3, and 4 wrong.
The mirroring settings in the iNES header are meant for games with hardwired mirroring, and are meaningless in games that have mapper-controlled mirroring. Games that use mappers like MMC1 or MMC3 can change the type of mirroring at any time.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

The mirroring settings in the iNES header are meant for games with hardwired mirroring, and are meaningless in games that have mapper-controlled mirroring. Games that use mappers like MMC1 or MMC3 can change the type of mirroring at any time.
Oh, ok. That still begs to ask why they didn't match the iNES header mirroring value with the one actually used in the game though...

But, am I right in assuming that the part of the header that says how many prg and chr rom sections there are? That is, the mapper specifies only a range, not the specific amount?
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

FinalZero wrote:Oh, ok. That still begs to ask why they didn't match the iNES header mirroring value with the one actually used in the game though...
I bet most dumpers would just guess the mirroring when filling in iNES headers until the games worked, and no matter what they guessed, games with mapper-controlled mirroring would always work.

But even if anyone cared about this, lots of games change the mirroring type at different times, and it would be very tedious to play through entire games just to make sure they use only one kind of mirroring all the way to the end, for the sole purpose of setting a bit in the header that doesn't really do anything.
But, am I right in assuming that the part of the header that says how many prg and chr rom sections there are? That is, the mapper specifies only a range, not the specific amount?
Each mapper has a maximum amount of PRG and CHR it can handle, and these limits are usually specified in detailed documents about them. The values in the iNES header count actual "pages", which are 16KB large in the case of PRG and 8KB in the case of CHR. These sizes were used because they were thought to be the smallest in commercial NES games (this assumption was wrong though, as there is at least one game with 8KB of PRG, and this game has to be doubled up in order to be correctly represented in the iNES format).

Since the sizes of memory chips are always powers of 2 (32KB, 64KB, 128KB, 256KB, etc) it's best that your PRG and CHR sections are like that too, so you should never use a weird iNES configuration like 3 PRG pages (48KB).
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

I bet most dumpers would just guess the mirroring when filling in iNES headers until the games worked, and no matter what they guessed, games with mapper-controlled mirroring would always work.

But even if anyone cared about this, lots of games change the mirroring type at different times, and it would be very tedious to play through entire games just to make sure they use only one kind of mirroring all the way to the end, for the sole purpose of setting a bit in the header that doesn't really do anything.
I'd expect them to at least fire up the rom and check though. But you're right, it's not really needed.
Each mapper has a maximum amount of PRG and CHR it can handle, and these limits are usually specified in detailed documents about them. The values in the iNES header count actual "pages", which are 16KB large in the case of PRG and 8KB in the case of CHR. These sizes were used because they were thought to be the smallest in commercial NES games (this assumption was wrong though, as there is at least one game with 8KB of PRG, and this game has to be doubled up in order to be correctly represented in the iNES format).

Since the sizes of memory chips are always powers of 2 (32KB, 64KB, 128KB, 256KB, etc) it's best that your PRG and CHR sections are like that too, so you should never use a weird iNES configuration like 3 PRG pages (48KB).
What happens if there's more? It's just simply not available? Linker error?

I suppose mappers varied in price too, thus affecting how a development team chose which one to use.

-----

From http://wiki.nesdev.com/w/index.php/MMC3 ...
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.
I don't understand what it means by "in each pair".

So, in addition to setting the header correctly, one must set things at the address in the mapper correctly too, in order for a game to run?

Also, it says:
Mirroring ($A000-$BFFE, even)
Does it reserve all of $A000 to $BFFE to say what the mirroring is? Why can't it just use a couple bits?? I think I'm misunderstanding something...

-----

And finally, do I have the following right?: The ca65 assembler creates an object file from assembly files, and then the ld65 linker creates a NES file from the object file?

-----

http://www.cc65.org/doc/ld65-2.html
Looking at the ld65 documentation, the -t (specifies target system) option and -C (specifies custom config file) option can't be used together. What kind of rom does the linker default to when "-t nes" is used?
Last edited by FinalZero on Sun Jan 02, 2011 1:30 am, edited 1 time in total.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

FinalZero wrote:What happens if there's more? It's just simply not available? Linker error?
More than what the mapper supports? I'm sure you can assemble very large ROMs, and some emulators will even run them without problems, but you will not be able to put them on real carts.
I suppose mappers varied in price too, thus affecting how a development team chose which one to use.
Yes. Things like extra RAM and batteries also played an important part in the manufacturing cost of the cartridges.
I don't understand what it means by "in each pair".
I think it's because most operations on the MMC3 are performed with two register writes: the first selects the operation and the second executes it. For example, to bankswitch a page of PRG-ROM you must first tell the mapper where in the addressing space the page will go, and then you tell it which page to put there.
So, in addition to setting the header correctly, one must set things at the address in the mapper correctly too, in order for a game to run?
Yes, you must configure the mapper to make sure everything (mirroring, active PRG and CHR pages, etc) is as you expect.
Does it reserve all of $A000 to $BFFE to say what the mirroring is? Why can't it just use a couple bits?? I think I'm misunderstanding something...
Because the 6502 relies on memory-mapped registers to communicate with different devices, when you write something to the mapper, the mapper has to decode the address in order to know which register you wrote to. The cart receives 15 address bits, and if you wanted a register to be accessible through a single memory location, the mapper would have to decode all 15 bits, increasing its complexity (and cost) unnecessarily. Since the mapper only has a few registers, it's easier to just decode a few bits and ignore the rest. As a side effect, the few registers are mirrored several times across the addressing space (the actual layout depends on which bits are decoded and which are ignored).

So, in the case you mentioned, it's not that the mapper needs a shitload of bytes just to configure the mirroring, it's just that the register that controls the mirroring can be accessed through any address in that range, but it's still just one register.

EDIT: I can't help you with the ca65 stuff.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

More than what the mapper supports? I'm sure you can assemble very large ROMs, and some emulators will even run them without problems, but you will not be able to put them on real carts.
Yeah, that's what I meant.
I think it's because most operations on the MMC3 are performed with two register writes: the first selects the operation and the second executes it. For example, to bankswitch a page of PRG-ROM you must first tell the mapper where in the addressing space the page will go, and then you tell it which page to put there.
Because the 6502 relies on memory-mapped registers to communicate with different devices, when you write something to the mapper, the mapper has to decode the address in order to know which register you wrote to. The cart receives 15 address bits, and if you wanted a register to be accessible through a single memory location, the mapper would have to decode all 15 bits, increasing its complexity (and cost) unnecessarily. Since the mapper only has a few registers, it's easier to just decode a few bits and ignore the rest. As a side effect, the few registers are mirrored several times across the addressing space (the actual layout depends on which bits are decoded and which are ignored).

So, in the case you mentioned, it's not that the mapper needs a shitload of bytes just to configure the mirroring, it's just that the register that controls the mirroring can be accessed through any address in that range, but it's still just one register.
Ok, I understand the reasoning, and how they're supposed to work now.
User avatar
clueless
Posts: 496
Joined: Sun Sep 07, 2008 7:27 am
Location: Seatlle, WA, USA

Post by clueless »

FinalZero wrote:And finally, do I have the following right?: The ca65 assembler creates an object file from assembly files, and then the ld65 linker creates a NES file from the object file?

-----

http://www.cc65.org/doc/ld65-2.html
Looking at the ld65 documentation, the -t (specifies target system) option and -C (specifies custom config file) option can't be used together. What kind of rom does the linker default to when "-t nes" is used?
On my Gentoo Linux development server (with cc65 installed):

Code: Select all

djenkins@hera ~/code/nesyar $ find /usr/local -name "nes*"
/usr/local/lib/cc65/lib/nes.lib
/usr/local/lib/cc65/lib/nes.o
/usr/local/lib/cc65/joy/nes-stdjoy.joy
/usr/local/lib/cc65/asminc/nes.inc
/usr/local/lib/cc65/include/nes.h
/usr/local/share/doc/cc65/nes.cfg
The linker cnfig file is the last ("nes.cfg") file. It is fairly well documented internally. It implements a NES with no mapper (32K prog-rom), 8K char-rom, but adds the 8K of prog-ram ($6000 to $7fff). This linker file also allocates 2 pages of ram ($300 to $4ff) for cc65's internal use with 'C' code.

Personally, I would not use the default linker file, even if I were writing NES software in a mix of C and asm.

In a NES game with a mapper, using ca65, one would give each banked segment a different segment name. The linker will tell you when you try to put too much code (or data) into a segment. The linker will (optionally) produce a "map" file that shows where it put each segment, and list how much free space is in each segment. ld65 can also produce a "debugger" file which is much more detailed.

These files are easy to parse with perl or python. I wrote a small perl script that digests the map file to tell me hos much space I have left in the three segments that I care about (in my non bank-switched game):

Code: Select all

djenkins@hera ~/code/nesyar $ cat tools/free-space.pl
#!/usr/bin/perl -w
# NesYar/tools/free_space.pl

# Analyze ld65 linker "map" file, print how much free space I have
# in various segments.

use strict;
use warnings;
use diagnostics;

my $segment_list = 0;
my $zp_end = 0;
my $kernel_end = 0;
my $vectors_start = 0;
my $data_end = 0;

while (<STDIN>) {
        chomp;
        my $line = $_;

        $segment_list = 1 if ($line =~ m/^Segment list:$/);
        next if (! $segment_list);
        $segment_list = 0 if ($line =~ m/^Exports list:$/);

        if ($line =~ m/^ZEROPAGE[\s]+([0-9A-F]+)  ([0-9A-F]+)  ([0-9A-F]+)$/) {
                $zp_end = hex ($2);
        } elsif ($line =~ m/^KERNEL[\s]+([0-9A-F]+)  ([0-9A-F]+)  ([0-9A-F]+)$/) {
                $kernel_end = hex ($2);
        } elsif ($line =~ m/^VECTORS[\s]+([0-9A-F]+)  ([0-9A-F]+)  ([0-9A-F]+)$/) {
                $vectors_start = hex ($1);
        } elsif ($line =~ m/^DATA[\s]+([0-9A-F]+)  ([0-9A-F]+)  ([0-9A-F]+)$/) {
                $data_end = hex ($2);
        }
}

print "\x1b[0;33m" unless ("$^O" eq "MSWin32");
print sprintf ("ZP avail:     %5d bytes\n", 256 - $zp_end);
print sprintf ("DATA avail:   %5d bytes\n", 2048 - $data_end);
print sprintf ("ROM avail:    %5d bytes\n", $vectors_start - $kernel_end);
print "\x1b[0m" unless ("$^O" eq "MSWin32");
It produces output like this:

Code: Select all

./tools/free-space.pl < ./nesyar.map
ZP avail:        16 bytes
DATA avail:     961 bytes
ROM avail:     7190 bytes
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

FinalZero wrote:What happens if there's more? It's just simply not available? Linker error?
If you try to add more data than what the link script supports, you will get a linker error.
I suppose mappers varied in price too, thus affecting how a development team chose which one to use.
If you want more detail beyond what tokumaru explained, look at one of the few published NES game post-mortems. This one mentions mapper pricing: a scanline counter cost money (because it brought in MMC3), a dedicated switchable bank for DPCM samples cost money (because it also brought in MMC3), PRG RAM cost money (because it brought in a 6264 and at least MMC1), and a battery cost money on top of that.
So, in addition to setting the header correctly, one must set things at the address in the mapper correctly too, in order for a game to run?
Yes. The first part of your startup code that sets up the mapper must be located in a fixed bank. For UNROM (mapper 2), this is $C000-$FFFF. For configurations of MMC3 and MMC6 (mappers 4, 118, and 119), this is $E000-$FFFF. For mappers with no fixed bank, such as A*ROM (mapper 7) or S*ROM (mapper 1), the first part of the code must be repeated at the same place in all banks.
And finally, do I have the following right?: The ca65 assembler creates an object file from assembly files, and then the ld65 linker creates a NES file from the object file?
Yes, just like a typical C toolchain.
http://www.cc65.org/doc/ld65-2.html
Looking at the ld65 documentation, the -t (specifies target system) option and -C (specifies custom config file) option can't be used together. What kind of rom does the linker default to when "-t nes" is used?
It defaults to whatever the built-in link script for NES uses. I believe this built-in link script corresponds to a board that doesn't actually exist (NROM with 8 KiB PRG RAM), though it could be created with circuitry similar to that used in Family BASIC.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

ca65 delegates placement of code in the binary image to the linker.
So then, does .org do anything at all in ca65 asm?
If you try to add more data than what the link script supports, you will get a linker error.
Ok.
If you want more detail beyond what tokumaru explained, look at one of the few published NES game post-mortems. This one mentions mapper pricing: a scanline counter cost money (because it brought in MMC3), a dedicated switchable bank for DPCM samples cost money (because it also brought in MMC3), PRG RAM cost money (because it brought in a 6264 and at least MMC1), and a battery cost money on top of that.
Thanks for the link.
Yes. The first part of your startup code that sets up the mapper must be located in a fixed bank. For UNROM (mapper 2), this is $C000-$FFFF. For configurations of MMC3 and MMC6 (mappers 4, 118, and 119), this is $E000-$FFFF. For mappers with no fixed bank, such as A*ROM (mapper 7) or S*ROM (mapper 1), the first part of the code must be repeated at the same place in all banks.
Ok.
Yes, just like a typical C toolchain.
Ok. It sounds stupid but I didn't realize it was so. It didn't help that other assemblers simply skip the linker step... With this in mind, my project assembles and links, and then plays in FCEUX without generating an error!, but the screen is blank and nothing happens... I don't have the linker set up correctly yet...
It defaults to whatever the built-in link script for NES uses. I believe this built-in link script corresponds to a board that doesn't actually exist (NROM with 8 KiB PRG RAM), though it could be created with circuitry similar to that used in Family BASIC.
Interesting.

-----

@clueless: Thank you for the script. I don't know Perl (I know some Python, but have never written anything major in it), but I have to get around to learning it sometime...

Also, in your thread on the second page there's a link to http://nesdev.com/bbs/viewtopic.php?t=2997 . Where is the patch at/available for download though?

-----

I don't have the linker set up completely yet, so my next push will focus on that, which is bound to generate more questions, which I'll dump here. Stay tuned!

-----

Thank you to all for answering all my questions so far, especially when the average internet board would eat somebody alive for something like this.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

FinalZero wrote:
ca65 delegates placement of code in the binary image to the linker.
So then, does .org do anything at all in ca65 asm?
According to the manual, it turns on absolute code mode temporarily. It's one way of making overlay code intended to be copied to RAM before execution; the other (preferred?) way is to specify a segment in the link script whose load and run addresses differ.
Yes, just like a typical C toolchain.
Ok. It sounds stupid but I didn't realize it was so.
It acts like a C compiler because it's bundled with one ;-)
Thank you to all for answering all my questions so far, especially when the average internet board would eat somebody alive for something like this.
Let me tell you part of why I don't bite newbies: I want to help demonstrate the legality of NES emulators. To be legal under US law, a copying technology has to have a substantial noninfringing use. Debian (and hence Ubuntu) accepts NES emulators, but Fedora doesn't because someone on fedora-legal thinks the three dozen or so noninfringing ROMs on pdroms.de are not substantial compared to the hundreds of infringing ROMs in a typical GoodNES set. But every time we train an eager newbie to be an NES coder or artist, we potentially get one step closer to a substantial library of playable homebrew games.
User avatar
clueless
Posts: 496
Joined: Sun Sep 07, 2008 7:27 am
Location: Seatlle, WA, USA

Post by clueless »

FinalZero wrote:
ca65 delegates placement of code in the binary image to the linker.
So then, does .org do anything at all in ca65 asm?
Yeah, it screws it up, don't use it. Seriously, I tried to use ".org" to create a very specific layout for my zero-page variables, to make viewing them in FCEUX's debugger easier. However, after using ".org" and ".reloc" a few times, the assembler produced unlinkable code. I don't remember the exact error. So I replaced my usage of ".org" with lots of ".aligns" and ".assert" and I hand-tune my variable declaration list whenever an assert fails. I also use lots of "structs", but I'm a C junkie. :)

Ex:

Code: Select all

;; For ease of debugging, we want the "Yar" and "Quotile" at multiples of 16

.align 16
.assert (* = $30), error, "Zero-page layout"
qotile_obj:             .tag    OBJ
qotile_dat:             .tag    QOTILE

.align 16
.assert (* = $40), error, "Zero-page layout"
yar1_obj:               .tag    OBJ
bullet1_obj:            .tag    OBJ
FinalZero wrote:
Yes, just like a typical C toolchain.
Ok. It sounds stupid but I didn't realize it was so. It didn't help that other assemblers simply skip the linker step... With this in mind, my project assembles and links, and then plays in FCEUX without generating an error!, but the screen is blank and nothing happens... I don't have the linker set up correctly yet...
If you wish, post your linker config somewhere and we'll take a look at it.
I also recommend that you enable the linker map file and debug file and review them. They will show you where the linker actually put stuff.

Also just load the ROM into FCEUX and look at it in the debugger. Are the three 6502 vectors ($fffa - $ffff) set properly?

You can use FCEUX's debugger to single-step through the execution of your ROM. FCEUX can also take as input a "symbol file", but I'm yet to write a tool to convert the ld65's ".deb" file into something that pleases FCEUX. When I do, I'll happily share it (but it will be in perl). Tepples might be willing to create one in python, or convert mine. I don't know python.
FinalZero wrote: @clueless: Thank you for the script. I don't know Perl (I know some Python, but have never written anything major in it), but I have to get around to learning it sometime...
Sure! I believe in sharing and giving back to the community and helping anyone that genuinely wants it.
FinalZero wrote: Also, in your thread on the second page there's a link to http://nesdev.com/bbs/viewtopic.php?t=2997 . Where is the patch at/available for download though?
I think that you are slightly mistaken. I did not create that thread, I have no posts in it, and its only one page long.

I read that thread when it came out. I never noticed the bug in ca65. Since my code works fine, I've not bothered to patch. This is what I use:

Code: Select all

djenkins@hera ~/code/nesyar $ ca65 --version
ca65 V2.13.2 - (C) Copyright 1998-2005 Ullrich von Bassewitz
FinalZero wrote: Thank you to all for answering all my questions so far, especially when the average internet board would eat somebody alive for something like this.
Certainly. You are most welcome. We feed rude noobs to NovaYoshi. We keep the good ones.

One more suggestion: Read the ca65 and ld65 docs a few times. Just pick some small section and read about a feature. You might not use it right away, but you'll learn what is available for when you might need it.

You won't need all features either, so if something looks really bizarre, skip it.

If you need to, write your own run-time "assert" logic. When an assertion fails, execute the invalid instruction $02. This will "halt" the CPU. Then set a breakpoint inside FCEUX to trip on invalid opcodes (there is a checkbox for this).
Ex:

Code: Select all

  lda player_energy
  cmp #MAX_ENERGY
  bcc ok
  .byte $02  ;; 6502 "KILL" opcode.
ok:
User avatar
Memblers
Site Admin
Posts: 3901
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers »

tepples wrote: According to the manual, it turns on absolute code mode temporarily. It's one way of making overlay code intended to be copied to RAM before execution; the other (preferred?) way is to specify a segment in the link script whose load and run addresses differ.
I had been curious about the load and run addresses, but have never tried to use them because I (wrongly) thought it had to do with the C compiler's startup code or something. How does that work, in practice?

I've often used .org like this:

Code: Select all

outside_label:
.org $0700
inside_label:
  nop
.reloc

 lda outside_label,x
 sta inside_label,x
 jmp inside_label
But any kind of cleaner method would be nice to know, this is really useful when you have a lot of RAM. I know I've been doing it "wrong", but haven't needed to change that yet.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

The "load address" is where the code is placed in the ROM, and the "run address" is where you're expected to copy it in RAM before running it.
Post Reply