Espozo wrote:Edit: (Again.) I solved the problem. I wrote sep #$10, rep #$20 instead of rep $10, sep #$20. After changed that, I ran it, used the restroom, then grabbed a soda and it was still running so I think It's safe to say it's alright. :wink: (By the way, I guess you should never rep right after you sep?)
I covered REP/SEP earlier, including what each bit represents. So let's cover it again, more verbosely. Remember: SEP/REP only touch (i.e. change) the bits you set to 1 in the operand -- all other bits are left alone. (The operand is essentially a mask of sorts). Below is a "chart" for you to use -- I know how SEP/REP work, but honestly I just remember this chart by heart because these are the most common operations you'll see:
Code: Select all
rep #$10 ; X/Y = 16-bit (set bit 4 of P to 0). $10 hex = %00010000 binary
sep #$10 ; X/Y = 8-bit (set bit 4 of P to 1). $10 hex = %00010000 binary
rep #$20 ; M = 16-bit (set bit 5 of P to 0). $20 hex = %00100000 binary
sep #$20 ; M = 8-bit (set bit 5 of P to 1). $20 hex = %00100000 binary
rep #$30 ; M = 16-bit, X/Y = 16-bit (set bit 4 and 5 of P to 0). $30 hex = %00110000 binary
sep #$30 ; M = 8-bit, X/Y = 8-bit (set bit 4 and 5 of P to 1). $30 hex = %00110000 binary
Using this "chart", you should be able to determine what you did, and why if you want something like 8-bit accumulator + 16-bit indexes that you need to use a combo of SEP and REP -- it cannot be done in a single instruction.
Espozo wrote:Also, I guess the fact that I'm only writing inx once is one of the problems? (I thought it would automatically increment by 2 bytes instead of one.)
Okay, two things here:
1. The increment opcodes (INC, INY, INX) only increment the register by 1. The "size" of the register has no bearing on "how much" is incremented. Rephrased: INC is equivalent to A++ or A = A +1, INY is equivalent to Y++ or Y = Y+1, INX is equivalent to X++ or X = X+1 (assuming you have some programming knowledge of other languages). The only bearing the register size (8 vs. 16-bit) has on this is when it comes time to increment from $FF to a new value (8-bit would go from $FF to $00, 16-bit would go from $FF to $100) or when incrementing a memory address (more on that at the end).
If you want to increment something by more than 1, you have a couple choices. For the X/Y registers, repeated calls to INX/INY would work (e.g. incrementing X by 2 would be INX / INX), but you should know that from your repeated INY statements within build_metasprite. :/
For incrementing the accumulator, you can use CLC / ADC #value (e.g. incrementing accumulator by 7 would be CLC / ADC #7).
There is no CLC/ADC equivalent that affects X or Y directly. If you wanted to increment X or Y by a larger value and don't want to have to call INX/INY repeatedly, then you have to transfer X or Y into the accumulator, use CLC/ADC, then transfer the accumulator back into X or Y. Example:
Code: Select all
ldx #4 ; X=$0004
txa ; Transfer X into accumulator (A=$0004)
clc ; Clear carry
adc #7 ; Add 7 to accumulator (A=$000B (11 decimal))
tax ; Transfer accumulator into X (X=$000B)
You will probably ask: "wouldn't doing TXA mean whatever (previously) was is the accumulator is lost?" -- yup, it does. That's why you'll find people doing PHA/PLA before/after that type of operation quite often, or using a temporary variable.
There is a point where repeated INY/INXs become space-wasting and time-wasting though (i.e. it's better to do something like TXA/CLC/ADC/TAX), but right now I really don't want to cover that because it'll just confuse you more. For now, if you wanted to increment X by, say, 12, then go ahead and do 12 INX instructions. If anyone comes along and says "this is inefficient blah blah blah", tell them you're still learning and to deal with one thing at a time. :-)
Also with INC (but not INX/INY), you can also increment (by 1) a value in memory without having to load it into the accumulator / write it back out. The active size (8 vs. 16-bit) of the accumulator matters here too (and can often cause people confusion, similar to what's happening presently). But again I don't want to cover that because it'll just add more confusion right now. Just know that it's available.
2. Terminology nitpick: you are not "incrementing by 2 bytes". You are incrementing an index register which you are using as an offset during your LDA.
Espozo wrote:The one thing I really do have to look at (which should be in the book) is the processor status bit things, because I don't have the slightest Idea of what I'm doing.
Well I've explained them twice now, including giving you a chart of essentially the most-commonly-used opcode+operand combinations are (I hope that helps you the most -- as I said, I understand how the opcodes work, but I honestly just remember the chart by heart. :-) ), so if you're still having problems then maybe referring to the WDC book is a better choice. There's a chapter on it, I believe.
One thing I should note: the learning curve you're going through here, with regards to 8-bit vs. 16-bit, is incredibly common, so don't feel alone! A lot of people used to the original 6502 and 65c02 (both 8-bit CPUs), when the 65816 came out, had very similar complexities/difficulties as what you're going through now. Doing 16-bit "stuff" on the 6502/65c02, however, is a lot more painful (IMO). The 65816 really spoils you -- it's one reason I have a harder time doing 6502, because I did a *lot* of my coding on the 65816 so using a native 8-bit CPU often makes me grumble. :-)
As for your SNES9x debugger shot: by default the SNES9x debugger doesn't execute any code, and instead stops at the very first instruction the processor wants to run. Step back for a moment and think about how the CPU "starts up". It starts executing code where the RESET vector points to, right? You should be able to determine where that is easily, and the debugger makes it even easier (there's a "Vector Info" button). The first instruction your program executes when the system starts is SEI. You should be able to find that in your code and go from there.
What you need to do is what I described earlier -- create a breakpoint on the execution of code, essentially right before you do your jsr build_metasprite
. But as I said earlier, the debuggers do not currently have a way to "connect" source code to actual running code, so what you're seeing is quite literally what the assembled results are + what the CPU is doing. This is why I said it'd be very useful if emulators actually had a way to drop to the debugger when encountering an instruction (e.g. brk $ff
), because then you could just add that line and run the code and then bam, continue from there.
A listing generation from your assembler would tell you exactly what memory address the jsr build_metasprite
instruction is at, but WLA DX (as I've said a billion times now) is completely broken in this regard, which makes your job a lot harder. Essentially what you need to do right now is step through (run) every single line of code until you see code that looks very similar to the code around/right before jsr build_metasprite
. If you aren't sure, do something that will clue you in: put a bunch of nop
statements right before your jsr
. Once you see those you'll know where they are, then you'll get an idea of what memory location the JSR is at, then can throw that into the debugger as an execution breakpoint, reset the system (there's a Reset button), click Run, and wait until it drops to the debugger and then you can step through your code instruction by instruction and see what it's doing, how the registers are affected, and so on. :-)
Learning how to use a debugger is a tedious process (about as tedious as programming) because each debugger behaves differently. There is no standard. I'm certain the bsnes debugger is substantially different from the SNES9x debugger, for example. The only one I have familiarity with is the SNES9x debugger, although as discussed in other threads NO$SNS has a debugger as well (although by default that emulator shows opcodes in a non-65xxx-syntax format -- you have to turn that feature off before you get something that's actually sane ;-) ).