load81 wrote:
Also, please feel free to leave any (constructive) comments that seem relevant. I'm here to learn. I want to write good ASM code.
A laudable goal - unfortunately, whoever wrote that example you found apparently didn't share it :/ You're absolutely correct in figuring that a loop would be a less silly way of accomplishing this.
Fortunately, the 6502 has features enough that it's relatively easy to write a loop that indexes across a block of memory. Specifically, the X and Y registers are primarily intended as index registers - so you can, say, LDA
string-address, X and STA
screen-address, X which would be roughly equivalent to screen[x] = string[x] in a high-level language. Then, simply by incrementing the X register, you're ready to move on to the next character.
The other important question is how you want to terminate the loop - and, by extension, how you want to terminate the string. There's two main ways to do that, C-style strings (which end with a zero byte) and Pascal-style strings (which begin with a string-length count before the actual text.) Both are valid strategies with their own advantages and disadvantages (C-string code is vulnerable to improperly-formed strings where the zero terminator is missing, while Pascal strings are limited in length by the size of the length variable - i.e. if the length is stored in one byte, the string can only be up to 255 characters long.)
Both are relatively easy to code on the 6502, because most operations set the Z flag if the result is zero, and conditional-branch instructions are available to jump someplace if the Z flag is set (BEQ) or if it's clear (BNE.) So you can easily detect the end of a C string right after loading the next string byte (loading the terminator will set the Z flag,) or you can do a Pascal string by loading the length value into one of the index registers (or a memory location, though this will be slower) and decrementing it after every pass through the loop (the final decrement will set the Z flag.)
I'll leave the actual implementation as an exercise, but that's the basics of it.
P.S. the reason the example uses screen codes instead of PETSCII is because it's writing directly to the C64 screen memory, and the character ROM the VIC-II uses is laid out in a different order than the PETSCII map, for some peculiar reason. The C64 Kernal routines for writing to the screen normally do the translation automatically, but if you're just dropping values into the tilemap, you need to account for that bit yourself.
P.P.S. the reason the example loads at $0801 is because this is the start of the BASIC program area on the C64, and the bit at the start of the program is a BASIC stub program that launches the actual machine-language program when you load and run it. If you put that data at $1000 instead, BASIC won't find it and the stub won't work. There's no particular reason to load at $1000 anyway other than that it's a nice round number in hexadecimal.