3 ms·
Yes. This doesn't strike me as an especially productive line of attack, but maybe I'm missing something (hopefully not obvious), maybe I'm just not imaginative
by to3m 10y ago
Yes. This doesn't strike me as an especially productive line of attack, but maybe I'm missing something (hopefully not obvious), maybe I'm just not imaginative enough, and/or maybe I'm underestimating how much effort people might be willing to put into such an endeavour.
This did get me thinking about the problem a bit this evening though. The 6502 is an awful target for many higher-level languages, but I think you could compile something like C, if you treat zero page as the stack for locals, and index it by X. The programmer would need to be aware of the target's rather tiresome limitations, but you'd get somewhat passable code at least.
(Unlike absolute addressing, you do pay a 1-cycle penalty for indexed zero page accesses, but what can you do? You need to store things in zero page to handle pointers.)
Suppose you had a function with a couple of locals, like this:
void strip(char *p,char c) {
unsigned char *dest=p;
do {
if(*p!=c) *dest++=*p;
} while(*p++!=0);
}
So you'd store c (1 byte), then p (2 bytes), and then once the space for locals is reserved, zero page starting from the address in X would look like this:
+0, +1 = dest
+2, +3 = p
+4 = c
So the ideal generated code would go along these lines:
DEX:DEX ; reserve space for locals
LDA 2,X:STA 0,X:LDA 3,X:STA 1,X ; dest=p
.L0
LDA (2,X) ; *p
CMP 4,X
BEQ L1 ; taken when *p==c
STA (0,X) ; *dest=*p
INC 0,X:BNE L2:INC 1,X:.L2 ; ++dest
.L1
LDA (2,X) ; *p
INC 2,X:BNE L3:INC 3,X:.L3 ; ++p
CMP #0
BNE L0 ; taken when *p!=0
INX:INX
RTS
I don't think many people would write code like that by hand, but it's not completely insane given the requirements.
This has actually now piqued my interest enough to make me think about actually coding something, so I guess that answers the question about how much effort somebody might be willing to put into such an endeavour.
Other thoughts:
- since ZP,X costs like ABS,Y, maybe have a second stack in main memory for non-pointers and index it with the Y register (the RMW instructions don't have an appropriate addressing mode though)
- you could statically allocate zero page for many programs, which would make it easier to use the (ZP),Y addressing mode
- turning canned snippets (like the INC/BNE/INC) into routines would probably be rarely beneficial, since getting the address into X is rather involved
- I've never used a C compiler for the 6502 so maybe they all do this anyway ;)
- white-flame 10y agocc65 (http://cc65.github.io/cc65/ http://cc65.github.io/cc65/) is probably the most popular C compiler for the 6502, and its has support for many of the old home computers. I only use its assembler, since it's one of the most powerful, but I'm somewhat familiar with its C side of things. I believe it uses a manual 16-bit stack pointer for frames, and zeropage for globals and statics. Pointers have to be copied into zeropage to be dereferenced, and I think it might have a numeric stack somewhere for intermediate results when evaluating numeric expressions. It's not super fast by any measure (simply due to impedance mismatch between C and 6502), but it does work and is quite mature. As a side note, most 6502 Forths do use zeropage for the operand stack, with heavy use of zp,X addressing in their operators.
- ktRolster 10y agoI don't think many people would write code like that by hand, but it's not completely insane given the requirements Typically if you were programming for the 6502 back in the day, you would build up a rather large macro library to make things simpler.