There were a few instructions of the init code that I wasn't sure about, and I was hoping someone could give me some insight.
Code:
Reset:
SEI
CLD
LDX #$40
STX $4017
LDX #$FF
TXS ; I'm not sure why this is done, are we manually resetting the stack? can someone give me a hint?
INX ; Increments X, which rolls X over its max value back to 0. I'm assuming we do this because it uses less memory than writing LDX #$00. Is that correct?
STX $2000
STX $2001
STX $4010
Sorry that it's not good enough for me to 'just know that it works, and don't worry about why'.
cartlemmy wrote:
There were a few instructions of the init code that I wasn't sure about, and I was hoping someone could give me some insight.
Code:
LDX #$FF
TXS ; I'm not sure why this is done, are we manually resetting the stack? can someone give me a hint?
The power-on value of the stack pointer might vary from one CPU revision to another. It'll certainly vary when the user presses the NES's reset button in the middle of a subroutine.
Quote:
Code:
INX ; Increments X, which rolls X over its max value back to 0. I'm assuming we do this because it uses less memory than writing LDX #$00. Is that correct?
Yes. It saves 1 byte and 0 cycles over LDX #$00.
cartlemmy wrote:
; I'm not sure why this is done, are we manually resetting the stack? can someone give me a hint?
Yeah, it's good practice to initialize the stack pointer. Your program might still work if you don't though, since the stack pointer wraps around, as long as you don't use page 1 ($0100-$01FF) for anything else. But if you plan on using page 1 for other purposes besides the stack, or if you plan on accessing the stack using using index registers (LDA $0101, X; LDA $0102, X; etc.) you have to initialize it.
Quote:
; Increments X, which rolls X over its max value back to 0. I'm assuming we do this because it uses less memory than writing LDX #$00. Is that correct?
Yes, this is correct.
Thanks guys, you're awesome!
Yes, unfortunately many code aimed at new programmers needlessly optimizes it, making the task of learning more difficult. Assembly is difficult enough as it is; save the optimizations until after you've learned how to initialize the NES.
Another reason is to allow easy access to the stack via indexed addressing. Sometimes you push some things on the stack, and then want to access one of the earlier things without pulling everything back off. You do this by transferring S to X, and then using $100+offset,x to access earlier things. If the stack pointer might have wrapped since pushing those, this will fail.
A final reason to initialize the stack pointer is consistency of behavior, in case your code ever depends ons value. Having it random makes debugging harder, since it's something that might differ without your knowledge.
Yeah, I don't have a problem with optimizations in tutorials, as long as there is an explanation. Thanks for the info Blargg.
One more question (in comments).
Code:
clrmem:
LDA #$00
STA $0000, x
STA $0100, x
STA $0200, x ;Isn't this sort of redundant, since we are setting it to #$FE later? Or am I missing something?
STA $0400, x
STA $0500, x
STA $0600, x
STA $0700, x
LDA #$FE
STA $0200, x
INX
BNE clrmem
Yeah, it's redundant. Sometimes you start with code that's known to work, then make changes that you are sure won't break it, and don't mind leaving some inefficiency if it means the program is easier to prove correct. Though here, it reduces clarity, because you wonder why it's doing a clear followed by a fill, whether there is something you aren't seeing.
If I were doing that, I'd have no problem with using a standard memory clear and avoiding modifying it, and then doing the fill separately later in the code. It's a combination of a well-tested memory clear that you use in EVERY program, and some extra code that's easy to prove correct.
So the coding style I use emphasizes correctness first, even if that sometimes results in inefficiencies. As long as they aren't in critical sections of code, it might not even have any noticeable impact on the program speed, and thus show that it was the right choice: trade some unimportant speed for always-important correctness and clarity.
Thanks Blarrg, that's what I was looking for.
cartlemmy wrote:
Code:
clrmem:
LDA #$00
STA $0000, x
STA $0100, x
STA $0200, x ;Isn't this sort of redundant, since we are setting it to #$FE later? Or am I missing something?
STA $0400, x
; [...]
LDA #$FE
STA $0200, x
INX
BNE clrmem
I'm pretty sure the first instance of $0200,x is a typo for $0300,x. Where did you find this code? I just checked the wiki and the error isn't there.
tepples wrote:
cartlemmy wrote:
Code:
clrmem:
LDA #$00
STA $0000, x
STA $0100, x
STA $0200, x ;Isn't this sort of redundant, since we are setting it to #$FE later? Or am I missing something?
STA $0400, x
; [...]
LDA #$FE
STA $0200, x
INX
BNE clrmem
I'm pretty sure the first instance of $0200,x is a typo for $0300,x. Where did you find this code? I just checked the wiki and the error isn't there.
I though I found it on that Nerdy Nights tutorial... But upon review, I couldn't find this error. Perhaps I screwed something up somehow, and in that case I apologize for the trouble.
IMO, this has been one of the more interesting discussions, even though it's about something so basic. The basics never get boring.
I like when we discuss code... I mean, not those "here's my wall of code - find my error for me" situations, but more when we talk about a good way to do this or that...