Page 1 of 1

Few questions about Offset-per-tile mode

Posted: Fri Apr 06, 2018 11:07 pm
by srg320
Now I add Offset-per-tile mode in my FPGA SNES, for now I did Offset-per-tile only for BG1 in BGMODE 2 (it works in Tetris Attack, Battletoads in battlemaniacs and SNES burn-in test rom), and I have a few questions.

As I understand, scrolling values in BG3 common to BG1 and BG2, but read 2 times: one for BG1 with BG1HOFS, and one for BG2 with BG2HOFS. Also, I think that in hardware reading scrolling values from BG3 occurs after reading tiles of BG1 and BG2 (in the place where the reading occurs tiles of BG3 and BG4 in BGMODE 0), therefore this scrolling values apply to next tile in row. I'm right or not?

And the second question, what games or test roms using Offset-per-tile in BGMODE 4 and 6?

Re: Few questions about Offset-per-tile mode

Posted: Sat Apr 07, 2018 4:39 am
by dougeff
lidnariq posted a test ROM here which uses modes 0-6.

viewtopic.php?f=12&t=14945

And I think Yoshi's Island uses an offset per tile mode on the "Touch Fuzzy Get Dizzy" level.

Re: Few questions about Offset-per-tile mode

Posted: Sat Apr 07, 2018 7:05 am
by creaothceann
Also in the levels that use lava or stone blocks that move up/down, iirc.

Re: Few questions about Offset-per-tile mode

Posted: Sun Apr 08, 2018 6:47 am
by srg320
Thanks, lidnariq's test rom very helped me.

Re: Few questions about Offset-per-tile mode

Posted: Sun May 20, 2018 10:31 am
by srg320
AWJ wrote:

Code: Select all

0.000004208333333, 0, 0, 1, 0, 1, 0, 0, 1 ; BG2 nametable  .1666 us
0.000004375000000, 0, 0, 0, 0, 0, 0, 0, 1 ; BG1 nametable  .1666 us
0.000004541666667, 0, 1, 0, 1, 0, 0, 0, 1 ; BG3 OPT        .3750 us
0.000004916666667, 1, 0, 0, 0, 0, 0, 0, 1 ; BG2 4bpp       .3750 us
0.000005291666667, 1, 0, 1, 0, 1, 0, 0, 1 ; BG1 4bpp       .3750 us
0.000005666666667, 0, 0, 1, 0, 1, 0, 0, 1 ; BG2 nametable  .2083 us
0.000005875000000, 0, 0, 0, 0, 0, 0, 0, 1 ; BG1 nametable  .1666 us
0.000006041666667, 0, 1, 0, 1, 0, 0, 0, 1 ; BG3 OPT        .3750 us
0.000006416666667, 1, 0, 0, 0, 0, 0, 0, 1 ; BG2 4bpp       .3750 us
0.000006791666667, 1, 0, 1, 0, 1, 0, 0, 1 ; BG1 4bpp       .3750 us
0.000007166666667, 0, 0, 1, 0, 1, 0, 0, 1 ; BG2 nametable
Mode 2 fetches the nametables, then two words of offset-per-tile data (again, we would need the lower address lines to distinguish them), then the patterns. Since the offset-per-tile is fetched after the nametables, each offset-per-tile fetch must apply to the next set of nametable fetches. This explains why offset-per-tile never applies to the first visible tile in a scanline.
If Mode 2 fetches only two words of offset-per-tile data for BG1 and BG2, then how calculate HOFS and VOFS for BG3?

Re: Few questions about Offset-per-tile mode

Posted: Sun May 20, 2018 10:51 am
by psycopathicteen
srg320 wrote:
AWJ wrote:

Code: Select all

