Compiling C and Assembly for Symon

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Quaker762
Posts: 7
Joined: 29 Sep 2014

Compiling C and Assembly for Symon

Post by Quaker762 »

Hey guys,
Sorry if this question has been answered a million times before, but I've researched a bit and haven't been able to come up with anything, so sorry for asking.

I've done systems programming before (writing small test operating systems in x86 assembly and C) and I've written a small CPU emulator, so I'm not new to the concepts involved with the 6502 (or assembly language), however, compiling my code is my weakest point. At the moment, I'm kind of stuck on how to properly use the cc65 toolchain to compile for the Symon Emulator. I have a windows script that would generate a flat binary file that Symon would correctly load, however, I don't believe it compiles correctly.

The issue I'm having is the linker is telling me that __STARTUP__ (which I assume is the entrypoint for my code) is unresolved, and it cannot create my output file (I left main out of the code and created another function and everything worked well). I'm completely stumped by how to go about resolving this, and any help would be greatly appreciated.

I then tried compiling a basic assembly file as a .prg, but I also wasn't too sure how to do that either, so it comes down to me not really knowing how to compile and link.
Note that eventually, this code will be built for a custom target, so I don't know how that's going to affected..

Any help would be greatly appreciated, and sorry if I posted this into the wrong board!
-Quaker762
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Compiling C and Assembly for Symon

Post by barrym95838 »

Welcome, Quaker762.

I believe that you posted to the correct board, so rest assured that a qualified expert will be around shortly to help. Unfortunately, I'm not that expert ... I've only experimented very tentatively with cc65 myself, and I will be following this thread to hopefully have my (similar) questions answered as well.

Mike
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: Compiling C and Assembly for Symon

Post by 8BIT »

The __STARTUP__ label originates in the crt0.s source file for your target. You get crt0.o after it's compiled and you include this as the FIRST file in your linker chain. I usually rename the crt0.o file to match my target, i.e. for my sbc4 target, it becomes sbc4.o.

I too use windows batch files. here's an example from one of my demo's:

Code: Select all

set CC65LIB=c:\cc65\lib
cl65 -t none -C sbc4.cfg -o hello.65b -m hello.map -l %CC65LIB%\sbc4.o hello.s %CC65LIB%\sbc4.lib
del *.o /Q >nul
pause
where sbc4.cfg is the config file for my target, hello.65b is the executable object file, hello.map is a reference map file (not needed), sbc4.o is the crt0.o file, hello.s is the source of the program being executed, and sbc4.lib is the library file for my target.

hope that helps!

Daryl
Please visit my website -> https://sbc.rictor.org/
Quaker762
Posts: 7
Joined: 29 Sep 2014

Re: Compiling C and Assembly for Symon

Post by Quaker762 »

8BIT wrote:
The __STARTUP__ label originates in the crt0.s source file for your target. You get crt0.o after it's compiled and you include this as the FIRST file in your linker chain. I usually rename the crt0.o file to match my target, i.e. for my sbc4 target, it becomes sbc4.o.

I too use windows batch files. here's an example from one of my demo's:

Code: Select all

set CC65LIB=c:\cc65\lib
cl65 -t none -C sbc4.cfg -o hello.65b -m hello.map -l %CC65LIB%\sbc4.o hello.s %CC65LIB%\sbc4.lib
del *.o /Q >nul
pause
where sbc4.cfg is the config file for my target, hello.65b is the executable object file, hello.map is a reference map file (not needed), sbc4.o is the crt0.o file, hello.s is the source of the program being executed, and sbc4.lib is the library file for my target.

hope that helps!

Daryl
Hey Daryl, thanks for the quick reply, but I still have issues/questions :?

I sort of understand what you mean, however my compiler isn't generating a crt0.s file for me. It might help if I show you how everything is structured:

In my directory, I have a file called kmain.c. This will be (hopefully) the main Kernel File for my OS. I then have a .cfg which consists of the following:

Code: Select all

MEMORY {
RAM1: start = $0200, size = $7F00;
ROM1: start = $C000, size = $4000, fill = yes;
}
SEGMENTS {
CODE: load = ROM1, type = ro;
DATA: load = ROM1, type = ro;
}
This is a config file that is specific to Symon so everything is aligned correctly.

My kmain.c consists of the basic:

Code: Select all

int main()
{
	return 0;
}
My build process consists of:

Code: Select all

