It was thus said that the Great Ethan Dicks once stated:
On Tue, Apr 27, 2004 at 06:33:35PM -0400, Sean 'Captain Napalm' Conner wrote:
The 6809 is geared more towards C (and higher
level languages in general)
than the 6502.
I'm not as familiar with the 6809 as I am with the 6502... what differences
in architecture make it better? Larger stack frame? More (and larger)
registers?
Yes to the above. The 6809 has the following:
A - 8bit accumulator
B - 8bit accumulator
DP - 8bit Direct Page [1]
CC - 8bit condition code
D - 16bit accumulator (reg A MSB, reg B LSB)
X - 16bit index
Y - 16bit index
S - 16bit stack [2] / index
U - 16bit stack [3] / index
PC - 16bit program counter
[1] The 6809 uses this as the MSB for 8-bit
direct addressing modes---it defaults to
$00 on startup.
[2] Hardware stack pointer, for use with BSR,
JSR, and interrupts. Can also be used as
an index register.
[3] software stack pointer, meant to be used
to pass parameters, but can also be used
as an index register
It also supports more addressing modes than the 6502 like position
independant (indexed off PC) and indirect addressing (in C, this would be
dereferencing a pointer). It also has a fairly orthogonal instruction set
which also helps in compiler writing (in my opinion). Of all the 8bit CPUs,
this happens to be my favorite.
(Z80) may
produce mediocre code.
Is that inherent to the CPU architecture, or just a coincidence of how
much effort people have (or have not) put into C compilers for 8-bit
machines?
Probably a bit of both. I know the instruction set of the 8080/Z80 is not
as orthogonal as the 6800/6809, with quite a few specialized instructions,
and only a single accumulator. To use the 8086 as an example (since it's
derived from the 8080), it takes quite a bit of compiler smarts to turn:
int i;
char *s = src;
char *d = dest;
for (i = 0 ; i < SIZE ; i++)
*d++ = *s++;
into:
mov cx,SIZE
mov si,[bp + src]
mov di,[bp + dest]
rep movsb
; a smart compiler might realize that s,d and i aren't
; used after this point, and discard the follow
; instructions ... (and this applies to each of the examples
; below as well)
mov [bp + src],si
mov [bp + dest],di
mov word ptr [bp + i],SIZE
A horribly written C compiler might produce (and I have seen this):
mov ax,[bp + src]
mov [bp + s],ax
mov ax,[bp + dest]
mov [bp + d],ax
mov word ptr [bp+i],0
loop: mov ax,[bp + i]
cmp ax,SIZE
je loop_exit
mov bx,[bp + s]
mov al,[bx]
inc bx
mov [bp + s],bx
mov bx,[bp + d]
mov [bx],al
inc bx
mov [bp + d],bx
mov ax,[bp + i]
inc ax
mov [bp + i],ax
jmps loop
loop_exit:
while a slightly better one would see that s and d are used as memory
pointers, and that i is used as a counter so it too could be used in a
register:
xor dx,dx
mov si,[bp + src]
mov di,[bp + dest]
loop: mov al,[si]
inc si
mov [di],al
inc di
inc dx,
cmp dx,SIZE
jl loop
mov [bp + s],si
mov [bp + d],di
mov [bp + i],dx
You get the idea. You, looking at the C code, can guess immediately that
you should probably use REP MOVSB, but a compiler can't guess that outright,
at least, not without a lot of smarts.
On the 6809 though, will look more like the above sequence (assuming a
half-way decent compiler) and that's about as good as you can get, since the
6809 doesn't have specialized instructions:
clra
clrb
std i,u
ldx src,u
ldy dest,u
loop: lda ,x+
sty ,y+
ldd i,u
addd #1
std i,u
cmpd #SIZE
bne loop
stx src,u
sty dest,u
Although, if SIZE doesn't exceed 255, the compiler could produce:
clrb
ldx src,u
ldy dest,u
loop: lda ,x+
sta ,y+
incb
cmpb #SIZE
bne loop
ldb #SIZE
clr i_high,u
stb i_low,u
stx src,u
sty dest,u
Of course, you should replace:
for (i = 0 ; i < SIZE ; i++)
*d++ = *s++;
with
memcpy(dest,src,SIZE);
which a C compiler is free to replace with:
mov cx,SIZE
mov si,[bp + src]
mov di,[bp + dest]
rep movsb
or (on a 6809):
ldb #SIZE ; assuming SIZE < 256
ldx src,u
ldy dest,u
loop: lda ,x+
sta ,y+
decb
bne loop
Even a poorly written compiler can be written with *that* amount of smarts
(basically, inlining anything defined in <string.h>). But I'm digressing.
-spc (Okay, should probably go to bed now ... )