nesdev.com
http://forums.nesdev.com/

CHR-RAM in UNROM
http://forums.nesdev.com/viewtopic.php?f=2&t=16580
Page 1 of 1

Author:  Diskover [ Sun Oct 15, 2017 2:37 am ]
Post subject:  CHR-RAM in UNROM

I'm doing tests at UNROM.

Compile with CC65.

I want to update a tile (for example, 0x00) of CHR 'on the fly' without turning the screen off.

How can I access the CHR-RAM to tell it to replace the 0x00 tile with another?
How can I access the CHR-RAM to tell it to move the graph to the left, right, up or down the tile 0x00?

Author:  rainwarrior [ Sun Oct 15, 2017 4:14 am ]
Post subject:  Re: CHR-RAM in UNROM

I don't know what you mean by "move the graph", but each tile is 16 bytes (8 x 8 bits x 2 planes), so the PPU address of any given tile is just 16x its index.

E.g. tile $53 begins at $0530 or $1530, depending on which CHR page you're using.

So, to write a new tile, just set the address with two writes to $2006, and then write the 16 bytes to $2007.

To do it without turning rendering off, you simply need to do this during vblank (probably in your NMI handler), just like you would for nametable updates.

Author:  tokumaru [ Sun Oct 15, 2017 12:47 pm ]
Post subject:  Re: CHR-RAM in UNROM

Do note that "updating tiles on the fly without turning the screen off" is a pretty slow processes, specially if you're not unrolling loops, so don't expect to be able to change a lot of tiles per frame. If you use the vblank interval exclusively for updating tiles (no pallette, NT, AT or sprite updates at all), you'll be able to update around 16 tiles at best.

Author:  na_th_an [ Sun Oct 15, 2017 1:13 pm ]
Post subject:  Re: CHR-RAM in UNROM

If you are using neslib to do the updates you may use the common method you use to update the nametables, this is, the set_vram_update function and the update list array. Just be sure to use the NT_UPD_HORZ switch alongside the MSB and add the 16 bytes to be updated afterwards, something like this:

Code:
// Before your main loop
set_vram_update (update_list);

[...]

// Calculate the address
gp_addr = pattern_number << 4; // Add 0x1000 for the second pattern table

// the ul pointer points to the current position in the update_list
*ul ++ = MSB (gp_addr) | NT_UPD_HORZ
*ul ++ = LSB (gp_addr);
*ul ++ = byte0;
...
*ul ++ = byte15;

// During the next VBLANK the bytes will be sent to VRAM
*ul = NT_UPD_EOF;
ppu_wait_update ();

[...]



I have never done this but I understand it should work. Note that, as mentioned, you will be able to update just a few patterns using this method (it could be as few as just a couple or three patterns!). It's better to add custom code to your NMI routine to handle this.

Author:  Diskover [ Tue Oct 17, 2017 1:15 am ]
Post subject:  Re: CHR-RAM in UNROM

No, what I'm talking about is being able to change the tiles of CHR-RAM.

Modifying VRAM I have already been able to do something, but what I need is to change tiles in the CHR-RAM to be able to get animated effects.

Author:  calima [ Tue Oct 17, 2017 1:57 am ]
Post subject:  Re: CHR-RAM in UNROM

CHR-RAM is VRAM.

Author:  tepples [ Tue Oct 17, 2017 6:16 am ]
Post subject:  Re: CHR-RAM in UNROM

It's mostly the same deal.

  • To write to nametables, you load an address $2000-$2FFF into PPU port $2006 and then start writing bytes through $2007.
  • To write to pattern tables, you load an address $0000-$1FFF into PPU port $2006 and then start writing bytes through $2007.