SET PATH=%CC65_BIN%
REM COMPILE ALL C CODE IN .S FILES, BEFORE WE COMPILE AND THEN LINK THEM INTO A 16KB ALIGNED ROM
cc65 kmain.c -t none -Osir --cpu 6502
cl65 kmain.s -t none -C kern.cfg -o kern.bin
pause
However, during the linking stage, ld65 complains that: Unresolved external `__STARTUP__' referenced in:
ld65: Error: 1 unresolved external(s) found - cannot create output file


On further inspection of my kmain.s file, I found this,

Code: Select all

.forceimport	__STARTUP__
which I'm assuming is the cause of my trouble.

Seeing as there is no __STARTUP__ referenced ANYWHERE in my code, I'm still unsure how to resolve this.
Sorry for the lengthy post hahaha
-Quaker762

EDIT: Wait, is crt0.s meant to act as a bootloader?
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: Compiling C and Assembly for Symon

Post by 8BIT »

You will need to use a library file to allow you to use any C code. your <main> right now is essential empty, but as soon as you start adding code, it will fail to link without a library file. Yes, the crt0.s is a sort of a bootloader...

Here's my crt0.s for the sbc4 target:

Code: Select all

;
; Ullrich von Bassewitz, 17.06.1998
;
; Startup code for cc65
;
; This must be the *first* file on the linker command line
;
;
; Modified for SBC-4 by Daryl Rictor
;
	.export		_exit
	.export		__STARTUP__ : absolute = 1	; Mark as startup
	.import		__RAM_START__
	.import		initlib, donelib
	.import		callmain                      ;, callirq
	.import		zerobss                       ;, push0
;	.import		_main

	.include	"zeropage.inc"
	.include	"sbc4.inc"

;
; SBC-4 file format includes a 3 byte load address at the beginning of the file
; The EXEHDR segment places these three bytes at the beginning of the output file
;

.segment	"EXEHDR"

        .word           __RAM_START__			; Start address
        .byte		$00					; bank 0

.segment   "STARTUP"

; ------------------------------------------------------------------------
; Actual code

; Clear the BSS data

	jsr	zerobss

; setup the stack

	lda	#<TOPMEM
	sta	sp
	lda	#>TOPMEM
	sta	sp+1			; Set argument stack ptr

; Call module contructors

	jsr	initlib

; Push arguments and call main

	jsr	callmain

; Call module destructors. This is also the _exit entry.

_exit:
	jsr	donelib
	jmp	_osreturn		; SBC-4 DiskOS re-entry point

.bss

hicol:	.res	1
locol:	.res	1
curs:		.res	1
This might help you understand CC65 better:

http://cc65.github.io/cc65/doc/intro.html

Daryl
Please visit my website -> https://sbc.rictor.org/
Quaker762
Posts: 7
Joined: 29 Sep 2014

Re: Compiling C and Assembly for Symon

Post by Quaker762 »

Hi again,

I just stumbled upon how to create a custom target in the cc65 tutorial, so I have a correct library file, however I'm still getting some bizarre issues that I don't think I should be getting. I'm using the default crt0.s file as specified at:

http://www.cc65.org/doc/customizing-3.html,

and so have modified my linker cfg to better suit this code:

Code: Select all

MEMORY {
ZP: start = $0, size =  $100, type  = rw, define = yes;
RAM: start = $0200, size = $7F00;
ROM: start = $C000, size = $4000, fill = yes;
}
SEGMENTS {
ZEROPAGE:  load = ZP,  type = zp,  define   = yes;
STARTUP: load = ROM, type = ro;
INIT: load = ROM, type = ro;
CODE: load = ROM, type = ro;
DATA: load = ROM, type = rw;
BSS: load = RAM, type = bss, define = yes;
}
FEATURES {
    CONDES:    segment = STARTUP,
               type    = constructor,
               label   = __CONSTRUCTOR_TABLE__,
               count   = __CONSTRUCTOR_COUNT__;
    CONDES:    segment = STARTUP,
               type    = destructor,
               label   = __DESTRUCTOR_TABLE__,
               count   = __DESTRUCTOR_COUNT__;
}
However I still get Unresolved externals, which if I've followed the tutorial correctly, shouldn't be happening.
I'm sure it's merely errors in my linker file, as the errors I'm getting are:

Code: Select all

Unresolved external `__DATA_LOAD__' referenced in:
  common/copydata.s(13)
  common/copydata.s(15)
