SDCC for 6502
SDCC for 6502
http://sdcc.sourceforge.net/index.php#News
They just announced work in progress to support the 6502.
They just announced work in progress to support the 6502.
Re: SDCC for 6502
it says "mos6502" so i assume they don't mean the W65C02, which is a shame.
Re: SDCC for 6502
Nice to have another C compiler on the block. I used SDCC on an 8-bit PIC project a number of years back and found it to be very good there. It managed to cover the data banking almost transparently, so maybe there is hope for it on the '816 too in the future?
-Gordon
-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Re: SDCC for 6502
Great news. I also used SDCC for an embedded 8051 project many years ago and found it very capable. It looks to also have support for the 65C02.
Re: SDCC for 6502
I played a little last night with SDCC-4.2.0 (the latest version) in a Linux Mint environment.
First thoughts:
- There is apparently no documentation regarding the 6502, other than a couple of mentions in the sdccman.pdf. Grepping doesn't find anything useful.
- Obviously, putchar() has to be defined if you want to use text input. The error message if you don't complains about a missing '_putchar' but it does not want that leading underscore.
- You're also going to have to include any necessary initialisation of the input mechanism (in my case, it will be a 68B50 uart).
- The mystic incantation (discovered after some trial and error) to build for 6502 is 'sdcc -mmos6502 hello.c' which rather implies that it's assembling base NMOS code (which I'm old-school enough to be happy about; it might not be optimal on a WDC part but it'll run on anything). It didn't like -65c02 or -wdc65c02.
- It seems to be assuming a flat memory model with 64k ram. The hex file starts with a single line: which points the reset, nmi, and irq vectors to $0200.
- The simple test file (as yet unrun, and note it doesn't have the uart initialisation!)
produces a hex file with code from $0200 to $0d30 or thereabouts. I assume that's because it's dragging in the stdio library - printf is always a code hog even without floating point.
Neil
First thoughts:
- There is apparently no documentation regarding the 6502, other than a couple of mentions in the sdccman.pdf. Grepping doesn't find anything useful.
- Obviously, putchar() has to be defined if you want to use text input. The error message if you don't complains about a missing '_putchar' but it does not want that leading underscore.
- You're also going to have to include any necessary initialisation of the input mechanism (in my case, it will be a 68B50 uart).
- The mystic incantation (discovered after some trial and error) to build for 6502 is 'sdcc -mmos6502 hello.c' which rather implies that it's assembling base NMOS code (which I'm old-school enough to be happy about; it might not be optimal on a WDC part but it'll run on anything). It didn't like -65c02 or -wdc65c02.
- It seems to be assuming a flat memory model with 64k ram. The hex file starts with a single line:
Code: Select all
:06FFFA00000200020002FB- The simple test file (as yet unrun, and note it doesn't have the uart initialisation!)
Code: Select all
#include <stdio.h>
char * ACIAStatus = 0xa000;
char * ACIAData = 0xa001;
int putchar(int ch);
int putchar(int ch)
{
while (((*ACIAStatus) & 0x02) == 0x02) {}
*ACIAData = (char)ch;
return ch;
}
void main (void)
{
printf ("hello world");
}Neil
Re: SDCC for 6502
Try puts instead of printf and see how much baggage you omit...
Re: SDCC for 6502
As expected: it's a lot smaller. As I said, printf is a memory hog on every small microcontroller; it drags in too much baggage with it even without floating point.
Neil
Code: Select all
:06FFFA00000200020002FB
:20020000A2FF9AA9388D0680A9038D0780A9048D0880A9008D0980A900A280207902A9005F
:1A0220008D0A80A90B8D0B80A9008D0C80A904A28020B7022072024C37025E
:20023A008D04808E0580AD00808520AD01808521A000B120A20029024868C902D004E0006D
:1F025A00F0E4AD02808534AD03808535AD04809134AE0580AD048060A203A92C4C02035A
:10032C0068656C6C6F20776F726C640000A001A024
:20027900852C862D852E862FAD06808530AD07808531A000AE0980F013B130912EC8B130A4
:1E029900912EC8D0F4E631E62FCAD0EDAE0880F008B130912EC8CAD0F8A52CA62D601D
:2002B7008D0D808E0E80AE0B80AC0C80AD0C800D0B80F030AD0D808535AD0E808536AD0AEE
:2002D7008085348420A534A0009135A420E635D002E6368A38E901AA98E900A8C000D0020D
:0B02F700E000D0DFAE0E80AD0D806097
:20030200852A862BA000B12AC900F017E62AD002E62BA200203A02C9FFD0E9E0FFD0E5A981
:0A032200FFAA60A200A90A4C3A02EB
:00000001FFRe: SDCC for 6502
I've been playing a little with the sdcc compiler; it's not bad at first glance but it's missing some obvious optimisations:
Those ACIA pointers should be constant pointers to a volatile char - the register content. However, it produces the following assembly:
where it has obviously defined the pointer as a word in memory; it copies it to a temporary word, and reads the byte using (abs),y. It also loops back and loads the pointer address every time. This is obviously generic so a pointer can change between calls - but one might have hoped that the const keyword would have allowed it to avoid the indirect load and the repeated load. Indeed, the ideal optimisation is perhaps a simple lda abs to the register... oh well, the whole point of C is that you don't have to worry about these things 
Another bit which is somewhat confusing this early in the morning is if one replaces the
with the hopefully more self-documenting but theoretically identical operation
which changes the generated assembly to
Which includes the requested test but leaves an unnecessary pha/pla hanging around.
All very interesting, but this is the first release. At present there is zero documentation either in the installed codebase or on the wiki page associated; I may have to join their forum so at least I can ask some questions.
I think I'll knock up a quick monitor and see how that works. I've got lots of eeprom space
Neil
Code: Select all
// pointers to the ACIA registers
volatile char * const ACIAStatus = 0xa000;
volatile char * const ACIAData = 0xa001;
int putchar(int ch)
{
// blocking write to the serial port
while ((*ACIAStatus) & 0x02) {}
*ACIAData = (char)ch;
return ch;
}
Code: Select all
_putchar:
sta _putchar_ch_65536_38
stx (_putchar_ch_65536_38 + 1)
; monitor.c: 35: while ((*ACIAStatus) & 0x02) {}
00101$:
lda _ACIAStatus
sta *(__TEMP+0)
lda (_ACIAStatus + 1)
sta *(__TEMP+1)
ldy #0x00
lda [__TEMP+0],y
and #0x02
bne 00101$
; monitor.c: 36: *ACIAData = (char)ch;
lda _ACIAData
sta *_putchar_sloc0_1_0
lda (_ACIAData + 1)
sta *(_putchar_sloc0_1_0 + 1)
lda _putchar_ch_65536_38
sta [*_putchar_sloc0_1_0],y
; monitor.c: 37: return ch;
ldx (_putchar_ch_65536_38 + 1)
lda _putchar_ch_65536_38
; monitor.c: 38: }
rts
Another bit which is somewhat confusing this early in the morning is if one replaces the
Code: Select all
while ((*ACIAStatus) & 0x02) {}
with the hopefully more self-documenting but theoretically identical operation
Code: Select all
while (0x02 == (*ACIAStatus) & 0x02) {}
which changes the generated assembly to
Code: Select all
00101$:
lda _ACIAStatus
sta *(__TEMP+0)
lda (_ACIAStatus + 1)
sta *(__TEMP+1)
ldy #0x00
lda [__TEMP+0],y
ldx #0x00
and #0x02
pha
pla
cmp #0x02
bne 00115$
cpx #0x00
beq 00101$
All very interesting, but this is the first release. At present there is zero documentation either in the installed codebase or on the wiki page associated; I may have to join their forum so at least I can ask some questions.
I think I'll knock up a quick monitor and see how that works. I've got lots of eeprom space
Neil
Re: SDCC for 6502
Another observation: as far as I recall no flags are set by simply loading a variable on the 6502, but require a cmp, cpx, or cpy operation (or playing games with the flag register via the stack).
In which case, this generated code looks suspicious:
It seems to me that the beq after 00113$ is dependent on the flags on entry to get_line, and not on an actual test. There is a jump to 0113$ later based on a comparison (buffer full) but also one later still which is just a jump.
Am I missing something obvious?
(I have not yet been able to get the code onto a real 6502; my development machine doesn't have the same GLIBC as this one and I'm a bit leery of updating it; there's too much on it. Hopefully over the weekend.)
Neil
In which case, this generated code looks suspicious:
Code: Select all
_get_line:
; monitor.c: 61: unsigned char inptr = 0; // eight bits are enough
ldx #0x00
stx _get_line_inptr_65536_46
; monitor.c: 62: char done = 0; // not done yet
stx _get_line_done_65536_46
; monitor.c: 65: while (0 == done)
00113$:
lda _get_line_done_65536_46
beq 00154$
rts
00154$:
; monitor.c: 67: inbuffer[inptr] = '\0';
ldx _get_line_inptr_65536_46
ldy #0x00
tya
sta (_inbuffer+0+0x0000),x
...
Am I missing something obvious?
(I have not yet been able to get the code onto a real 6502; my development machine doesn't have the same GLIBC as this one and I'm a bit leery of updating it; there's too much on it. Hopefully over the weekend.)
Neil
Re: SDCC for 6502
Hmm, no, you have that wrong unfortunately: loading a register does set N and Z. (Not so on all other micros, but true on 6502. If in doubt run a few instructions in an emulator: easy6502 is right there in your browser, for example.)
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: SDCC for 6502
As stated in the "programming tips" section of the 6502 primer at http://wilsonminesco.com/6502primer/PgmTips.html, an automatic compare-to-zero instruction is built into the following 65c02 instructions: LDA, LDX, LDY, INC, INX, INY, DEC, DEX, DEY, INA, DEA, AND, ORA, EOR, ASL, LSR, ROL, ROR, PLA, PLX, PLY, SBC, ADC, TAX, TXA, TAY, TYA, and TSX. This means that, for example, a CMP #0 after an LDA is redundant, a wasted instruction. A kitten somewhere dies every time you do that!
The only time a 65c02 (CMOS) needs a compare-to-zero instruction after one of these is if you want to compare a register that was not involved in the previous instruction. Store instructions (STA, STX, STY) however do not affect status.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: SDCC for 6502
Thank you gents! I thought I knew this processor - it's only been forty years since I used one in anger
So I looked in the Zaks that's been open on my desktop for the last month and there it is, plain as day... doh!
I think I got confused with the 8080 which I've been recreating at logic level; that one does require an ALU operation to set the flags and the register move and load instructions don't set flags. https://www.pastraiser.com/cpu/i8080/i8080_opcodes.html
Thanks again; I'll keep on plugging on at understanding this compiler.
So I looked in the Zaks that's been open on my desktop for the last month and there it is, plain as day... doh!
I think I got confused with the 8080 which I've been recreating at logic level; that one does require an ALU operation to set the flags and the register move and load instructions don't set flags. https://www.pastraiser.com/cpu/i8080/i8080_opcodes.html
Thanks again; I'll keep on plugging on at understanding this compiler.
Re: SDCC for 6502
Getting a little further with the secret incantations:
tells the linker to put the assembled code at 0xe000 (in my eeprom space) and to use from 0x0200 for constants and variables. Default values without --code-loc is to build at 0x0200 and it puts the bss at 0x8000 (where I have an empty hole in the memory map) without the --xram-loc. A --data-loc looked like the obvious switch for the bss but instead it moves the zero page variables...
That done, the code
produces
which outputs the expected '#' from the 68B50.
Neil
Code: Select all
sdcc -mmos6502 monitor.c --code-loc 0xe000 --xram-loc 0x0200tells the linker to put the assembled code at 0xe000 (in my eeprom space) and to use from 0x0200 for constants and variables. Default values without --code-loc is to build at 0x0200 and it puts the bss at 0x8000 (where I have an empty hole in the memory map) without the --xram-loc. A --data-loc looked like the obvious switch for the bss but instead it moves the zero page variables...
That done, the code
Code: Select all
*ACIAStatus = 0x95;
*ACIAData = '#';
Code: Select all
; monitor.c: 140: *ACIAStatus = 0x95;
ldx _ACIAStatus
ldy (_ACIAStatus + 1)
stx *(__TEMP+0)
sty *(__TEMP+1)
lda #0x95
ldy #0x00
sta [__TEMP+0],y
; monitor.c: 142: *ACIAData = '#';
ldx _ACIAData
ldy (_ACIAData + 1)
stx *(__TEMP+0)
sty *(__TEMP+1)
lda #0x23
ldy #0x00
sta [__TEMP+0],y
Neil
Re: SDCC for 6502
> secret incantations
That's good to know, thanks!
That's good to know, thanks!
Re: SDCC for 6502
When I get to a more complete state of knowledge, I'll knock up a quick how-to. The main things I need to know are
- How to compile anything! (done)
- How to compile code to a given memory map (done)
- How to handle interrupts and the BRK instruction
- How to include assembly code directly