8x16 and whatever else unreg wants to know

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: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tepples »

If you're calling subroutines in RAM, whether for self-modifying code or for having additional fixed bank space, you have to copy them to RAM before you call them. See "LOAD and RUN addresses" in ld65 Users Guide.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

tepples wrote:If you're calling subroutines in RAM, whether for self-modifying code or for having additional fixed bank space, you have to copy them to RAM before you call them. See "LOAD and RUN addresses" in ld65 Users Guide.
unregistered wrote:After moving the_function that needs to be in PRG-RAM into an unused bank, and writting a short new-function to copy the_function into an appropriate spot in bank 0 of PRG-RAM and change its jmp correctly, and creating a label to mark that appropriate spot... the game assembles, but reset: still begins with a bunch of zeros. Any idea why?
See my function has already been copied to RAM (for self-modifying code), though I can't see that bc our game never makes it through reset. :) But, thank you tepples for making it clear that subroutines can be called in RAM on the NES! :D I'll visit your link. :) ...maybe the PPU registers are set incorrectly...
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

Ah! So my asm6_ has successfully created a faulty .nes file (lots of brks), but when trying to assemble our game with asm6 it quits assembling after pass 1...

tepples, can subroutines be run when they are inside 'Save RAM' $6000-$7000 in MMC1?

The site you linked to must be experiencing problems... I'll try again. :)


edit: sigh, guess I caused my asm6_ to sometimes assemble corrupt binaries. :( tokumaru recommends asm6:
tokumaru[color=#FF8040], [url=https://forums.nesdev.com/viewtopic.php?p=110164#p110164]here[/url],[/color] wrote:NESASM and ASM6 are equally simple IMO: both can create a ROM from nothing more than a single ASM file, without configuration files or complex command lines. If you're going for simplicity, you should pick one of these 2. I prefer ASM6because NESASM uses non-standard 6502 syntax for some things and it has been known to fail silently in the past, producing corrupt binaries without reporting any errors (some people say these bugs have been fixed).
I need to fix this sometime. :oops:
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tepples »

I was under the impression that Nintendo's big four FDS-to-cartridge ports (Metroid, Kid Icarus, The Legend of Zelda, and Super Mario Bros. 2: Mario Madness) run code in RAM at $6000. If you have dumped a game with such RAM, you can set an execute breakpoint on $6000-$7FFF to see for yourself.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 and whatever else unreg wants to know

Post by tokumaru »

Both ASM6 and NESASM have quirks that will cause you to scratch your head sometimes... You just have to keep looking for the cause of the problem so you can get to know your tools better.

It's definitely possible to run code at $6000-$7FFF, but you need to be careful when setting up the addresses for this code. Like tepples said, ca65 has a way for you to define the LOAD address (where the code is stored in ROM) and the RUN address (the PRG-RAM address you'll copy it to), but in ASM6 you have to do this manually, possibly like this:

Code: Select all

  ;(...)

;save ROM address for later
ROMAddress = $

  ;change address to PRG-RAM
  .base $6000

SubroutineStart:

  ;(...)

SubroutineEnd:

  ;restore ROM address, taking the code size into consideration
  .base ROMAddress + (SubroutineEnd - SubroutineStart)
If you don't change the address to PRG-RAM, references to absolute addresses in that subroutine will use the ROM address, which is not where the subroutine be running from. And if you forget to take the subroutine's size into consideration when restoring the ROM address, the final size of the ROM bank will be wrong, resulting in an invalid NES file.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

Ah, so PRG-RAM doesn't work like PRG-ROM? That's pretty obvious, but when setting up PRG-RAM like you showed, tokumaru, the address, changed with .base to PRG-RAM, helps absolute addresses be correct inside that subroutine, but we have to adjust the PRG-ROM address bc that subroutine is also in PRG-ROM? The addresses in the subroutine are pointing to PRG-RAM so the game will never get mixed up and try to run that section of PRG-ROM?

It seems I incorrectly set up the 4 PRG-RAM banks so that they were exactly like the PRG-ROM banks... bank0:

Code: Select all

.base $6000
;seei is transfered here form bank 13
seei_:

.pad $6FF0
-reset_part1:
  sei
  ldx #$FF
  txs ;set the stack pointer
  stx $8000 ;reset the mapper
  jmp reset_part2 ; must be in $C000-$FFED
.word vblank, -reset_part1, irq
and then bank1 through bank3 are then set up the same way (without the seei_ label).

Thank you so much tokumaru! :D Going to try setting it up like you recommended. :)
edit: It seems my code wouldn't work anyways bc RAM never holds anything you want unless you load/store into it from ROM, like booker and you all taught me. :) ENDEDIT.

tepples, your link always worked; rather, I forgot what I had learned earlier that github links don't work on this old computer. :oops:
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 8x16 and whatever else unreg wants to know

Post by tokumaru »

Yeah, the complication comes from the fact that even though the code is supposed to run from RAM (which means that the PC must be set to the correct RAM section so all absolute references are correct), it's still stored in ROM, taking up space there.

I don't know if this is what you're doing, but you can't have that PRG-RAM code stored separately in the NES file, it must be stored within the PRG-ROM space. My example was a generic one that allows PRG-RAM code to be stored anywhere in PRG-ROM, but since you're working with full banks, you could just use the lower part of a PRG-ROM bank for your PRG-RAM stuff and manually .base the address to, say, $D000 ($1000 bytes after $C000) for the rest of the PRG-ROM. That way you won't need all the label math from my example. Either way, PRG-ROM banks should remain the same size as before, and any PRG-RAM code you have must be stored inside them, but with the correct PC value for the address where that code will run from.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