Unresolved external `__DATA_RUN__' referenced in:
  common/copydata.s(18)
  common/copydata.s(20)
Unresolved external `__DATA_SIZE__' referenced in:
  common/copydata.s(23)
  common/copydata.s(24)
Unresolved external `__RAM_SIZE__' referenced in:
  crt0.s(32)
  crt0.s(34)
Unresolved external `__RAM_START__' referenced in:
  crt0.s(32)
  crt0.s(34)
I'm confused, as __RAM_START__ and __RAM_SIZE__ should apparently be generated by the linker. Anything to do with __DATA_ seems to be related to the copydata import

I commented out the offending lines (just to test if it would even load in the emulator) and managed to get a compiled binary file, however I got no code execution whatsoever. The PC just incremented every step while giving me a BRK instruction.

I'm even more confused now, and have no idea what to do anymore :x
Again, sorry for asking such mundane questions.
-Quaker762
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: Compiling C and Assembly for Symon

Post by 8BIT »

You are making progress!

Can you post your batch file? It should have also changed to include your target library and crt0.o file.

Don't worry about the questions... I had similar struggles when I started using CC65.

Daryl
Please visit my website -> https://sbc.rictor.org/
Quaker762
Posts: 7
Joined: 29 Sep 2014

Re: Compiling C and Assembly for Symon

Post by Quaker762 »

Okay, here's my batch files.

I have two, but I'll put them into one eventually:

BuildLib.bat

Code: Select all

@ECHO off
SET CC65_BIN=E:\Users\Jesse\Documents\System I\cc65\bin
SET PATH=%CC65_BIN%
ca65 --cpu 6502 crt0.s
ar65 a dos.lib crt0.o
pause
dos.lib is copied and renamed from cc65/lib/supervision.lib as recommended in the tutorial.

Build.bat

Code: Select all

@ECHO off
SETLOCAL
REM SET OUR CC65 ENV VARIABLES
SET CC65_HOME=E:\Users\Jesse\Documents\System I\cc65
SET CC65_INC=E:\Users\Jesse\Documents\System I\cc65\asminc
SET CC65_BIN=E:\Users\Jesse\Documents\System I\cc65\bin
SET LD65_LIB=E:\Users\Jesse\Documents\System I\cc65\lib
SET PATH=%CC65_BIN%
REM COMPILE ALL C CODE IN .S FILES, BEFORE WE COMPILE AND THEN LINK THEM INTO A 16KB ALIGNED ROM
cc65 -t none --cpu 6502 kmain.c
ca65 kmain.s
ld65 -C symon.cfg -o kernel.bin -m kern.map -vm kmain.o dos.lib 
GOTO CLEAN

:CLEAN
REM DELETE ALL OF OUR .O FILES
DEL /S *.o
GOTO PAUSE

:PAUSE
pause
Sort of spaghetti code, it'll get cleaned eventually ahaha.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Compiling C and Assembly for Symon

Post by barrym95838 »

Space char(s) in your pathname? Bill Buckels mentions that as a no-no in the thread referenced below. Could it be something that simple?

https://groups.google.com/forum/#!searc ... 8D5fEWchQJ

Mike
User avatar
BigDumbDinosaur
Posts: 9428
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: Compiling C and Assembly for Symon

Post by BigDumbDinosaur »

Quaker762 wrote:

Code: Select all

@ECHO off
SET CC65_BIN=E:\Users\Jesse\Documents[b]\System I\[/b]cc65\bin
SET PATH=%CC65_BIN%
ca65 --cpu 6502 crt0.s
ar65 a dos.lib crt0.o
pause
Use of whitespace in filenames is generally considered to be bad practice, especially in a compiler "make file." Unfortunately, MS Windows actively promotes that sort of thing.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: Compiling C and Assembly for Symon

Post by 8BIT »

In your second batch file, change this line:

Code: Select all

ld65 -C symon.cfg -o kernel.bin -m kern.map -vm kmain.o dos.lib 
to this:

Code: Select all

ld65 -C symon.cfg -o kernel.bin -m kern.map -vm crt0.o kmain.o dos.lib 
Be sure the crt0.o is in one of the paths. This is how I got my code to compile. I'm not sure its right, but it did work for me.

Daryl
Please visit my website -> https://sbc.rictor.org/
Quaker762
Posts: 7
Joined: 29 Sep 2014

Re: Compiling C and Assembly for Symon

Post by Quaker762 »

