0x is usually used to refer to values (numbers stored at addresses) whereas $ is used to refer to addresses themselves.
There is also a difference between CPU address and ROM address.
8-bit CPUs (such as used in the NES) will only have a 16-bit addressing capability (thus 16 bits = 4 hex digits). That means typically CPUs in cartridge-based 8-bit consoles would have a 32KB ROM limit (16 bits equals 64KB, but consoles usually needed to reserve some space for RAM, and if they were using memory-mapped IO, reserving some space for that, too. It was usually logically simplest to just divide that memory map down the middle. Even if it was something like the Genesis memory map, where as I understand, battery-backed games usually split the 4MB address space down the middle, even though a 2MB save would've been **** huge for a 16-bit era game.
To have ROM bigger than 32KB usually required a mapper. Mapper breaks the ROM (which itself can be any size as long as mapper can support it) down into banks, so that while only 32KB worth of "banks" can be accessible at any one point, the game can immediately swap them out as needed.