3 ms·
Does it end that code with a jmp $fbfd ?
by Someone 3y ago
Does it end that code with a
jmp $fbfd
?
- mananaysiempre 3y agoDoubtful, given the JSR comes from an inline asm. You’d need to code the call in C (with an appropriate calling convention, which I don’t know if this port defines) for Clang to be able to optimize a tail-position call into a jump—which it is capable of doing, generally speaking.
- retrac 3y agoNo. The compiler knows that trick for its own code :) not sure about introspecting into the assembly (I think LLVM doesn't do that). But either way, standard C returns int of 0 from main on success. So: ldx #0 txa rts
- Someone 3y agoNitpick: this isn’t standard C (it uses void main, not int main) Nitpick 2: why ldx #0 txa rts? I would think lda #0 rts is shorter and faster Back to my question: if it can’t, the claim “an assembler programmer couldn't do better” isn’t correct. I think an assembler programmer for the 6502 would consider doing a jmp at the end, even if it makes the function return an incorrect, possibly even unpredictable value. If that value isn’t used, why spend time setting it? A assembly programmer also would: - check whether the routine at 0xFBFD accidentally guarantees to set A to zero, or returns with the X or Y register set to zero, and shamelessly exploit that. - check whether the code at 0xFBFD preserves the value of the accumulator (unlikely, I would guess, but if it does, the two consecutive ‘l’s need only one LDA#) - consider replacing the code to output the space inside “hello world” by a call to FBF4 (move cursor right). That has the same effect if there already is a space there when the code is called. - call 0xFBF0 to output a printable character, not 0xFBFD (reading https://6502disassembly.com/a2-rom/APPLE2.ROM.html https://6502disassembly.com/a2-rom/APPLE2.ROM.html, I notice that is faster for letters and punctuation) On a 6502, that’s how you get your code fit into memory and make it faster. To write good code for a 6502, you can’t be concerned about calling conventions or having individually testable functions.
- tom_ 3y agoI bet that sizeof(int)==2 - which immediately tells you everything you need to know - and the return value from a function has 8 bits in X and 8 bits in A. So ldx#0:txa is how you load a return value of (int)0. Regarding this specific unrolled loop, I would expect a 6502 programmer would just write the obvious loop, because they're clearly optimizing for space rather than speed when calling the ROM routine. They'll be content with the string printing taking about as long as it takes, which clearly isn't too long, as they wouldn't have done it that way otherwise. And the loop "overhead" won't be meaningful. (Looks like it'll be something like 7 cycles per character? I'm not familiar with the Apple II. Looks like $fbfd preserves X though.)
- retrac 3y agoYes, I compiled with -O3 for maximum speed. That would be an unusual flag choice in most cases. I just wanted to use 6502 code (so many seem to be able to read it!) with C side by side. x86 would have worked as well. Where the fastest answer would also be the same construct, assuming the dependency on an external routine.
- Max-q 3y agoWe did a lot of loop unrolling and self modifying code back in the day, when making demos for the C64. The branch is really expensive. For example, clearing the screen you might use 16 STA adr,x and then add 16 to X before you branch to the loop.
- tom_ 3y agoIndeed, in some cases you want the unrolls. The 6502 is good in the twisties, but if you're trying to do any kind of copy or fill then the percentage of meaningful cycles is disappointingly low, and the unroll may be necessary. Also, if you're trying to keep in sync with some other piece of hardware, then just doing it step at a time can be much easier. I have done a lot of all of this sort of code and I am quite familiar with the 6502 tradeoffs. But for printing 15 chars by calling a ROM routine, I stand by my comments.
- 3y ago