16bit table indexing problem

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

16bit table indexing problem

Post by Drew Sebastino »

I have no idea why, but a code I am trying to make doesn't work. I think there is a problem with me loading values from a table using a 16bit accumulator, because the first value I'm loading is $FFFF and beq-ing it, and for some reason, it thinks it is 0 and branches when it is not supposed to. (Either that, or my code is just really messed up. :oops: ) I tried setting up the table like .DB $FF,$FF,$00,$00 (and so on) because WLA said I couldn't do .DB $FFFF,$0000.

Here's my code:
Metasprite Demo.rar
(222.56 KiB) Downloaded 681 times
The code is just the metasprite one I had made, but I tried to make it work with 16bit values. A sprite still appears on the screen, but only because I have it set to using hioam.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: 16bit table indexing problem

Post by koitsu »

You want .dw $ffff,$0000, by the way. That means "define word", and a word on 65816 is 16-bit. .dw means define-word, .db means define-byte.

I wouldn't be surprised if .db $ff,$ff caused the assembler to generate odd code when using 16-bit lda/etc. statements that reference them. Did you generate an assembly listing (I explained how to do this in another thread recently -- the procedure is the same but use wla-65816.exe for assembling of course) and see if the code being generated is what you expect?

P.S. -- No I haven't looked at the source.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: 16bit table indexing problem

Post by Drew Sebastino »

I fixed the table, but sadly, it still doesn't work :(. Also, about the assembly listing, do you create it by writing -i between wla and the filename? Will it work with the wla.bat file?
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: 16bit table indexing problem

Post by koitsu »

Espozo wrote:I fixed the table, but sadly, it still doesn't work :(. Also, about the assembly listing, do you create it by writing -i between wla and the filename? Will it work with the wla.bat file?
You have to use -i as a flag to both the assembler and the linker. And of course it will work in a batch file -- there's nothing different about one of those compared to, say, doing it manually. I.e.:

Code: Select all

wla-65816 -i -o %1.asm %1.obj
wlalink -i -vr temp.prj %1.fig
(Who uses FIG files in this day and age?!? Good lord, talk about an uncommon ROM format even back in the 90s...)

Also, could you at least give some relevant code bits/lines (and please reference the filename) where something like lda #$ffff / beq {label} is actually branching? (It should not -- ever. lda #$ffff would guarantee the zero flag in the CPU is not set, thus the beq would never happen). I have a feeling the lda statement you're using is actually loading a zero value from somewhere you're not expecting it, hence why the branch works.

There are 7 assembly-related files in this RAR, so being more specific would be quite helpful. I assume you know because you've run this through a debugger (ex. Geiger's SNES9x build with debugging) to see what the behaviour is.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: 16bit table indexing problem

Post by Drew Sebastino »

