Forum: Compiler & IDEs 6502 C-Compiler cc65


von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Im Moment versuche ich gerade, Assemblercode für den Junior-Computer mit 
dem C-Compiler zu erzeugen.
1
[
2
/*
3
 * Blinking an LED connected to PORTB0 of a Junior Computer
4
 *
5
 * compile blink.c
6
7
 *
8
 * 2025-05-28 mchris
9
 *
10
 */
11
12
// MOS6532 PIA addrese $1A80
13
#define PBD             (*(volatile unsigned char*)0x1A82)
14
#define PBDD            (*(volatile unsigned char*)0x1A83)
15
#define TIMER_READ      (*(volatile unsigned char*)0x1A84)
16
#define TIMER_DIV1024   (*(volatile unsigned char*)0x1A97)
17
18
void blink(void)
19
{
20
    // init PORTB0 as output
21
    PBDD=1;
22
    while(1)
23
    {
24
        TIMER_DIV1024=248;      // init timer for clkdiv=1024 and start=248
25
        while(TIMER_READ!=0);   // wait until timer is zero
26
        PBD^=1;                 ^// toggle PORTB0
27
    }
28
}
Mit der Befehlszeile
cc65 -O -t none blink.c
läst sich das folgende Assembler-File erzeugen:
1
;
2
; File generated by cc65 v 2.18 
3
;
4
  .fopt    compiler,"cc65 v 2.18 "
5
  .setcpu    "6502"
6
  .smart    on
7
  .autoimport  on
8
  .case    on
9
  .debuginfo  off
10
  .importzp  sp, sreg, regsave, regbank
11
  .importzp  tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
12
  .macpack  longbranch
13
  .export    _blink
14
15
; ---------------------------------------------------------------
16
; void __near__ blink (void)
17
; ---------------------------------------------------------------
18
19
.segment  "CODE"
20
21
.proc  _blink: near
22
23
.segment  "CODE"
24
25
  lda     #$01
26
  sta     $1A83
27
L0014:  lda     #$F8
28
  sta     $1A97
29
L0015:  lda     $1A84
30
  bne     L0015
31
  lda     $1A82
32
  eor     #$01
33
  sta     $1A82
34
  jmp     L0014
35
36
.endproc
Was gar nicht so schlecht aussieht, wenn man es mit dem originale 
Assemblerfile, anhand dessen der C-Code erstellt wurde, vergleicht 
(siehe Anhang)

Das Problem: wie kann man aus diesem Assemblerfile den Binärcode 
erstellen, so dass er an der Adresse 0x300 beginnt?

Links:
cc65 : https://cc65.github.io/

Junior Computer: 
http://retro.hansotten.nl/6502-sbc/elektuur-junior/junior/base-elektor-junior/

von Andras H. (andras_h)


Lesenswert?

Fehlt da nicht noch ein main und der C-Startup davor? Oder wie soll die 
C Umgebung aufgesetzt werden?

von Christoph M. (mchris)


Lesenswert?

Andras H. (andras_h)
28.05.2025 16:45
>Fehlt da nicht noch ein main und der C-Startup davor? Oder wie soll die
>C Umgebung aufgesetzt werden?

Denke ich auch. Aber es werden ja die gleichen Befehle wie im oben 
angehängten 'Original' Assemblerprogramm (blink.asm) erzeugt und das 
braucht ja auch keinen Startup-Code.

: Bearbeitet durch User
von Andras H. (andras_h)


Lesenswert?

Na ja, ich würde trozdem über den main laufen wollen. Vor allem, wenn 
der Compiler richtig den CPU supported, dann ist da schon alles fertig, 
und man hat später alle vorteile (?). Es wird auch einfacher zu testen.

Sonst Compiler Manual aufmachen und gucken, ob man irgendwie 
handgeschriebene asm befehle reintun kann. Meisst geht das mit asm("") 
oder _asm. Damit kann man beliebig hacken.

Aber ich würde erstmals den Hello Word empfehlen. Damit man guckt ob die 
Umgebung richtig funktioniert. Wenn das geht, dann würde ich versuchen 
irgendwie davon abweichen. Zum beispiel etwas ohne den startup code zu 
bauen.

von Bernhard K. (bkom)


Lesenswert?

Beim cc65: nach dem Compile muss erst der Assembler
Und dann der Linker mit einem config-File aufgerufen werden:
In etwa so:

cc65 -O -t none blink.c
ca65 -l -cpu 65sc02 blink.s
ld65  -C deinesystemconfig.cfg blink.o -o blink.out

Das Config-File "deinesystemconfig.cfg" muss auf dein System passen,
Beispiele in "deinPfadzumcc65/lib/cc65/cfg" ...

Config-File Doku:
https://cc65.github.io/doc/ld65.html#s5

von Christoph M. (mchris)


Angehängte Dateien:

Lesenswert?

Bernhard K. (bkom)
28.05.2025 17:48
> cc65 -O -t none blink.c
> ca65 -l -cpu 65sc02 blink.s
> ld65  -C deinesystemconfig.cfg blink.o -o blink.out

Danke für den Hinweis.
Wie so oft, liegen die Probleme in den "filigranen" Details und mag an 
meiner cc65-Version
**ca65 V2.18 - Ubuntu 2.19-1
liegen, die standardmäßig im Ubuntu-Repo zu finden ist. Wenn ich in das 
Github-Repo des cc65 schaue, ist da ja eine ständige Weiterentwicklung 
zu sehen:
https://github.com/cc65/cc65

Mein Befehlssequenz sieht jetzt folgendermaßen aus (cfg und startup file 
im Anhang):
1
# C-Source nach Assembler konvertieren
2
cc65 -O -t none blink.c
3
4
# Assembler file compilieren
5
ca65 -l blink.lst blink.s
6
#( Listfile -l braucht filnamen )
7
8
#Startup script wird gebraucht und muss compiliert werden
9
cl65 -t none -c crt0.s -o crt0.o
10
11
# alles zusammenbauen: Link startup blink und startup-Code
12
ld65 -C junior.cfg crt0.o blink.o -o blink.bin
Aber es darf ja nichts zu einfach sein: Im Startup-Code muss ich das 
'jsr main' auskommentieren. Aus irgendwelchen Gründen wird das 'main' 
nicht gefunden ..

von Klaus (feelfree)


Lesenswert?

Christoph M. schrieb:
> Aus irgendwelchen Gründen wird das 'main' nicht gefunden ..

Wenn sich die Aussage auf dein im Eröffnungsbeitrag vorgestelltes 
blink.c bezieht, dann ist der Grund ganz offensichtlich.

von Christoph M. (mchris)


Lesenswert?

Klaus (feelfree)
29.05.2025 08:31

>Wenn sich die Aussage auf dein im Eröffnungsbeitrag vorgestelltes
>blink.c bezieht, dann ist der Grund ganz offensichtlich.

Nicht ganz. Ersetzte den Funktionsnamen 'blink' durch 'main' und es wird 
trotzdem nicht gehen.

von Harald K. (kirnbichler)


Lesenswert?

Christoph M. schrieb:
> Wie so oft, liegen die Probleme in den "filigranen" Details und mag an
> meiner cc65-Version
> **ca65 V2.18 - Ubuntu 2.19-1
> liegen, die standardmäßig im Ubuntu-Repo zu finden ist.

... ein anderer auch aktiv gepflegter Compiler ist SDCC:
https://sdcc.sourceforge.net/

von Christoph M. (mchris)


Lesenswert?

Harald K. (kirnbichler)
29.05.2025 11:13
> ... ein anderer auch aktiv gepflegter Compiler ist SDCC:
> https://sdcc.sourceforge.net/

Beim cc65
https://github.com/cc65/cc65
schreiben sie:
cc65 is originally based on the "Small C" compiler by Ron Cain and 
enhanced by James E. Hendrix.

von Klaus (feelfree)


Lesenswert?

Christoph M. schrieb:
> Ersetzte den Funktionsnamen 'blink' durch 'main' und es wird
> trotzdem nicht gehen.

Aus dem main() im .c-source wird beim compilieren im .s ein _main 
exportiert, warum auch immer - ich kenne mich damit nicht aus.
Das auskommentieren von jsr main würde dazu führten, dass blink nie 
ausgeführt wird. Stattdessen könnte man im crt.s main zu _main ändern.

: Bearbeitet durch User
von Christoph M. (mchris)


Lesenswert?

Klaus (feelfree)
29.05.2025 12:54

> Aus dem main() im .c-source wird beim compilieren im .s ein _main
> exportiert, warum auch immer

Das sind die 'filigranen' Details, von denen ich oben geschrieben hatte. 
Ein kleiner Unterstrich "_" macht den Unterschied, ob es geht oder nicht 
geht.
Mit dem Unterstrich kann man das erste Beispiel kompilieren .. ein 
erster Erfolg.

Aber die Welt darf ja nicht zu einfach sein. Will ich das 
Tonleiterprogramm kompilieren, welches Funktionsaufrufe aus der 'main' 
enthält
1
#include <stdint.h>
2
3
#define PBD             (*(volatile unsigned char*)0x1A82)
4
#define PBDD            (*(volatile unsigned char*)0x1A83)
5
6
void shortdelay(uint8_t x)
7
{
8
    do
9
    {
10
        x--;
11
    }while(x!=0);
12
}
13
14
void playnote(uint8_t n)
15
{
16
    uint8_t duration=50;
17
18
    do
19
    {
20
        shortdelay(n);
21
        shortdelay(0);
22
23
        PBD^=1;                 // toggle PORTB0
24
25
        duration--;
26
    }while(duration!=0);
27
}
28
29
void main(void)
30
{
31
    // init PORTB0 as output
32
    PBDD=1;
33
    while(1)
34
    {
35
        playnote(200);
36
        playnote(158);
37
    }
38
}
Werden die Stack Funktionen des C-Systems vermisst.
1
Linking temp.o and crt0.o, creating temp.bin
2
Unresolved external 'incsp1' referenced in:
3
  temp.s(36)
4
Unresolved external 'incsp2' referenced in:
5
  temp.s(68)
6
Unresolved external 'pusha' referenced in:
7
  temp.s(28)
8
  temp.s(50)
9
  temp.s(52)
10
Unresolved external 'sp' referenced in:
11
  temp.s(54)
12
  temp.s(62)
13
  temp.s(65)
14
  temp.s(66)
15
  temp.s(30)
16
  temp.s(33)
17
  temp.s(34)
Es fehlt als das nächste Puzzelstück im großen Kompiler-Abenteuerspiel.

von Klaus (feelfree)


Lesenswert?

Christoph M. schrieb:
> Aber die Welt darf ja nicht zu einfach sein.

Nun ja, wer für einen 45 Jahre alten Einplatinenrechner ohne vernünftige 
Ein/Ausgabemöglichkeiten plötzlich eine Toolchain incl. C-Compiler haben 
will, kann halt nicht davon ausgehen, dass vor ihm schonmal jemand so 
verrrückt war, das auszuprobieren ...

von Thomas W. (datenreisender)


Lesenswert?

Klaus schrieb:
> Christoph M. schrieb:
>> Aber die Welt darf ja nicht zu einfach sein.
>
> Nun ja, wer für einen 45 Jahre alten Einplatinenrechner ohne vernünftige
> Ein/Ausgabemöglichkeiten plötzlich eine Toolchain incl. C-Compiler haben
> will, kann halt nicht davon ausgehen, dass vor ihm schonmal jemand so
> verrrückt war, das auszuprobieren ...

Und dann nicht auf richtiger Hardware sondern mit einem Emulator 
entwickelt: That's the new Frontier!

P.S.: Genial finde ich es trotzdem.

von Bernhard K. (bkom)


Lesenswert?

>
> # alles zusammenbauen: Link startup blink und startup-Code
> ld65 -C junior.cfg crt0.o blink.o -o blink.bin
>
> [/c]
>
Ich erinnere mich kaum noch - ist schon mehr als 15 Jahre her -
aber ich meine es fehlt noch "-t junior", die runtime-lib
für den Juniorcomputer gibts wahrscheinlich nicht, "-t kim" könnte
aber auch funktionieren ...

von Klaus (feelfree)


Lesenswert?

Bernhard K. schrieb:
>>
>> # alles zusammenbauen: Link startup blink und startup-Code
>> ld65 -C junior.cfg crt0.o blink.o -o blink.bin
>>
>> [/c]
>>
> Ich erinnere mich kaum noch - ist schon mehr als 15 Jahre her -
> aber ich meine es fehlt noch "-t junior", die runtime-lib
> für den Juniorcomputer gibts wahrscheinlich nicht, "-t kim" könnte
> aber auch funktionieren ...
1
ld65 -t none crt0.o playnote.o none.lib -o playnote.bin
macht den Trick.

von Christoph M. (mchris)


Lesenswert?

> Klaus (feelfree)
> 29.05.2025 16:30
1
ld65 -t none crt0.o playnote.o none.lib -o playnote.bin
>macht den Trick.

Jetzt scheint der Compiler das Linker-File zu ignorieren und statt das 
main an der gewünschten Adresse 0x300 anzuspringen, statt dessen nach 
0x1000 springt.

Mein Konfigurationsfile sieht so aus ( beim STACKSTART bin ich mir noch 
unsicher )
1
SYMBOLS {
2
    __STARTUP__:   type = import;
3
    __STACKSIZE__: type = weak, value = $0080;
4
    __STACKSTART__: type = weak, value = $0180;
5
}
6
MEMORY {
7
    ZP:       file = "", define = yes, start = $0000, size = $0100;
8
    CPUSTACK: file = "",               start = $0100, size = $0100;
9
    RAM:      file = %O, define = yes, start = $0300, size = $0800 - __STACKSIZE__;
10
}
11
SEGMENTS {
12
    ZEROPAGE: load = ZP,     type = zp;
13
    STARTUP:  load = RAM,    type = ro;
14
    LOWCODE:  load = RAM,    type = ro,  optional = yes;
15
    ONCE:     load = RAM,    type = ro,  optional = yes;
16
    CODE:     load = RAM,    type = ro;
17
    RODATA:   load = RAM,    type = ro;
18
    DATA:     load = RAM,    type = rw,  define   = yes;
19
    BSS:      load = RAM,    type = bss, define   = yes;
20
}
21
FEATURES {
22
    CONDES: type    = constructor,
23
            label   = __CONSTRUCTOR_TABLE__,
24
            count   = __CONSTRUCTOR_COUNT__,
25
            segment = ONCE;
26
    CONDES: type    = destructor,
27
            label   = __DESTRUCTOR_TABLE__,
28
            count   = __DESTRUCTOR_COUNT__,
29
            segment = RODATA;
30
    CONDES: type    = interruptor,
31
            label   = __INTERRUPTOR_TABLE__,
32
            count   = __INTERRUPTOR_COUNT__,
33
            segment = RODATA,
34
            import  = __CALLIRQ__;
35
}

von Klaus (feelfree)


Lesenswert?

Christoph M. schrieb:
> Jetzt scheint der Compiler das Linker-File zu ignorieren

Hab's ja auch nicht angegeben.
Probier's mal mit deinem -C junior.cfg statt -t none.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.
Lade...