What is wrong with my metatile routine? (ASM6 quirk)

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

samwise970
Posts: 20
Joined: Tue Oct 17, 2017 12:13 am

What is wrong with my metatile routine? (ASM6 quirk)

Post by samwise970 » Wed Feb 06, 2019 1:07 pm

EDIT: My problem has been solved! Among other things, I was stupid and tried to TYX. Interestingly enough, ASM6 seems to have read that as a label and didn't fail on compile.

Hey all,

I've been working on this for a while, and I've hit a point where I just don't know what to fix.

I'm working on a metatile routine. Metatile is 2x2 tiles, and it seemed to work alright. However, now I'm working on adding attribute mapping based on the metatile, and it's all messed up.

Here's my metatile attribute routine. The idea is that it's supposed to read the metatile number from the game map in "metascr", and then use that index to lookup the palette number (0 - 3) for the corresponding metatile in "METAattr". Right now, all of the metatiles should be with palette 0 except for the blank sky, #$15, which is palette 01. Then I'm shifting bits to the left, and adding the resulting number to the attribute number I have stored. At the end, I'm writing the number to $2007. I think I'm starting at the right address in $2006, just doing what NerdyNights had.

Var attrtemp is used to store my attribute byte, and var attrx is used to store my X counter before I TAX.

Code: Select all

LoadMETAattr:
  LDA $2002		;read PPU to reset high/low latch
  LDA #$23
  STA $2006		;write hight byte of $23C0 address
  LDA #$C0
  STA $2006		;write low byte of $23C0 address
  LDX #$00
  LDY #$00
LoadMETAattrLoop:
  TYX
  LDA metascr, x	;load data from metatable
  STX attrx
  TAX
  LDA METAattr, x
  STA attrtemp		;load first attr
  LDX attrx
  INX
  LDA metascr, x
  STX attrx
  TAX
  LDA METAattr, x
  ASL A
  ASL A				;multiply second attr by 4
  CLC
  ADC attrtemp
  STA attrtemp
  LDX attrx
  DEX
  TXA
  CLC
  ADC #$10
  TAX
  LDA metascr, x
  STX attrx
  TAX
  LDA METAattr, x
  ASL A
  ASL A
  ASL A
  ASL A				;multiply third attr by 16
  CLC
  ADC attrtemp
  STA attrtemp
  LDX attrx
  INX
  LDA metascr, x
  STX attrx
  TAX
  LDA METAattr, x
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A				;multiply fourth attr by 64
  CLC
  ADC attrtemp
  STA attrtemp
  STA $2007
  INY
  INY
  CPY #$10
  BNE LoadMETAattrLoop
  JMP METAattrdone
When I compile and run, I get something really weird. My loop increments Y twice at the end, and should end when Y==16, so I'm only expecting to apply attributes to the first 8 32x32 attribute squares (if this was working correctly, the first row of 16px metatiles would be palette 0, the second would be palette 1, all subsequent would be palette 0). But it seems that instead, random 32px attribute squares are of only palette 1, all over the screen. To compound this, more and more attribute squares are changed to palette 1 when I reset. Making things weirder still, when I change to PAL mode, I can see that there is a single background tile on the top which is completely incorrect, and this tile changes position when I reset.

I know there are multiple things I must be doing wrong. I know this means I'm not handling my reset correctly, but I don't know enough to fix it. Could someone out there walk me through the changes I need to make to apply this correctly? I realize this is a lot to ask.

Attached is the entire ASM file. It's not too huge, based on the NerdyNights week 6, and in ASM6 symtax.

EDIT: Also attached are the CHR and NES files if you want to test it out.
Attachments
abduction.chr
(8 KiB) Downloaded 109 times
metatile_attr.nes
(24.02 KiB) Downloaded 113 times
metatile_attr.asm
(12.42 KiB) Downloaded 113 times
Last edited by samwise970 on Wed Feb 06, 2019 4:20 pm, edited 2 times in total.

unregistered
Posts: 1038
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: What is wrong with my metatile routine?

Post by unregistered » Wed Feb 06, 2019 1:40 pm

Note: There isn't a tyx available in 6502. You could tya, tax... or, like tokumaru taught me, you could set up a page of ROM (i.e. $E0xx) to hold its low byte value... i.e. $E000 holds #$00, $E001 holds #$01, etc... and then use ldx $E000, y. :)

User avatar
dougeff
Posts: 2617
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: What is wrong with my metatile routine?

Post by dougeff » Wed Feb 06, 2019 1:46 pm

Also, don't calculate this during v-blank (inside the NMI). Preferably, you would pre-calculate this and store it in a buffer, and then, during NMI just copy the changes quickly.

Maybe it works now, but maybe you try to add something, like palette swapping, and this runs into the frame, and fails.

One more thing.
6 asl's is the same as

lsr
ror a
ror a

and "ora" is a bit faster than "clc adc" for this.
Last edited by dougeff on Wed Feb 06, 2019 1:51 pm, edited 1 time in total.
nesdoug.com -- blog/tutorial on programming for the NES

samwise970
Posts: 20
Joined: Tue Oct 17, 2017 12:13 am