barrym95838 wrote:
Space char(s) in your pathname?
BigDumbDinosaur wrote:
Use of whitespace in filenames is generally considered to be bad practice, especially in a compiler "make file." Unfortunately, MS Windows actively promotes that sort of thing.
Oh yeah... Don't know what possessed me to put a space in the directory name... They've been removed now.
8BIT wrote:
In your second batch file, change this line:

Code: Select all

ld65 -C symon.cfg -o kernel.bin -m kern.map -vm kmain.o dos.lib 
to this:

Code: Select all

ld65 -C symon.cfg -o kernel.bin -m kern.map -vm crt0.o kmain.o dos.lib 
Be sure the crt0.o is in one of the paths. This is how I got my code to compile. I'm not sure its right, but it did work for me.

Daryl
Same error still. Here's a photo of the console.
http://imgur.com/XZuQOfQ

I'm putting it down to something missing from my linker script, but again, the RAM symbols should be generated by the linker.

-Quaker762
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: Compiling C and Assembly for Symon

Post by 8BIT »

I'll try to dust off my cc65 this weekend and see if I can duplicate the problem based on your files. Then I might be able to resolve it.

Daryl
Please visit my website -> https://sbc.rictor.org/
Quaker762
Posts: 7
Joined: 29 Sep 2014

Re: Compiling C and Assembly for Symon

Post by Quaker762 »

8BIT wrote:
I'll try to dust off my cc65 this weekend and see if I can duplicate the problem based on your files. Then I might be able to resolve it.

Daryl
Thanks a heap Daryl, here's my full crt0.s and kmain.c files

kmain.c

Code: Select all

int main()
{
	int x = 0;
	int i;
	
	for(i = 0; i < 1000; i++)
	{
		x = x + 1;
	}
	
	for(;;);
	
	return 0;
}
ctr0.s

Code: Select all

; ---------------------------------------------------------------------------
; crt0.s
; ---------------------------------------------------------------------------
;
; Startup code for cc65 (Single Board Computer version)

.export   _init, _exit
.import   _main

.export   __STARTUP__ : absolute = 1        ; Mark as startup
.import   __RAM_START__, __RAM_SIZE__       ; Linker generated

.import    copydata, zerobss, initlib, donelib

.include  "zeropage.inc"

; ---------------------------------------------------------------------------
; Place the startup code in a special segment

.segment  "STARTUP"

; ---------------------------------------------------------------------------
; A little light 6502 housekeeping

_init:    LDX     #$FF                 ; Initialize stack pointer to $01FF
          TXS
          CLD                          ; Clear decimal mode

; ---------------------------------------------------------------------------
; Set cc65 argument stack pointer

          LDA     #<(__RAM_START__ + __RAM_SIZE__)
          STA     sp
          LDA     #>(__RAM_START__ + __RAM_SIZE__)
          STA     sp+1

; ---------------------------------------------------------------------------
; Initialize memory storage

          JSR     zerobss              ; Clear BSS segment
          JSR     copydata             ; Initialize DATA segment
          JSR     initlib              ; Run constructors

; ---------------------------------------------------------------------------
; Call main()

          JSR     _main

; ---------------------------------------------------------------------------
; Back from main (this is also the _exit entry):  force a software break

_exit:    JSR     donelib              ; Run destructors
          BRK
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: Compiling C and Assembly for Symon

Post by 8BIT »

ok - found some time today.

This worked for me. edit your .cfg file to this:

Code: Select all

MEMORY {
ZP: start = $0, size =  $100, type  = rw, define = yes;
RAM: start = $0200, size = $7F00, define = yes;
ROM: start = $C000, size = $4000, fill = yes;
}
SEGMENTS {
ZEROPAGE:  load = ZP,  type = zp,  define   = yes;
STARTUP: load = ROM, type = ro,  define   = yes;
INIT: load = ROM, type = ro,  define   = yes;
CODE: load = ROM, type = ro,  define   = yes;
DATA: load = ROM, type = rw,  define   = yes;
BSS: load = RAM, type = bss, define = yes;
}
FEATURES {
    CONDES:    segment = STARTUP,
               type    = constructor,
               label   = __CONSTRUCTOR_TABLE__,
               count   = __CONSTRUCTOR_COUNT__;
    CONDES:    segment = STARTUP,
               type    = destructor,
               label   = __DESTRUCTOR_TABLE__,
               count   = __DESTRUCTOR_COUNT__;
}
I added the

Code: Select all

, define = yes
to the lines that were unresolved.

Give that a try.

Daryl
Please visit my website -> https://sbc.rictor.org/
Post Reply