Calypsi C compiler toolchain for 6502 and 65816

Programming the 6502 microprocessor and its relatives in assembly and other languages.
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

This is great! I have a SuperCPU 128 for the Commodore 128. Will be looking into this with great interest.
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

Please consider at least running a github if only for your example code and updated binaries so that we can post issues. Since this appears to be the only place to talk with you and provide feedback, I have no choice but to post a long message.

Im creating a c64 target (for the supercpu), but calls to main() are always a byte or two off.

Heres the build commands:

Code: Select all

as65816 c64startup.asm -o c64startup.o -l --code-model small --data-model large
as65816 c64.asm -o c64.o -l --code-model small --data-model large
cc65816 test.c -o test.o -l --code-model small --data-model large
ln65816  test.o c64.o  c64startup.o  rules.scm  clib-sc-ld.a --rtattr cstartup=c64startup --output-format raw -l --cross-reference 
Here is my cstartup.s (with my modifications):

Code: Select all

            .rtmodel cstartup,"c64startup"

            .rtmodel version, "1"
            .rtmodel cpu, "*"

            .section stack
            .section cstack
            .section heap
            .section data_init_table

            .extern main, exit
            .extern _Dp, _Vfp
            .extern _DirectPageStart

#ifndef __CALYPSI_DATA_MODEL_SMALL__
            .extern _NearBaseAddress
#endif

#include "macros.h"

;;; ***************************************************************************
;;;
;;; The reset vector. This uses the entry point label __program_root_section
;;; which by default is what the linker will pull in first.
;;;
;;; ***************************************************************************

              .section reset
              .pubweak __program_root_section
__program_root_section:
              .word   __program_start


;;; ***************************************************************************
;;;
;;; __program_start - actual start point of the program
;;;
;;; Set up CPU stack, initialize sections and call main().
;;; You can override this with your own routine, or tailor it as needed.
;;; The easiest way to make custom initialization is to provide your own
;;; __low_level_init which gets called after stacks have been initialized.
;;;
;;; ***************************************************************************

    .section code,noreorder
    .pubweak __program_start
__program_start:
    ; provides BASIC startup: "10 SYS 2062"
    .byte 0x01, 0x08    ; always zero, load address
    .byte 0x07, 0x08    ; pointer to next line
    .byte 0x0A, 0x00    ; line number (10)
    .byte 0x9e          ; SYS token    
    .ascii " 2062"      ; SYS address in ASCII
    .byte 0, 0, 0       ; end-of-program
    
              clc
              xce                   ; native 16-bit mode
              rep     #0x38         ; 16-bit registers, no decimal mode
              ldx     ##.sectionEnd stack
              txs                   ; set stack
              lda     ##_DirectPageStart
              tcd                   ; set direct page
#ifdef __CALYPSI_DATA_MODEL_SMALL__
              lda     ##0
#else
              lda     ##.word2 _NearBaseAddress
#endif
              stz     dp:.tiny(_Vfp+2)
              xba                   ; A upper half = data bank
              pha
              plb                   ; pop 8 dummy
              plb                   ; set data bank


;;; **** Initialize data sections if needed.
;              .section code, noroot, noreorder
;              .pubweak __data_initialization_needed
;              .extern __initialize_sections
;__data_initialization_needed:
;              lda     ##.word2 (.sectionEnd data_init_table)
;              sta     dp:.tiny(_Dp+6)
;              lda     ##.word0 (.sectionEnd data_init_table)
;              sta     dp:.tiny(_Dp+4)
;              lda     ##.word2 (.sectionStart data_init_table)
;              sta     dp:.tiny(_Dp+2)
;              lda     ##.word0 (.sectionStart data_init_table)
;              sta     dp:.tiny(_Dp+0)
;              call    __initialize_sections

;;; **** Initialize streams if needed.
;              .section code, noroot, noreorder
;              .pubweak __call_initialize_global_streams
;              .extern __initialize_global_streams
;__call_initialize_global_streams:
;              call    __initialize_global_streams