Re: What is wrong with my metatile routine?

Post by samwise970 » Wed Feb 06, 2019 1:49 pm

Some of the problem seems to lay in lines 170,171 & 224,225 of my code.

170,171

Code: Select all

  LDA #%00000000   ; disable sprites, disable background, no clipping on left side
  STA $2001 
224,225

Code: Select all

  LDA #%00011110   ; enable sprites, enable background, no clipping on left side
  STA $2001  
I was disabling rendering and enabling it again before and after my main Metatile routine. When I ran the attribute routine, I had rendering already on.
However, it doesn't seem to have totally fixed the problem. It looks a lot better, but only the first 32px attribute tile is what I'd expect (top two 16px tiles are palette 0, bottom two are palette 1). The rest of the attribute tiles are all palette 1, top and bottom...

Attached is a revised .NES

after I uploaded the file I saw unregistered's reply. I'll take that into account and see if it fixes anything!

Doug, thanks as always... I didn't think I was calculating inside the NMI.. clearly I need more knowledge on NMI and vblank
Attachments
metatile_attr.nes
(24.02 KiB) Downloaded 114 times

samwise970
Posts: 20
Joined: Tue Oct 17, 2017 12:13 am

Re: What is wrong with my metatile routine?

Post by samwise970 » Wed Feb 06, 2019 2:02 pm

unregistered was right. I should've known about TYX. Changing to TYA and then TAX fixed the issue. It seems to work now!

https://wiki.nesdev.com/w/index.php/The_frame_and_NMIs
I see what you're talking about now Doug. I'm drawing to $2007, so that code has to be in vblank. And there's not much vblank time, so I'm wasting it on logic.

You're saying I need to write to a buffer var instead of directly to $2007, then write to $2007 all at once, right? What size does my buffer need to be? Hopefully it doesn't need to be the entire size of the screen (960 bytes). Can I have a 32 byte buffer and write each row at a time?

User avatar
koitsu
Posts: 4216
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: What is wrong with my metatile routine?

Post by koitsu » Wed Feb 06, 2019 2:10 pm

I'm curious: what assembler are you using that permitted you to use the 65816 tyx ($bb) opcode? If it's a 65816 assembler that doesn't offer a way to enable a strict 6502 (not 65c02!) mode, then OK, mistakes happen. Else if it does offer such (and is used), or it's a 6502 assembler, then that's incredibly broken and should be reported.

samwise970
Posts: 20
Joined: Tue Oct 17, 2017 12:13 am

Re: What is wrong with my metatile routine?

Post by samwise970 » Wed Feb 06, 2019 2:13 pm

koitsu wrote:I'm curious: what assembler are you using that permitted you to use the 65816 tyx ($bb) opcode? If it's a 65816 assembler that doesn't offer a way to enable a strict 6502 (not 65c02!) mode, then OK, mistakes happen. Else if it does offer such (and is used), or it's a 6502 assembler, then that's incredibly broken and should be reported.
I'm using ASM6 v1.6

EDIT: On further investigation, I think ASM6 doesn't process commands that it doesn't recognize. I tried imputting some garbage, just randomly typed LDO, and it still compiled with no affect on the program. It's not that ASM6 was using the TYX, it just was skipping over that line since it didn't recognize TYX as a command.

User avatar
koitsu
Posts: 4216
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: What is wrong with my metatile routine?

Post by koitsu » Wed Feb 06, 2019 2:32 pm

samwise970 wrote:I'm using ASM6 v1.6
Congratulations, you've found a quirk/bug in the assembler. The parser is treating lines that don't match opcodes as labels. In other words, it thinks tyx is a label:

Code: Select all

D:\downloads\x>\console\bin\asm6

asm6 1.6

Usage:  asm6 [-options] sourcefile [outputfile] [listfile]

    -?          show this help
    -l          create listing
    -L          create verbose listing (expand REPT, MACRO)
    -d<name>    define symbol
    -q          quiet mode (no output unless error)

See README.TXT for more info.

D:\downloads\x>\console\bin\asm6 test.asm test.o test.lst
pass 1..
test.o written (12 bytes).
test.lst written.

D:\downloads\x>type test.lst

                                  .org $8000
08000
08000                           main:
08000 78                          sei
08001 18                          clc
08002                             tyx       ; this should ideally fail to assemble
08002 A9 01                       lda #$01
08004 A9 02                       lda #<tyx
08006 85 00                       sta $00
08008 A9 80                       lda #>tyx
0800A 85 01                       sta $01
0800C
asm6f (version as of this writing) suffers from the same problem.

