cc65 equivalent instructions?

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
randomkiwi
Posts: 5
Joined: 26 Oct 2023

cc65 equivalent instructions?

Post by randomkiwi »

So I am writing a 6502 emulator, and now wants to test out some programs. I decided to generate the 6502 assembly from C using https://godbolt.org/. I wrote a simple program declaring two variables and then adding them and storing the result on a third variable. The generated assembly output using cc65 2.19 while makes sense, also includes several instructions which (I think) are not part of the original 6502 assembly, for example instructions like 'pushax', 'ldaxysp', 'tosaddax', 'incsp6', etc. I searched a bit, and I understood that since the memory supported by a 6502 processor is extremely small, the cc65 compiler maintains a software stack and these instructions I talked about are used to manipulate them.

Is my understanding correct? Secondly, is there a way to generate 'pure' 6502 assembly from C code, which I can just assemble to into opcodes and run in my emulator?
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: cc65 equivalent instructions?

Post by drogon »

I'd suggest you start by writing assembly from scratch and not try C - it's harder to write code, but easier to get the toolchain going.

Just start, one instruction at a time and (say) arrange your emulator to return after e.g. a BRK instruction.

When you think it's good enough you can run the Klauss tests on it for 6502 and 65C02.

https://github.com/Klaus2m5/6502_65C02_functional_tests

Although this site has the same tests, but edited for the ca65 assembler which you are (will be) using:

https://github.com/amb5l/6502_65C02_functional_tests

Hope it goes well.

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: cc65 equivalent instructions?

Post by BigEd »

Agreed that C isn't a great place to start. For a beginner, I recommend the easy6502 tutorial. (Don't get hung up on syntax differences between assemblers - that's of no importance. The important thing is the mental model you need to build.

Having said that...

Are you sure you're seeing instructions like that? I suspect you're seeing subroutine calls, to helper routines which cc65 makes use of.

I tried adding some compiler options (-Oi -Os --codesize 999 --static-locals), with this result
https://godbolt.org/z/sds77vzcT

where

Code: Select all

char sum(char a, b) {
    char z;
    z=a+b;
    return z;
}
is transformed to

Code: Select all

.proc   _sum: near

L0002:

        jsr     pushax
        ldy     #$00
        lda     (sp),y
        clc
        ldy     #$02
        adc     (sp),y
        sta     L0002
        ldx     #$00
        lda     L0002
        jmp     incsp3
which still has a couple of helpers, but hopefully clear enough from context as to what they are doing. If in further doubt, consult the cc65 documentation.
User avatar
Proxy
Posts: 746
Joined: 03 Aug 2018
Location: Germany

Re: cc65 equivalent instructions?

Post by Proxy »

randomkiwi wrote:
for example instructions like 'pushax', 'ldaxysp', 'tosaddax', 'incsp6', etc. I searched a bit, and I understood that since the memory supported by a 6502 processor is extremely small, the cc65 compiler maintains a software stack and these instructions I talked about are used to manipulate them.
those are not instructions, they are functions which the compiler calls to handle the software stack, there are also some more for stuff like multiplication, division, etc, these are supplied by the runtime library of whatever target you're using.
if you have a custom target without a runtime library then the linker will complain about those functions being missing.

