Page 1 of 2
CC65 - compiling code for homemade device
Posted: Sun Aug 19, 2018 5:43 pm
by Atlantis
I need some help with patching some holes in my knowledge.

I've been writing code for different microcontrollers (8051, AVR, PIC, STM32) for several years. Usually I use C, but I also have basic knowledge about other languages, including assembly. Recently I began experimenting with vintage microprocessors, including 8080 and 6502. I've built few boards and done some experiments with running BASIC. Now I want to try to use 6502 as a controller in one of my "embedded" projects, just like modern MCU. Unfortunately I don't feel comfortable about writing large amount of code in assembly, so I'd prefer to stick with CC65. But first I need to clarify some things.
Writing C code for modern MCU is relatively easy. Compiler is aware of hardware. It knows what amounts of RAM and FLASH are available, i knows addresses of every port and control register.
I would like to know:
1) How to tell CC65 where the RAM begins and ends.
2) The same about EPROM.
3) How to define names pointing to ports and registers in address space. For example when I have latch register at 0xA000 and I would like to simply write new value by using something like NAME = 0x0F.
In brief: I would like to provide CC65 all the necessary information, to use my own 6502 based device like AVR or PIC microcontroller.
Re: CC65 - compiling code for homemade device
Posted: Sun Aug 19, 2018 7:52 pm
by JenniferDigital
Ok, so many moons ago I spent a while setting up a CC65 target for my homebrew computer (which I now run assorted other stuff on too now).
What I did, if I remember correctly, was to make a .cfg file defining my memory map and where the output goes etc. Then I wrote a tiny c runtime (crt0.s) in assembly (based on an example).
Next I copied the supervision libraries, assembled the crt0.s file and put it in the library. There very well might have been more but I just don't remember.
It definitely works though I must point out that when I updated cc65, I had to redo my libraries slightly.
Go and play with the Kowalski simulator for a couple of weekends, then see how you feel, since you still need a smattering of 6502 code just to get started unless someone gives you a leg-up.
Re: CC65 - compiling code for homemade device
Posted: Sun Aug 19, 2018 9:21 pm
by DerTrueForce
Theres some documentation here:
https://cc65.github.io/doc/customizing.html
I looked at it for my design, and found it confusing. Your mileage may vary, though. I might have been overthinking it.
Re: CC65 - compiling code for homemade device
Posted: Sun Aug 19, 2018 10:08 pm
by BigDumbDinosaur
I need some help with patching some holes in my knowledge.