0.000004208333333, 0, 0, 1, 0, 1, 0, 0, 1 ; BG2 nametable  .1666 us
0.000004375000000, 0, 0, 0, 0, 0, 0, 0, 1 ; BG1 nametable  .1666 us
0.000004541666667, 0, 1, 0, 1, 0, 0, 0, 1 ; BG3 OPT        .3750 us
0.000004916666667, 1, 0, 0, 0, 0, 0, 0, 1 ; BG2 4bpp       .3750 us
0.000005291666667, 1, 0, 1, 0, 1, 0, 0, 1 ; BG1 4bpp       .3750 us
0.000005666666667, 0, 0, 1, 0, 1, 0, 0, 1 ; BG2 nametable  .2083 us
0.000005875000000, 0, 0, 0, 0, 0, 0, 0, 1 ; BG1 nametable  .1666 us
0.000006041666667, 0, 1, 0, 1, 0, 0, 0, 1 ; BG3 OPT        .3750 us
0.000006416666667, 1, 0, 0, 0, 0, 0, 0, 1 ; BG2 4bpp       .3750 us
0.000006791666667, 1, 0, 1, 0, 1, 0, 0, 1 ; BG1 4bpp       .3750 us
0.000007166666667, 0, 0, 1, 0, 1, 0, 0, 1 ; BG2 nametable
Mode 2 fetches the nametables, then two words of offset-per-tile data (again, we would need the lower address lines to distinguish them), then the patterns. Since the offset-per-tile is fetched after the nametables, each offset-per-tile fetch must apply to the next set of nametable fetches. This explains why offset-per-tile never applies to the first visible tile in a scanline.
If Mode 2 fetches only two words of offset-per-tile data for BG1 and BG2, then how calculate HOFS and VOFS for BG3?
It doesn't. Mode 2 only has 2 layers.

Re: Few questions about Offset-per-tile mode

Posted: Sun May 20, 2018 11:13 am
by srg320

Code: Select all

HOFS = X + BGnHOFS
VOFS = Y + BGnVOFS
ValidBit = 0x2000 for BG1, or 0x4000 for BG2
if (!IsFirst8x8Tile(BGn, HOFS)) {
  /* Hopefully these calculations are right... */
  Hval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS)
  Vval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS + 8)
  if (Hval&ValidBit) HOFS = (HOFS&7) | ((X&~7) + (Hval&~7))
  if (Vval&ValidBit) VOFS = Y + Vval
}
Pixel[X,Y] = GetPixel(Get8x8Tile(BGn, HOFS, VOFS), HOFS, VOFS)
What does means n in this formula?

In BSNES source BG3's offsets calculate separately for BG1 and BG2, that is 4 words of offset-per-tile data reads from BG3 tilemap.

Code: Select all

if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
    uint16 offset_x = (x + (hscroll & 7));

    if(offset_x >= 8) {
      unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
      unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
      unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000);

      if(self.regs.bgmode == 4) {
        if(hval & valid_mask) {
          if((hval & 0x8000) == 0) {
            hoffset = offset_x + (hval & ~7);
          } else {
            voffset = y + hval;
          }
        }
      } else {
        if(hval & valid_mask) hoffset = offset_x + (hval & ~7);
        if(vval & valid_mask) voffset = y + vval;
      }
    }
  } 

Re: Few questions about Offset-per-tile mode

Posted: Sun May 20, 2018 1:00 pm
by lidnariq
srg320 wrote:If Mode 2 fetches only two words of offset-per-tile data for BG1 and BG2, then how calculate HOFS and VOFS for BG3?
In the offset-per-tile modes, BG3 doesn't contain a nametable. Instead it literally contains the horizontal and vertical offsets for the lower-numbered backgrounds.

Re: Few questions about Offset-per-tile mode

Posted: Sun May 20, 2018 11:29 pm
by srg320
Maybe I'm stupid, maybe my bad English is the problem. I formulate a question on another.

For example, in Mode 2 enabled BG1 and BG2 with different scroll values and size 64x32. How to calculate the position in BG3 Map memory region to get the horizontal and vertical offsets for BG1 and BG2?

Re: Few questions about Offset-per-tile mode

Posted: Thu May 24, 2018 1:00 am
by srg320
So, I asked and I answer. OPT data read from BG3 Map Table, 3 (4 if tile size 16x16) lower bits of scrolling offset not use in this case. Therefore no need in addition lower bits BG1(2)HOFS to BG3 horizontal scrolling offset. I think the formula should be that:

Code: Select all

HOFS = X + BGnHOFS
VOFS = Y + BGnVOFS
ValidBit = 0x2000 for BG1, or 0x4000 for BG2
if (!IsFirst8x8Tile(BGn, HOFS)) {
  /* Hopefully these calculations are right... */
  Hval = GetTile(BG3, ((X-8)&~7)+BG3HOFS, BG3VOFS)
  Vval = GetTile(BG3, ((X-8)&~7)+BG3HOFS, BG3VOFS + 8)
  if (Hval&ValidBit) HOFS = (HOFS&7) | ((X&~7) + (Hval&~7))
  if (Vval&ValidBit) VOFS = Y + Vval
}
Pixel[X,Y] = GetPixel(Get8x8Tile(BGn, HOFS, VOFS), HOFS, VOFS)
With this variant, need to read only 2 words of OPT data like in real hardware.
I applied this formula to my FPGA project and it works.