Redesigning the 6502 to make it more suitable for high-level languages is problematic. The most important criteria is to be able to support an indexed stack addressing mode.
I was with you until this point. While you can obviously choose whatever design criteria that you want, it's not immediately clear to me how any modern C compiler would benefit from this.
I don't understand how you would think that "modern CPUs are stack based." Is ARM stack based? SPARC? PowerPC? SiL? AVR?
I merely meant it in the sense that cjs and garthwilson meant it. 'C' expects to have stack frames and register rich architectures spill registers to the current thread's stack when they call functions. That is, registers act as a cache for the stack, but the language is stack oriented.
The 65T2 should make compiler writing easier than for a 6502, because one can conceive of pseudo registers being aliased in actual local variables and parameters on the stack. If we imagine R0..Rn mapping to S+0 .. S+2n, then operations on A, Rm map to A,S+2m. This is the reverse of what happens in a register rich architecture where actual registers alias actual local variables. There's an interesting discussion on this approach for the 'C' compiler written for the Magic-1 architecture.
Magic-1 is register poor, but the designer ported LCC to it by creating a number of pseudo registers which are then mapped to its stack. The same approach could work for the 65C816 to port to a newer version of LCC.
In RISC processors, the primary addressing mode is: IndexReg+offset; where one register is usually designated as the stack pointer itself. Thus the 65T2 does the same thing, it supports IndexReg+Offset modes for S, X, Y,but it also supports the indirect equivalents for stack locals and parameters: (s+offset),X and (s+offset),Y.
This makes its addressing modes somewhat more versatile than an actual 6502 (but not a 65C816), because indirect, indexed addressing is available for both X and Y; and space on the stack can be easily allocated using ADS #n.
65T2 makes register spilling and filling easy because it can be largely achieved by ADS #n instead of having to move values in and out of zero-page to the stack. Consider:
uint16_t bar(uint16_t *Sum) { return (*Sum)+(*Sum>>1); }
uint16_t foo(void) { uint16_t v=100; return bar(&v); }
On the 65T2 the code could look like this:
Code: Select all
:bar ;Sum is at S+2 and S+3
lda *s+3 ;hi byte (indirect= ea mode 5 due to the *s, not mode 1 which would be lda s+3)
asra ;btw *s+3 means *(s+3).
pha
lda *s+3; lo byte.
rora
add *s+3;lo byte
sta *s+3
pla
adc *s+3 ;hi byte.
sta *s+3;hi byte.
rts
:foo ;
lda #0
pha
lda #100
pha ;v=100.
lea s
phx
pha
jsr bar
Passing parameters and accessing the contents of pointers is relatively easy on the 65T2 (at least for these simple examples, Dhrystone would be an interesting and more substantial test). A compiler might pre-allocate space in foo for V and for temporary variables in bar using ads #-n and then use lda / sta instructions rather than pha or pla, but this wouldn't substantially change the code generation.
Back later...