I've been writing code for different microcontrollers (8051, AVR, PIC, STM32) for several years. Usually I use C, but I also have basic knowledge about other languages, including assembly. Recently I began experimenting with vintage microprocessors, including 8080 and 6502. I've built few boards and done some experiments with running BASIC. Now I want to try to use 6502 as a controller in one of my "embedded" projects, just like modern MCU. Unfortunately I don't feel comfortable about writing large amount of code in assembly, so I'd prefer to stick with CC65. But first I need to clarify some things.
Writing C code for modern MCU is relatively easy. Compiler is aware of hardware. It knows what amounts of RAM and FLASH are available, i knows addresses of every port and control register.
I would like to know:
1) How to tell CC65 where the RAM begins and ends.
2) The same about EPROM.
3) How to define names pointing to ports and registers in address space. For example when I have latch register at 0xA000 and I would like to simply write new value by using something like NAME = 0x0F.
In brief: I would like to provide CC65 all the necessary information, to use my own 6502 based device like AVR or PIC microcontroller.
I don't want to be discouraging, but it's going to be difficult to avoid some assembly language in getting your "bare metal" system up and running. CC65 doesn't produce high quality object code and you are probably going to be wishing you knew the 6502 assembly language better, especially in the realm of controlling I/O hardware.
As DigitalDunc suggested, you should install the Kowalski 6502 simulator on a Windows machine (XP SP3 or later) and learn how to program the 6502 family in its native tongue. There is a mountain of documentation on the 6502 family here and all over the Web, so there is no shortage of help. Once you get comfortable with 6502 assembly language you will quickly discover why so many of us prefer it over higher level languages when writing technical and system code.
Attached is the most recently built version of the Kowalski simulator. Searches here on the forum will lead you to plenty of discussion on using it.
- 6502v1.2.14a.zip
- Kowalski 6502 Simulator V1.2.14a
- (540.44 KiB) Downloaded 187 times
Re: CC65 - compiling code for homemade device
Posted: Sun Aug 19, 2018 11:51 pm
by GARTHWILSON
Once you get comfortable with 6502 assembly language you will quickly discover why so many of us prefer it over higher level languages when writing technical and system code.
This is coming from someone who, decades ago, wrote a nearly 100,000-line billing application in 6502 (8502) assembly language for a dozen networked Commodore 128D's for a truck-leasing company (see
viewtopic.php?f=2&t=3588&p=43131#p43131 and his post above it) and also does C (although he would rather not). Go ahead and use C for your higher-level portions if that's what you're comfortable in; but when assembly is appropriate for better efficiency at the bare-metal level, we're here to help for that, too.
Re: CC65 - compiling code for homemade device
Posted: Mon Aug 20, 2018 4:15 am
by BigEd
Ugh. In a thread that's about how to use CC65, I really wouldn't encourage suggestions to do things a different way. If you don't like the approach, post elsewhere with positive recommendations about your preferred approach.
Re: CC65 - compiling code for homemade device
Posted: Mon Aug 20, 2018 4:54 am
by LIV2
Edited: I had posted a bunch of stuff on configuring for assembly etc but you want the opposite of that.
I remember the documentation not being great, but you can have a look at the .cfgs here:
https://github.com/cc65/cc65/tree/master/cfg
I haven't yet figured out how to add support to for the libraries etc, I haven't yet felt the need to write C for the 65c02
Re: CC65 - compiling code for homemade device
Posted: Mon Aug 20, 2018 5:27 am
by JenniferDigital
A further possibly useful point is that the Kowalski simulator does work (with perhaps a few glitches now and then) on a Linux box if you install Wine.
Re: CC65 - compiling code for homemade device
Posted: Mon Aug 20, 2018 6:44 am
by Atlantis
Once you get comfortable with 6502 assembly language you will quickly discover why so many of us prefer it over higher level languages when writing technical and system code.
Writing low-level I/O routines in assembly in not much of an issue. I prefer to use C because I already have set of libraries, either written by me or by other people. They are mostly platform independent or only require providing some low-level functions to operate. I usually try to write my own code to be portable between platforms, for example by specifying variable size with intxx_t type.
It would be too much of a hassle to rewrite it again and again for every CPU family. I know that assembly code is efficient, but first you need to master it. I understand that some people are using assembly to utulize all of the resources of some retro computer. This is not my case. I am exploring 6502 just for fun. I want to learn something more about low-level operations of CPU systems and try to build some device by using ancient tech instead of modern MCU in the process.
BTW I am trying to follow instructions from
https://cc65.github.io/doc/customizing.html.
Following line causes error: Attribute expected, got 'WEAK'.
Code: Select all
__STACKSIZE__: value = $0200, weak = yes;
It works after changing to:
Code: Select all
__STACKSIZE__: value = $0200, type = weak
Is it right solution?
Re: CC65 - compiling code for homemade device
Posted: Mon Aug 20, 2018 8:10 am
by BigEd
I prefer to use C because...
Indeed! And you titled the thread well, and made it clear it's a question about cc65.
I don't have the experience or knowledge to say much, but I do know some Acorn-using people have had success with cc65. Here's an Acorn Atom thread:
https://stardot.org.uk/forums/viewtopic ... 75#p136775
And here's the cfg file for an Atom:
https://github.com/janrinze/cc65/blob/m ... g/atom.cfg
in which we see
Code: Select all
__STACKSIZE__: type = weak, value = $0800; # 2k stack
(Edited to add detail)
Re: CC65 - compiling code for homemade device
Posted: Mon Aug 20, 2018 2:25 pm
by 8BIT
Try doing a CC65 search in this forum. Several users have worked on custom CC65 targets, including me.
Here are a few places to look (but there are others too):
viewtopic.php?f=2&t=2196
viewtopic.php?f=2&t=3064
In addition, on my website are several sources that you can look over for examples:
SBC2 support -
http://sbc.rictor.org/download/cc65sbc2.zip
SBC3 support -
http://sbc.rictor.org/download/cc65lib.zip
AVR 65C02 emulator (simulator) -
http://sbc.rictor.org/download/AVR_CC65.zip
CC65 for the Kowalski Simulator -
http://sbc.rictor.org/support/CC65forSim.zip
I can help once you get started, but I may be slow to respond at times.
Daryl
Re: CC65 - compiling code for homemade device
Posted: Thu Aug 30, 2018 5:10 pm
by Atlantis
Ok, I was able to prepare project template for my board ant then compile simple blink example.
However I have some issues with assembly routines for delays and hd44780.
It stops working when I try to use these assembly written libraries.
There is a code. What do you think about it. Is there something wrong?
delay.s
Code: Select all
; ---------------------------------------------------------------------------
; delay.s
; ---------------------------------------------------------------------------
;
; Delay subroutines
.export _delay_3us,_delay_ms
.segment "CODE"
; ---------------------------------------------------------------------------
; Delay 3us
_delay_3us:
tax
delay_3us_loop:
dex
bne delay_3us_loop
rts
; ---------------------------------------------------------------------------
; Delay ms
_delay_ms:
tay
delay_ms_loop1:
ldx #$FF
delay_ms_loop2:
jsr _delay_3us
dex
bne delay_ms_loop2
dey
bne delay_ms_loop1
rts
delay.h
Code: Select all
#ifndef _DELAY_H_
#define _DELAY_H_
extern void __fastcall__ delay_3us (uint8_t duration);
extern void __fastcall__ delay_ms (uint8_t duration);
#endif
hd44780.s
Code: Select all
; ---------------------------------------------------------------------------
; hd44780.s
; ---------------------------------------------------------------------------
;
; LCD driver
hd44780_cmd = $A380
hd44780_data = $A381
.import _delay_3us,_delay_ms
.export _hd44780_init,_hd44780_putc, _hd44780_puts, _hd44780_cmd
.segment "ZEROPAGE"
ptr:
.res 2
.segment "CODE"
; ---------------------------------------------------------------------------
; Initialize display
_hd44780_init:
;delay 100ms
lda #$64
jsr _delay_ms
lda #$30
sta hd44780_cmd
;delay 10ms
lda #$0A
jsr _delay_ms
lda #$30
sta hd44780_cmd
;delay 100us
lda #$21
jsr _delay_3us
lda #$30
sta hd44780_cmd
;delay 100us
lda #$21
jsr _delay_3us
lda #$38
jsr _hd44780_cmd
lda #$08
jsr _hd44780_cmd
lda #$01
jsr _hd44780_cmd
lda #$06
jsr _hd44780_cmd
lda #$0C
jsr _hd44780_cmd
rts
; ---------------------------------------------------------------------------
; Send one character
_hd44780_putc:
pha
jsr _hd44780_busy
pla
sta hd44780_data
rts
; ---------------------------------------------------------------------------
; Send string of characters terminated by \0
_hd44780_puts:
ldy #$00
stx ptr
sta ptr+1
hd44780_puts_loop:
lda (ptr),y
beq hd44780_puts_return
jsr _hd44780_putc
iny
jmp hd44780_puts_loop
hd44780_puts_return:
rts
; ---------------------------------------------------------------------------
; Send command
_hd44780_cmd:
pha
jsr _hd44780_busy
pla
sta hd44780_cmd
rts
; ---------------------------------------------------------------------------
; Wait for busy flag
_hd44780_busy:
lda hd44780_cmd
and #$80
bne _hd44780_busy
rts
hd44780.h
Code: Select all
#ifndef _HD44780_H_
#define _HD44780_H_
#include <stdint.h>
extern void hd44780_init (void);
extern void __fastcall__ hd44780_putc (char c);
extern void __fastcall__ hd44780_puts (char *str);
extern void __fastcall__ hd44780_cmd (uint8_t cmd);
extern void __fastcall__ hd44780_gotoxy (uint8_t x, uint8_t y);
#endif
Makefile
Code: Select all
# Adjust the run address to match the .org in the source code
all: main.hex
main.hex: a.out
bin2hex.py --offset=0xc000 a.out main.hex
a.out: interrupt.o vectors.o main.o hd44780.o delay.o
ld65 -C ./lib/ethergeiger.cfg -m main.map interrupt.o vectors.o hd44780.o delay.o main.o ./lib/ethergeiger.lib
main.s: main.c
cc65 -t none -O --cpu 6502 main.c
main.o: main.s
ca65 --cpu 6502 main.s
delay.o: delay.s
ca65 --cpu 6502 delay.s
hd44780.o: hd44780.s
ca65 --cpu 6502 hd44780.s
interrupt.o: interrupt.s
ca65 --cpu 6502 interrupt.s
vectors.o: vectors.s
ca65 --cpu 6502 vectors.s
clean:
$(RM) *.o *.lst *.map, *.out, *.hex a.out main.s
Re: CC65 - compiling code for homemade device
Posted: Thu Aug 30, 2018 8:53 pm
by 8BIT
Code: Select all
; ---------------------------------------------------------------------------
; Delay 3us
_delay_3us:
tax
delay_3us_loop:
dex
bne delay_3us_loop
rts
; ---------------------------------------------------------------------------
; Delay ms
_delay_ms:
tay
delay_ms_loop1:
ldx #$FF
delay_ms_loop2:
jsr _delay_3us
dex
bne delay_ms_loop2
dey
bne delay_ms_loop1
rts
If you call _delay_ms, you will enter an endless loop and never return.
Look below delay_ms_loop2:, Every time you call _delay_3us, it will return with x=0. The next instruction is dex, so x=$FF and the "bne delay_ms_loop2" will repeat forever.
I can help, but I need to know the clock frequency of your system. Also note, the _delay_3us routine will use a minimum of 12 cycles, not including the JSR used to call it. So if you are using a 1 MHz clock, you may want to consider a 20us delay routine. Anything under that can be done with NOP or other code inline.
thanks!
Daryl
Re: CC65 - compiling code for homemade device
Posted: Fri Aug 31, 2018 4:03 am
by Atlantis
I can help, but I need to know the clock frequency of your system. Also note, the _delay_3us routine will use a minimum of 12 cycles, not including the JSR used to call it. So if you are using a 1 MHz clock, you may want to consider a 20us delay routine. Anything under that can be done with NOP or other code inline.
Thanks. I will be grateful.

My device works at 1MHz. 20 us loop will be fine. I just need it for delays during HD44780 initialization.
Re: CC65 - compiling code for homemade device
Posted: Fri Aug 31, 2018 1:02 pm
by 8BIT
I ran out of time to test this but wanted to post it so you would not wait too long. I'll test it tomorrow.
Code: Select all
; Delay subroutines
.export _delay_5us,_delay_ms
.segment "CODE"
; ---------------------------------------------------------------------------
; Delay 5us
; there's an additional 15us overhead for each call, so the
; minimum delay is 20us with increments of 5us. The formula is:
; duration = 5*a + 15, where "a" is the value in the accumulator
; note a value of zero in "a" is treated as 256, not zero!
_delay_5us:
nop
tax
delay_5us_loop:
dex
bne delay_5us_loop
rts
; ---------------------------------------------------------------------------
; Delay ms
_delay_ms:
tay
lda #196 ; 196*5 + 15 = 995 (dey&bne take 5 cycles)
delay_ms_loop1:
jsr _delay_5us
dey
bne delay_ms_loop1
rts
Daryl