;;; **** Initialize heap if needed.
;              .section code, noroot, noreorder
;              .pubweak __call_heap_initialize
;              .extern __heap_initialize, __default_heap
;__call_heap_initialize:
;#ifdef __CALYPSI_DATA_MODEL_SMALL__
;              lda     ##.sectionSize heap
;              sta     dp:.tiny(_Dp+2)
;              lda     ##.sectionStart heap
;              sta     dp:.tiny(_Dp+0)
;              lda     ##__default_heap
;#else
;              lda     ##.word2 (.sectionStart heap)
;              sta     dp:.tiny(_Dp+6)
;              lda     ##.word0 (.sectionStart heap)
;              sta     dp:.tiny(_Dp+4)
;              lda     ##.word2 __default_heap
;              sta     dp:.tiny(_Dp+2)
;              lda     ##.word0 __default_heap
;              sta     dp:.tiny(_Dp+0)
;              ldx     ##.word2 (.sectionSize heap)
;              lda     ##.word0 (.sectionSize heap)
;#endif
;              call    __heap_initialize

              .section code, root, noreorder
              lda     ##0           ; argc = 0
              call    main
              rts
https://imgur.com/a/9lfFU4o
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

heres some more info:

Code: Select all

.C:0826  20 2C 08    JSR $082C
.C:0829  60          RTS
.C:082a  A9 00       LDA #$00
.C:082c  00          BRK
.C:082d  6B          RTL
whats happening here is that the JSR to call main (082a) is instead skipping two bytes and hitting the BRK. Looks like a problem in the linker perhaps.
John West
Posts: 383
Joined: 03 Sep 2002

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by John West »

How does __program_start get its value? C64 program files start with a two byte load address, which you are providing. But those bytes do not get loaded. If __program_start is $0801, the assembler will believe that everything is two bytes higher than it actually is.

If you can set it to $07ff, then the first bytes to be loaded (.byte 0x07, 0x08) will be at $0801, everything will be where it should be, and it should start working.
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

It actually properly creates the BASIC portion as is.
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

John - your note gave me an idea.. the load address isnt really code, so I tried dropping it, doing the compile, and then adding it back using a hex editor after the prg file was created. Seems to work now. I guess a post build step would be needed afterward to add the load address. Thank you!
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

a question for OP. docs say:
Quote:
18.3 Calling convention
The calling convention is fairly complex in all its details, but for most common situations it is reasonable
simple.
If parameters are passed on the stack the caller is responsible for doing any cleanup. The called function can
use any register resource, but it must obey that certain registers are to be preserved. If using registers that
shall be preserved, the called function is responsible for saving the current value and then restore it before
giving control back.
Parameters are passed in the A accumulator, index register X and pseudo registers _Dp[0-7].
Registers A, X, Y and pseudo registers 07 are destroyed by a function call. Pseudo registers 815 must be
preserved.
What determines when parameters are passed on the stack vs registers?
hth313
Posts: 30
Joined: 07 Oct 2018

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by hth313 »

xlar54 wrote:
Please consider at least running a github if only for your example code and updated binaries so that we can post issues. Since this appears to be the only place to talk with you and provide feedback, I have no choice but to post a long message.

Im creating a c64 target (for the supercpu), but calls to main() are always a byte or two off.

Heres the build commands:

Code: Select all

as65816 c64startup.asm -o c64startup.o -l --code-model small --data-model large
as65816 c64.asm -o c64.o -l --code-model small --data-model large
cc65816 test.c -o test.o -l --code-model small --data-model large
ln65816  test.o c64.o  c64startup.o  rules.scm  clib-sc-ld.a --rtattr cstartup=c64startup --output-format raw -l --cross-reference 
You should use --output-format=prg for Commodore 64 rather than raw. It adds the start address before raw output, otherwise these format are the same.

For the Commodore 64 and similar projects, you could use the https://github.com/hth313/Calypsi-6502-Commodore project. That is intended for board support for C64 and related computers. I will consider a more generic Calypsi project on Github for issues that does not fit into particular board support.
hth313
Posts: 30
Joined: 07 Oct 2018

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by hth313 »

xlar54 wrote:
a question for OP. docs say:

What determines when parameters are passed on the stack vs registers?
The safest is to look at the generated code. What it does is to scan the parameter list left to right and bind registers in a given order. First it uses the CPU register(s) for a single parameter, then it will take the DP pseudo registers. If a parameter cannot fit in register, it will look further down the parameter list for a possible candidate to put in register.
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

hth313 wrote:
xlar54 wrote:
Please consider at least running a github if only for your example code and updated binaries so that we can post issues. Since this appears to be the only place to talk with you and provide feedback, I have no choice but to post a long message.

Im creating a c64 target (for the supercpu), but calls to main() are always a byte or two off.

Heres the build commands:

Code: Select all