Oops... :oops: MetaspriteTest.asm is the main file, which jumps to Metasprite. (don't worry about all the other files.) The part where it jumps to Metasprite is under "InfiniteLoop" and the table is right near the end of MetaspriteTest. You're going to have to change .db to .dw and combine the two bytes together.

Don't hesitate to ask any questions. I appreciate you trying to help me.
(Who uses FIG files in this day and age?!? Good lord, talk about an uncommon ROM format even back in the 90s...)
The .bat file. :P (I've honestly never heard of .fig files before.)

Edit: I just looked up and downloaded Snes9x debugger and wow does it look useful. (I currently use bsnes debugger)
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: 16bit table indexing problem

Post by koitsu »

I finally got it to assemble and link (I haven't bothered running it yet).

Wow, these listing files are absolute utter garbage. I don't even know what to say about this.

Code: Select all

                                        
                                        ;=== Include MemoryMap, VectorTable, HeaderInfo ===
$78                                     .INCLUDE "Header.inc"
$18                                     
$FB                                     ;=== Include Library Routines & Macros ===
                                        .INCLUDE "LoadGraphics.asm"
$C2 $38                                 .INCLUDE "InitSNES2.asm"
                                        .INCLUDE "2input.asm"
$A9 $80                                 .INCLUDE "Sprites.asm"
$A9 $A0                                 .INCLUDE "Metasprite.asm"
$A9 $00                                 
$A9 $90                                 ;==============================================================================
$8D $21 $21                             ; main
$8D $21 $21                             ;==============================================================================
$A2 $FF $1F                             
$8D $21 $21                             .DEFINE MapX		$18
$8D $21 $21                             .DEFINE MapY		$1A
$A9 $01                                 .DEFINE XPosition	$1C
$A9 $01                                 .DEFINE YPosition	$1E
$9A                                     
$A9 $01                                 .BANK 0 SLOT 0
$A9 $01                                 .ORG 0
$A2 $24 $92                             .SECTION "WalkerCode"
This doesn't even make any sense no matter how you try to interpret it. All I've managed to determine is this: the assembler and/or linker (I don't know which) is outputting actual bytes that correlate with code of the actual program, but the lines it outputs do not correlate with the actual bytes shown -- e.g. assembler directives/pseudo-ops end up getting intermixed with actual assembly code.

For example:

Code: Select all

$78                                     .INCLUDE "Header.inc"
$18                                     
$FB                                     ;=== Include Library Routines & Macros ===
$78 is sei, $18 is clc, $FB is xce. These are the first 3 instructions in InitSNES2.asm, so what the hell are they doing interspersed/intermixed with directives in MetaspriteTest.asm? I also noticed that each .asm file gets its own .lst file, except those ALSO look wrong! What this means is that this thing is designed completely wrong when it comes to use of .INCLUDE directives -- i.e. listing files cannot be reliably generated with this assembler.

Plain and simple: this assembler is a piece of shit. Who uses this thing?! Good god. It's no wonder nobody can get any programming done if the tools are in this kind of shape. x816 for DOS worked better than this.

I can tell this whole thing is solely focused around UNIX development environments, and reliance on actual GNU Makefiles. You know how I know that? Because there, you wouldn't be using .INCLUDE -- you'd have your Makefile reference every individual assembly file, and call wla-65816 on each one individually (i.e. 7 assembly files, 7 calls to wla-65816). I'm going to modify your wla.bat (heavily) to do this, to work around the obvious brokenness with listing file generation.

Consider me disgusted.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: 16bit table indexing problem

Post by Drew Sebastino »

koitsu wrote:Plain and simple: this assembler is a piece of shit. Who uses this thing?! Good god. It's no wonder nobody can get any programming done if the tools are in this kind of shape. x816 for DOS worked better than this.
Are you referring to WLADX? What do you use then? Also, If I remember, the.bat file came with SNESstarterkit.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 16bit table indexing problem

Post by tepples »

koitsu wrote:I can tell this whole thing is solely focused around UNIX development environments, and reliance on actual GNU Makefiles.
You don't need UNIX to run GNU makefiles. They run just fine in MSYS, a port of Bash, GNU Make, and GNU Coreutils to Windows.

One advantage of setting up a makefile (compared to a batch file that just reassembles everything all the time) is that if you change (say) an image file, Make will reconvert it to tiles, recompress it, reassemble the one source code file that contains an .incbin referencing the compressed tiles, and relink it. In large, complicated projects, this can save a lot of CPU and disk time over reconverting, recompressing, and reassembling everything in your project. This in turn means less time spent between Ctrl+R and the emulator opening, especially on an Atom netbook, though you can still force a full rebuild (make clean && make).
You know how I know that? Because there, you wouldn't be using .INCLUDE -- you'd have your Makefile reference every individual assembly file, and call wla-65816 on each one individually (i.e. 7 assembly files, 7 calls to wla-65816).
The ca65 toolchain does the same thing, with ca65 generating .o files that ld65 combines into an executable .sfc, .nes, or whatever.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: 16bit table indexing problem

Post by koitsu »

I'm not going to tell someone to install MSYS or Cygwin or other environments just to make a SNES ROM, Tepples. It's completely unnecessary and overkill. You should know better than to try and go that route with me. ;-)

My point stands: listing files with WLA DX are worthless if .INCLUDE is used anywhere.

I should note I tried separating this project up into how it "should" be done (using the project file correctly, assembling things as libraries, etc. then putting it all together during link-time) but gave up after repeatedly banging my head against a wall with this error message from the assembler: INTERNAL_PASS_1: A section must be open before any code/data can be accepted. (The file in question only contained code within .SECTION and .ENDS blocks (I even moved the macros into their own), so the message make no sense). The documentation is just as abysmal as it was the last time I looked at it (months ago).

I guess I'll say fuck listing files for now and I'll just go look at the thing in a real-time debugger and focus on the real problem.
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: 16bit table indexing problem

Post by Sik »

koitsu wrote:I'm not going to tell someone to install MSYS or Cygwin or other environments just to make a SNES ROM, Tepples. It's completely unnecessary and overkill. You should know better than to try and go that route with me. ;-)
To be fair, you don't need any of those to use make (you just don't get *nix commands, but if your makefile doesn't use them then that doesn't matter - yes, that'd make sense with SNES development since you'll be using uncommon tools anyway). MinGW already comes with its own make (no, MSYS isn't needed), so one really could just take the make from MinGW (literally just one exe) and use that.

I guess one may want to distribute make on its own instead of telling people to get MinGW, but that'd work.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: 16bit table indexing problem

Post by 93143 »

Espozo, are you still using the super old version of WLA DX, or have you managed to compile the latest one?
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: 16bit table indexing problem

Post by Drew Sebastino »

I honestly have no idea how to compile it. (If someone could post it already compiled in a rar, I would greatly appreciate it.)
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: 16bit table indexing problem

Post by koitsu »

Okay, I haven't really sifted through the entire program/code to figure out what all is going on here, but let's talk about the code and what it's actually doing. First, MetaspriteTest.asm has this around label InfiniteLoop. Apologies for formatting mistakes, as this code uses hard tabs rather than spaces (but not consistently):

Code: Select all

InfiniteLoop:

	WAI

	ldy #$00
	ldx #MetaspriteTable
	jsr start_metasprite

...

MetaspriteTable:
	.DB $FF,$FF,$00,$00,$00,$00,$00,$00,$FF,$FF,$00,$10,$00,$00,$00,$00,$00,$00
This code gets turned into the below, effectively due to run-time register sizes and so on:

Code: Select all

  wai
  ldy #$0000
  ldx #$8405
  jsr $820e
In the debugger (this took me a bit to do). Best place to set an exec breakpoint is at $8312.

Code: Select all

Disassembly:
$00/8311 CB          WAI                     A:0000 X:0000 Y:0000 P:envmxdIZC
$00/8312 A0 00 00    LDY #$0000              A:0000 X:0000 Y:0000 P:envmxdIZC
$00/8315 A2 05 84    LDX #$8405              A:0000 X:0000 Y:0000 P:envmxdIZC
$00/8318 20 0E 82    JSR $820E  [$00:820E]   A:0000 X:0000 Y:0000 P:envmxdIZC
$8405 happens to be the 16-bit address (pre-calculated during assembly-time) of the memory location of MetaspriteTable. Let's start by asking: is that the correct address? Let's find out. And of course SNES9x won't let me copy/paste the Hex Editor portion... wonderful, so I get to type all of this in manually:

Code: Select all

008400 8D 10 21 28 60 FF FF 00 00 00 00 00 00 FF FF 00
008410 10 00 00 00 00 00 00 FF FF FF FF FF FF FF FF FF
008420 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
That looks correct. So with that in mind, let's go look at start_metasprite and see what it's doing with the X register.

Code: Select all

start_metasprite:
	php
	rep #$10
	sep #$30

build_metasprite:
	lda $0000,x
	beq metasprite_done
	inx
	lda $0000,x
	clc
Initially this look right, but I can already see multiple catastrophic bugs given the assumptions of the programmer vs. what the processor will do. Let's see what the real-time debugger has to say:

Code: Select all

SNES reset.
$00/823C 78          SEI                     A:0000 X:0000 Y:0000 P:EnvMXdIZC
$00/8312 A0 00 00    LDY #$0000              A:00FF X:0000 Y:1000 P:envMxdiZC
$00/8315 A2 05 84    LDX #$8405              A:00FF X:0000 Y:0000 P:envMxdiZC
$00/8318 20 0E 82    JSR $820E  [$00:820E]   A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/820E 08          PHP                     A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/820F C2 10       REP #$10                A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/8211 E2 30       SEP #$30                A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/8213 B5 00       LDA $00,x  [$00:0005]   A:00FF X:0005 Y:0000 P:eNvMXdizC
$00/8215 F0 23       BEQ $23    [$823A]      A:0000 X:0005 Y:0000 P:envMXdiZC
Your REP/SEP are in the wrong order. By doing REP #$10 / SEP #$30, you are setting 16-bit indexes, then setting 8-bit accumulator and 8-bit indexes. There are two ways to solve this, but one is wrong and the other is right. These are your options:

Code: Select all

  rep #$30   ; A=16, X/Y=16
  sep #$20  ; A=8
Or:

Code: Select all

  sep #$30  ; A=8, X/Y=16
  rep #$10  ; X/Y=16
Guess which one is the correct way? The first one. The 2nd one will introduce a horrible bug: you'll lose the upper byte of the X/Y index registers -- it'll be zeroed. This happens on the 65816 and ONLY with the index registers. You can swap between 16-bit and 8-bit accumulator without the full 16-bit contents being affected, but with indexes, upon going to 8-bit you lose the upper byte. In fact, that's happening with your code already. Look closely at the contents of X:

Code: Select all

$00/8211 E2 30       SEP #$30                A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/8213 B5 00       LDA $00,x  [$00:0005]   A:00FF X:0005 Y:0000 P:eNvMXdizC
See how it goes from $8405 to $0005, all because you set 8-bit indexes?

So let's go with REP #$30 / SEP #$20 and see how things look after that:

Code: Select all

$00/8318 20 0E 82    JSR $820E  [$00:820E]   A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/820E 08          PHP                     A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/820F C2 30       REP #$30                A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/8211 E2 20       SEP #$20                A:00FF X:8405 Y:0000 P:eNvmxdizC
$00/8213 B5 00       LDA $00,x  [$00:8405]   A:00FF X:8405 Y:0000 P:eNvMxdizC
$00/8215 F0 23       BEQ $23    [$823A]      A:00FF X:8405 Y:0000 P:eNvMxdizC
Much better.

I should also point out here: you should not be using .dw $ffff,... like we discussed earlier. You are using an 8-bit accumulator, not a 16-bit accumulator (despite what you said earlier). And your build_metasprite routine is coded to use 8-bit accumulators as well. If you were to turn on 16-bit accumulator, your routine would break (look closely at where you're storing the results in SpriteBuf1 and what hard-coded math you're using there!).

I hope this has been a lesson in why having an assembler that generates proper/decent listings is VERY IMPORTANT. The fact WLA DX can't do this sanely/correctly is ridiculous.

I see other bugs in this program though, depending on how intelligent WLA DX is about knowing about addressing modes and banks, and when those crop up you're going to be crying big tears. Case in point: lda $0000,x right now is getting assembled into $b5 $00 (LDA directpage,X) because your MetaspriteTable data happens to be within the same bank as your the code that's running (in bank $00).

Eventually you're going to have to break outside of that (dealing with multiple banks); for example if MetaspriteTable was in a different bank (say bank $01 or $81 (same thing in this memory mode)), then the above code would be wrong and manifest itself by misbehaving in real-time: you'd be loading the wrong data: it'd be coming from bank $00 (where direct page is hard-coded to live) rather than where B was. In other words:

Code: Select all

  rep #$10
  ldx #MetaspriteTable
  sep #$20
  lda #$01
  pha
  plb
  lda $0000,x
WLA DX may end up screwing you by optimising lda $0000,x into $b5 $00 (LDA directpage,X), rather than $ad $00 $00 (LDA absolute,X). The former would get you whatever bytes happened to be in bank $00 address $0000 + X, the latter would get you whatever bytes happened to be in bank $01 address $0000 + X.

The only way to "force" the assembler into knowing this is to use the .w modifier, i.e.:

Code: Select all

  lda.w $0000,x
Which will ALWAYS assemble to the 16-bit absolute address + opcode ($ad $00 $00).

Alternately you could use full 24-bit addressing ("long addressing") on all of your stuff that's not explicitly in direct page, through the .l (dot-ELL) modifier. Be aware that 24-bit addressing takes up 1 more byte, and takes 1 more cycle than absolute. This added cycle can add up real fast when doing loops, which is why before many loops you'll find people changing what B points to and then using absolute addressing.

Food for thought.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: 16bit table indexing problem

Post by koitsu »

Why are people bothering to discuss compiling WLA DX? The binaries are already available per the home page:

http://www.villehelin.com/wla.html
Binaries (UNSUPPORTED):

Win32 (link)
Go ahead and get the ones labelled version 9.5 / 02-Nov-2013.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: 16bit table indexing problem

Post by 93143 »

...eh?

I was sure I got it from there...

...but I misremembered. I'm using Neviksti's SNES starter kit, which is not the same as that one tutorial that said to download WLA DX separately. The starter kit includes binaries from 2003.

Okay, that straightens that out, at least on my end. Sorry, Espozo.

And yes, I will probably end up switching to ca65, mostly because it has Super FX support.
Post Reply