YEAY! PRAISE GOD!! :D My function is successfully running inside PRG-RAM! :) Thank you so much tokumaru! Now to attempt to make it self-modify itself. This is so much fun! :)
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

It self-modifies itself successfully! :D Have to reduce the blinking, but one more thing works! PRAISE GOD!! :D

ok, I'll be silent now. :)
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

After writting an address to $2006, so that writes to $2007 go to the correct spot on the screen, do I have an unlimited amount of time to write to that spot on the screen?

tepples has told me that writes to registers and RAM last indefinitly, until loss of power or the data is overwritten... $2006 is a PPU register, but can I quit drawing a screen and then resume at the next vblank without having to write $2006 before each section of the screen is drawn? That would be so cool! :)

edit: this would only be a valid question if $2006 was incremented after every $2007 write; I'll check the wiki :) ENDEDIT.


I guess tepples would recommend I try this myself.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tepples »

Yes, the VRAM address that you loaded through $2006 is incremented by 1 or 32 (depending on $2000 setting) after each $2007 write.

If rendering is turned off through $2001, you have as long as you need after setting the VRAM address to write data to $2007. If rendering is turned on, however, the PPU will continuously overwrite the VRAM address during rendering. This means you have to fit the upload into vertical blanking and reset the scroll position through $2005 and $2000 afterward.

One exception to RAM writes lasting until power loss is dynamic random access memory (DRAM). Unlike static random access memory (SRAM), values stored in DRAM will decay into unspecified values if not refreshed every so often, but more DRAM will fit on a chip of a given size than SRAM. Unlike other memory in the NES, OAM is DRAM, and OAM on the NTSC PPU is particularly touchy. The PPU automatically refreshes OAM when rendering is on, but turning rendering off for much longer than the duration of one vblank (1.3 ms) will cause OAM values to begin to decay.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

tepples wrote:Yes, the VRAM address that you loaded through $2006 is incremented by 1 or 32 (depending on $2000 setting) after each $2007 write.

If rendering is turned off through $2001, you have as long as you need after setting the VRAM address to write data to $2007. If rendering is turned on, however, the PPU will continuously overwrite the VRAM address during rendering. This means you have to fit the upload into vertical blanking and reset the scroll position through $2005 and $2000 afterward.
Ah so we also have to store that VRAM address and rewrite it to $2006 before drawing each section of the screen, since rendering will be enabled bc I'm going to try only writing the screen during vblank. You said earlier that we should try to write sections in 2200 cycles... it that the length of vblank? If so it would take around 8 frames for a screen to be written. :)
tepples wrote:One exception to RAM writes lasting until power loss is dynamic random access memory (DRAM). Unlike static random access memory (SRAM), values stored in DRAM will decay into unspecified values if not refreshed every so often, but more DRAM will fit on a chip of a given size than SRAM. Unlike other memory in the NES, OAM is DRAM, and OAM on the NTSC PPU is particularly touchy. The PPU automatically refreshes OAM when rendering is on, but turning rendering off for much longer than the duration of one vblank (1.3 ms) will cause OAM values to begin to decay.
That's very cool to now know, thank you tepples! :D
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

tepples[color=#FF8040], on page 100,[/color] wrote:The 16,536 cycles need to happen while rendering is turned off. Turning rendering off and on rapidly will cause flicker, which could trigger seizures in sensitive players. If you want to update anything without cutting to a blank screen, you'll need to break the update into shorter chunks that fit into 2200 cycles or so. For example, the Action 53 menu and 240p Test Suite help system update one 128-byte line of VWF text per frame, taking roughly a third of a second in all to get the new text up. I guess you could heavily letterbox the display so that only about 120 scanlines are visible in order to increase the update time every frame, but I doubt that'd go over very well.
You say, "Turning rendering off and on rapidly will cause flicker... ." tepples, waiting a frame with rendering unchanged, is that a long enough wait to eliminate flicker? Please define "rapidly" :) or I guess I could just attempt this myself. :)

It seems that waiting 1 frame is much quicker and easier, less cycles, than getting my code to wait 8 frames while drawing the screen in sections (even though that new code might work if I would complete its changing-$2006-appropriatelyness). This waiting a frame just occurred to me.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 8x16 and whatever else unreg wants to know

Post by tepples »

If you're cutting to a different scene, such as if the player character went off the side of the map or into a door, the player won't mind if the screen is off for a few frames. (If the transition occurs mid-jump, it needs to be faster.) But if you're repeatedly updating a single scene, on for 7 frames and off for 1 and repeat, that's a bit more annoying. What are you actually trying to do by updating the entire map? Are you trying to show the player character entering a new area, or are you trying to animate changes to the background in the same area, or are you trying to do neither of the above (in which case please describe)?
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: 8x16 and whatever else unreg wants to know

Post by unregistered »

We're trying to animate changes to the background in the same Nametable. Would turning rendering off, drawing the entire screen, turning rendering on, waiting a frame, turning rendering off, drawing the entire next screen, and turning rendering on eleminate the flicker? I'm going to guess no bc that's a simple solution. :) But, could it work?
Post Reply