as65816 c64startup.asm -o c64startup.o -l --code-model small --data-model large
as65816 c64.asm -o c64.o -l --code-model small --data-model large
cc65816 test.c -o test.o -l --code-model small --data-model large
ln65816  test.o c64.o  c64startup.o  rules.scm  clib-sc-ld.a --rtattr cstartup=c64startup --output-format raw -l --cross-reference 
You should use --output-format=prg for Commodore 64 rather than raw. It adds the start address before raw output, otherwise these format are the same.

For the Commodore 64 and similar projects, you could use the https://github.com/hth313/Calypsi-6502-Commodore project. That is intended for board support for C64 and related computers. I will consider a more generic Calypsi project on Github for issues that does not fit into particular board support.
I might have an older version of the compiler, as prg isnt an option. Mine is v3.5.1. (Also note that Im using the 65816 target as the supercpu has an 65816 in it)

Code: Select all

F:\Software\Emulation\Commodore\Development\projects\8086tiny\64test>ln65816  test.o c64.o  c64startup.o  rules.scm  clib-sc-ld.a --rtattr cstartup=c64startup --output-format prg -l --cross-reference 
option --output-format: unexpected "pr" or 'p'
expecting "intel-hex", "pgz", "raw", or "s-record"
Last edited by xlar54 on Fri Feb 25, 2022 1:47 am, edited 1 time in total.
xlar54
Posts: 28
Joined: 18 Oct 2017

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by xlar54 »

hth313 wrote:
xlar54 wrote:
a question for OP. docs say:

What determines when parameters are passed on the stack vs registers?
The safest is to look at the generated code. What it does is to scan the parameter list left to right and bind registers in a given order. First it uses the CPU register(s) for a single parameter, then it will take the DP pseudo registers. If a parameter cannot fit in register, it will look further down the parameter list for a possible candidate to put in register.
Ok, and then anything it cant place in a register, it puts on the stack?
User avatar
Sheep64
In Memoriam
Posts: 311
Joined: 11 Aug 2020
Location: A magnetic field

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by Sheep64 »

Thank you for working on a C compiler. The 6502 Forum can be a tough crowd and I've had difficulty complimenting work on a C compiler. Although many people are dis-inclined to support C on 6502, that has been a futile objection since cc65 was released.

To obtain trustworthy execution of C on 6502, we require three or more compilers which are able to compile each other - or another technique yet to be discovered/published. In 1984, Ken Thompson's Reflections on Trusting Trust explained how to hide malware in a compiler. The malware, as implemented and distributed, was a quine which identified when the compiler was being compiled and added a branch to the parse tree. The purpose of the branch was to identify compilation of the Unix login program and also modify its parse tree. This allowed a specific username/password to obtain elevated privileges on any affected system. Compilation of the compiler or login program produced the same binary and none of the unwanted functionality appeared in the source code.

Eliminating such quines requires three or more independent compilers where there is no collusion. This specifically requires compilers which are maintained in separate repositories and are maintained by teams without overlap.

Thank you for being one of these critical teams.
xlar54 on Wed 23 Feb 2022 wrote:
Please consider at least running a github if only for your example code and updated binaries so that we can post issues.
Please do not host any operating system or language with a subsidiary of a direct competitor and convicted monopolist. The 6502 Forum already has difficulty with a Microsoft subsidiary regarding email. We don't need problems with another subsidiary. Actually, I believe that it is highly questionable to host the primary copy of EhBASIC on Github. That'll work until it doesn't.

Of particular note for a C compiler, Github restricts the names of insecure POSIX functions. There is no such restriction for insecure Microsoft functions.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by BigEd »

Please, don't bother with the "convicted monopoly" stuff - it's not the case that "the forum has trouble with" any supplier or company - it's only true, and can only be true, that specific people hold particular opinions.

It never moves a conversation forward in a good way to make these kinds of value-laden comments, or to repeat them. It's just tribal signalling. We do very much better here, in a technical hobby, to put all those things aside, and stick to the technical topics.
hth313
Posts: 30
Joined: 07 Oct 2018

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by hth313 »

Just to let you know that my C compiler tools are now available from https://www.calypsi.cc/

I released 3.6.2 yesterday, but I do not plan to post here every time I make a release in the future, just check the page out from time to time if you are interested.
hth313
Posts: 30
Joined: 07 Oct 2018

Re: Calypsi C compiler toolchain for 6502 and 65816

Post by hth313 »

xlar54 wrote:

Ok, and then anything it cant place in a register, it puts on the stack?
Yes, any parameter that is not placed in a register is placed on the stack. For the 65816 it is the hardware stack and for the 6502 it uses a simulated stack that can be up to 64K (provided you have RAM and space for it).

Sorry for the late answer.
Post Reply