as the other's suggested, maybe getting started with assembly would be a better idea. but if your end goal is getting C running then maybe start directly with ca65 (the assembler included with the cc65 utilities). it's a bit more complicated than other assemblers because it generates object files which need to be linked, but once you understand it and are comfortable with it, going from there to C will be a lot easier (plus you don't have to learn a different assembler syntax when writing assembly functions for cc65).
User avatar
Agumander
Posts: 129
Joined: 17 Jul 2018
Location: Long Island, NY
Contact:

Re: cc65 equivalent instructions?

Post by Agumander »

If you wanted to make it "pure" assembly you can look up the assembly for these routines in the CC65 source.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: cc65 equivalent instructions?

Post by BigEd »

BTW, to test out an emulator, one typical tactic is to try to run a Basic interpreter - any one of the usual ones. Another very useful tactic is to run Klaus Dormann's test suite, which is very thorough and has found errors in the great majority of emulators (since corrected, of course.)

To just get started, I would probably just take examples from anywhere - perhaps the easy6502 tutorial. Or example code from the reference section of this forum: http://6502.org/source/
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: cc65 equivalent instructions?

Post by drogon »

Since I have the time I'll write bit more...

To generate executable code from cc65 it needs a few more things than just the compiler. It's a more or less complete set of tools that work in the same way as "the big boys" tools do on a desktop or server system - compiler, assembler and linker. Additionally you need a target platform which specifies the code (& data) load and execution addresses.

The target lets you pick the machine you're running it on - there are many pre-defined such as Apple II, BBC Micro, Commodore PET, OSI and so on. These affect the libraries, load addresses and so on.

The godbolt site is as it says; a compiler explorer. It's designed to let you see and compare the output ff various compilers and not to generate actual runnable code.

So the first thing you need to do is get the cc65 suite installed locally.

Then just write a simple assembly program (and I'm assuming that as you've written an emulator you're familiar with 6502 assembler)

You can then assemble with

ca65 -g myfile.s -o myfile.o -l myfile.l

That generates a relocatable object file called myfile.o with a listing file of myfile.l

To turn this into an executable binary file then:

ld65 -t none -S 0x8000 -vm -m myfile.m -o myfile myfile.o

That takes your relocatable object file, converts it into a standalone binary with a starting address of $8000 and a map file of myfile.m.

Here is a small example: Add numbers in locations 0 and 1 and store the result in 2:

myfile.s:

Code: Select all

; Example
loop:
	clc
	lda	$0
	adc	$1
	sta	$2
	jmp   loop
the assemble command and list the output:

Code: Select all

% ca65 -g myfile.s -o myfile.o -l myfile.l
% cat myfile.l
ca65 V2.17 - Git cd72f816
Main file   : myfile.s
Current file: myfile.s

000000r 1               ; Example
000000r 1  18           	clc
000001r 1  A5 00        	lda	$0
000003r 1  65 01        	adc	$1
000005r 1  85 02        	sta	$2
000007r 1  4C rr rr     	jmp	loop
The 'r' in the address field means it's a relocatable value as is the 'rr' in the JMP instruction.

Linking and displaying the object file:

Code: Select all

% ld65 -t none -S 0x8000 -vm -m myfile.m -o myfile myfile.o
% odx myfile
000000 18 a5 00 65 01 85 02 4c 00 80                    >...e...L..<
Note the % symbol is my prompt and the odx command is a hex dump command I use. Also note the address after the 4C in the dump - 00 80 which the linker has translated into an absolute value based on the start address given on the command line.

There are many, many more ways to drive the cc65 suite but this is about the simplest.

Hope that helps....

Gordon
(Also writing an emulator after many years using real CPUs!)
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
johnwbyrd
Posts: 89
Joined: 01 May 2017

Re: cc65 equivalent instructions?

Post by johnwbyrd »

BigEd wrote:
I tried adding some compiler options (-Oi -Os --codesize 999 --static-locals), with this result
https://godbolt.org/z/sds77vzcT

where

Code: Select all

char sum(char a, b) {
    char z;
    z=a+b;
    return z;
}
is transformed to

Code: Select all

.proc   _sum: near

L0002:

        jsr     pushax
        ldy     #$00
        lda     (sp),y
        clc
        ldy     #$02
        adc     (sp),y
        sta     L0002
        ldx     #$00
        lda     L0002
        jmp     incsp3
which still has a couple of helpers [..]
llvm-mos compiles that same C code into maybe 80% fewer executed instructions:

Code: Select all

sum:                                    ; @sum
        stx     __rc2
        clc
        adc     __rc2
        rts
Verify for yourself: https://godbolt.org/z/a1Mn8PoYq

LLVM-MOS does not, in general, generate code that calls inline stack helper functions. There are no "pushax" or "incsp3" functions and the like inlined... it's all just generated assembly. Those called functions are not exactly cheap on cc65.
Post Reply