If you're using a generic update buffer system, it should work for both, with two exceptions:

  • If the buffer format uses bits 13 and 12 of the destination address for behavior flags instead of the destination address, it won't work.
  • If the buffer format uses an address $0000-$00FF for terminating (as Nintendo's does), you may not be able to replace the first 16 tiles of the first pattern table. You may, however, be able to write to $4000-$40FF, which the PPU mirrors to $0000-$00FF.

Author:  Diskover [ Wed Oct 18, 2017 2:28 pm ]
Post subject:  Re: CHR-RAM in UNROM

I do not know if it's a language problem, but I do not understand you very much.

For now I have managed to do this: Basically drawing on the tile, although I can not write on the tile I want, I always write in the 0x00 and sometimes it is also written in other tiles without much sense.

Code:
//x starts at 0

if(joypad1 & PAD_LEFT)      --x;         
if(joypad1 & PAD_RIGHT)   ++x;

PPU_ADDRESS = 0x20;       //Here I am writing $2000?

      if(x == 0){         
         PPU_DATA    = 0x80;
         PPU_DATA    = 0x80;
         PPU_DATA    = 0x80;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x80;
         PPU_DATA    = 0x80;
         PPU_DATA    = 0x80;
         PPU_DATA    = 0x80;
         
      }
   
      if(x == 1){
         PPU_DATA    = 0x40;
         PPU_DATA    = 0x40;
         PPU_DATA    = 0x40;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x40;
         PPU_DATA    = 0x40;
         PPU_DATA    = 0x40;
         PPU_DATA    = 0x40;
         
      }
      
      if(x == 2){
         PPU_DATA    = 0x20;
         PPU_DATA    = 0x20;
         PPU_DATA    = 0x20;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x20;
         PPU_DATA    = 0x20;
         PPU_DATA    = 0x20;
         PPU_DATA    = 0x20;
         
      }
      
      if(x == 3){
         PPU_DATA    = 0x10;
         PPU_DATA    = 0x10;
         PPU_DATA    = 0x10;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x10;
         PPU_DATA    = 0x10;
         PPU_DATA    = 0x10;
         PPU_DATA    = 0x10;
         
      }
      
      if(x == 4){
         PPU_DATA    = 0x08;
         PPU_DATA    = 0x08;
         PPU_DATA    = 0x08;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x08;
         PPU_DATA    = 0x08;
         PPU_DATA    = 0x08;
         PPU_DATA    = 0x08;
         
      }
      
      if(x == 5){
         PPU_DATA    = 0x04;
         PPU_DATA    = 0x04;
         PPU_DATA    = 0x04;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x04;
         PPU_DATA    = 0x04;
         PPU_DATA    = 0x04;
         PPU_DATA    = 0x04;
         
      }
      
      if(x == 6){
         PPU_DATA    = 0x02;
         PPU_DATA    = 0x02;
         PPU_DATA    = 0x02;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x02;
         PPU_DATA    = 0x02;
         PPU_DATA    = 0x02;
         PPU_DATA    = 0x02;
         
      }
      
      if(x == 7){
         PPU_DATA    = 0x01;
         PPU_DATA    = 0x01;
         PPU_DATA    = 0x01;
         PPU_DATA    = 0xFF;
         PPU_DATA    = 0x01;
         PPU_DATA    = 0x01;
         PPU_DATA    = 0x01;
         PPU_DATA    = 0x01;
         
      }
      
      if(x == 8) x = 0;
      if(x == 255) x = 7;
      
      Reset_Scroll();


What I get is this:
Image


ROM:
Attachment:
prueba1.nes [64.02 KiB]
Downloaded 9 times

Author:  team_disposable [ Wed Oct 18, 2017 3:08 pm ]
Post subject:  Re: CHR-RAM in UNROM

tl;dr - Just quickly looking at your code, you only seem to be writing the first part of the address to PPU_ADDRESS - you need to write the whole 16 bit address. Secondly, presumably because it's a demo, your code has movement functions being called before the update to CHR-RAM - I would recommend you don;t do this, and call CHR-RAM updates first, at the very top, as NMI update time is limitedand if it overruns, you will get horrible graphical glitches to your tiles.

Hi Diskover, the game you're porting looks ace! I look forward to playing it!

I've done quite a lot of CHR-RAM updating for animations -

First I made a lookup table of the address of the graphic I want to write in to CHR-RAM, and the address it should be written to - here's an excerpt:

Code:
;address in rom high, address in rom low, destination address high, destination address low
tile_lookup:
.byte <spike1_chr, >spike1_chr, 22, 16
 .byte <spike2_chr, >spike2_chr, 22, 16
 .byte <spike3_chr, >spike3_chr, 22, 16
.byte <coin1_chr, >coin1_chr, 18, 16
.byte <coin2_chr, >coin2_chr, 18, 16
.byte <coin3_chr, >coin3_chr, 18, 16
.byte <coin4_chr, >coin4_chr, 18, 16
.byte <fivecoin1_chr, >fivecoin1_chr, 18, 32
.byte <fivecoin2_chr, >fivecoin2_chr, 18, 32
.byte <fivecoin3_chr, >fivecoin3_chr, 18, 32
.byte <fivecoin4_chr, >fivecoin4_chr, 18, 32


Secondly, I wrote a function in assembly to load the tile when given the name as a parameter:

Code:
_copy_tile:
 tay
 lda tile_lookup, y ; load the source address into a pointer in zero page
 sta src
 iny
 lda tile_lookup,y
 sta src+1
 iny
 lda tile_lookup,y
  sta PPUADDR  ; load the destination address into the PPU
  iny
  lda tile_lookup,y
  sta PPUADDR
  ldy #0
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
   
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
   
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
   
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
 
  lda (src),y  ; copy one byte
  sta PPUDATA
  iny
  rts   


Thirdly, I then export this from the assembly, forthly I write a function header in C, and then finally call it in C like this:

Code:
copy_tile(chr_heart1);


That's it - just make sure you're calling copy_tile in the NMI.

Hopefully this is of some help, if not let me know!

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/