In short: opcode typos or existence assumptions in asm6 v1.6 can (will) result in the assembler treating such mistake as a label, resulting in successful assembly (because it's perfectly OK to have a label on a line by itself) rather than an error. Improving the parser (making it substantially more strict) is the only way to accomplish this. There are some ways to kludge-fix this but that subject's off-topic for this thread.

User avatar
gauauu
Posts: 660
Joined: Sat Jan 09, 2016 9:21 pm
Location: Central Illinois, USA
Contact:

Re: What is wrong with my metatile routine?

Post by gauauu » Wed Feb 06, 2019 2:58 pm

koitsu wrote:
samwise970 wrote:I'm using ASM6 v1.6
Congratulations, you've found a quirk/bug in the assembler. The parser is treating lines that don't match opcodes as labels. In other words, it thinks tyx is a
Wow, that's disastrous. That means typos compile happily and break silently. How is this not already widely known?

samwise970
Posts: 20
Joined: Tue Oct 17, 2017 12:13 am

Re: What is wrong with my metatile routine?

Post by samwise970 » Wed Feb 06, 2019 3:02 pm

Sick! Thanks for the explanation.

If ASM6 is treating "TYX" as a label, does that mean I could later write something like

Code: Select all

  LDX #$00
TYX
  INX
  CPX #$10
  BNE TYX
Talk about confusing.

In my mind, this could be fixed by simply checking labels for a colon ":" at the end. If it did that, then

Code: Select all

  LDX #$00
TYX:
  INX
  CPX #$10
  BNE TYX
would compile, and my first example would fail. But IDK.

User avatar
slembcke
Posts: 170
Joined: Fri Nov 24, 2017 2:40 pm

Re: What is wrong with my metatile routine?

Post by slembcke » Wed Feb 06, 2019 3:03 pm

dougeff wrote:Also, don't calculate this during v-blank (inside the NMI).
Yeah... and don't try and save memory by reading attribute table back back from the PPU either. In the end I had > 1k of memory sitting unused, and I wrote this monstrosity to save 64 bytes. O_o (Though it did work, and was kinda fun to write anyway) https://github.com/slembcke/critical-ma ... etatiles.s

User avatar
koitsu
Posts: 4216
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: What is wrong with my metatile routine?

Post by koitsu » Wed Feb 06, 2019 3:12 pm

gauauu wrote:Wow, that's disastrous. That means typos compile happily and break silently. How is this not already widely known?
Loopy kept asm6 as simple as possible, adhering to KISS quite strictly. Take a look at the code sometime if you haven't -- it's nothing like you probably imagine (it wasn't for me anyway, as an author of a disassembler). Parsers are notoriously painful to implement (and C doesn't make this any easier/more pleasant). The subject of spacing (read: whitespace and tabs) becomes important quickly, and just as quick brings up the importance of a BNF for syntax compliance, thus bringing things like yacc/bison into the mix, and suddenly you have a whole non-KISS-compliant assembler with dependencies. One of the things that makes asm6 beautiful is that it's a single .c file with no dependencies (practically a diamond-tipped needle in a haystack compared to most of today's software).

Generally speaking, a kludge fix would be to require that labels by themselves (on a single line) must end with : (and trailing spacing stripped/ignored), else the line should be parsed/treated as opcodes/macros/whatever (i.e. whatever it currently does). But here I am giving a terse simple solution that hasn't been tested or even ensured it can work; I don't write assemblers, so I shouldn't be considered authoritative on how to solve such parsing complexities. Anyway, it's subject for another thread...

User avatar
tokumaru
Posts: 11469
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: What is wrong with my metatile routine? (ASM6 bug found)

Post by tokumaru » Wed Feb 06, 2019 3:18 pm

Is it really a bug, though? If that's not a supported instruction, it is a valid label after all. Are assemblers supposed to blacklist certain words because they're instructions in other CPUs?

Not requiring a colon after labels was definitely a design choice, not an oversight, probably for compatibility reasons. I don't know how one word to shoot fixing this "bug" without breaking that compatibility or blacklisting words based on instructions from other CPUs...

I'm coding my own assembler right now and I'm pretty sure it'll have this "bug" too, for the same reasons.

samwise970
Posts: 20
Joined: Tue Oct 17, 2017 12:13 am

Re: What is wrong with my metatile routine? (ASM6 bug found)

Post by samwise970 » Wed Feb 06, 2019 3:34 pm

tokumaru wrote:Is it really a bug, though? If that's not a supported instruction, it is a valid label after all. Are assemblers supposed to blacklist certain words because they're instructions in other CPUs?

Not requiring a colon after labels was definitely a design choice, not an oversight, probably for compatibility reasons. I don't know how one word to shoot fixing this "bug" without breaking that compatibility or blacklisting words based on instructions from other CPUs...

I'm coding my own assembler right now and I'm pretty sure it'll have this "bug" too, for the same reasons.
I guess my question would be, do CA65 and NESASM also interpret all non-commands as labels? I understand your argument for compatibility, but idk if I agree. I'm trying to imagine if Python interpreted everything it didn't recognize as an IF statement missing the colon haha

User avatar
tokumaru
Posts: 11469
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: What is wrong with my metatile routine? (ASM6 bug found)

Post by tokumaru » Wed Feb 06, 2019 3:59 pm

ca65 requires colons after labels by default. There is a "labels_without_colons" option, but then it forces labels to be placed at the very beginning of the line. These rules slone are enough to prevent this bug (as long as instructions are indented, which is the norm in assembly), but since it's also aware of other 65xx variants, it may in fact handle this case more specifically.
Last edited by tokumaru on Wed Feb 06, 2019 4:02 pm, edited 1 time in total.

Post Reply