CC65 - compiling code for homemade device

Building your first 6502-based project? We'll help you get started here.
Atlantis
Posts: 122
Joined: 19 Jun 2018

CC65 - compiling code for homemade device

Post 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.
JenniferDigital
Posts: 92
Joined: 25 May 2015

Re: CC65 - compiling code for homemade device

Post 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.
DerTrueForce
Posts: 483
Joined: 04 Jun 2016
Location: Australia

Re: CC65 - compiling code for homemade device

Post 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.
User avatar
BigDumbDinosaur
Posts: 9426
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: CC65 - compiling code for homemade device

Post by BigDumbDinosaur »

Atlantis wrote:
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
x86?  We ain't got no x86.  We don't NEED no stinking x86!
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: CC65 - compiling code for homemade device

Post by GARTHWILSON »

BigDumbDinosaur wrote:
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.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: CC65 - compiling code for homemade device

Post 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.
LIV2
Posts: 173
Joined: 12 Feb 2014
Location: Sweden

Re: CC65 - compiling code for homemade device

Post 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
JenniferDigital
Posts: 92
Joined: 25 May 2015

Re: CC65 - compiling code for homemade device

Post 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.
Atlantis
Posts: 122
Joined: 19 Jun 2018

Re: CC65 - compiling code for homemade device

Post by Atlantis »

BigDumbDinosaur wrote:
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?
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: CC65 - compiling code for homemade device

Post by BigEd »

Quote:
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)
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: CC65 - compiling code for homemade device

Post 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
Please visit my website -> https://sbc.rictor.org/
Atlantis
Posts: 122
Joined: 19 Jun 2018

Re: CC65 - compiling code for homemade device

Post 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

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

Re: CC65 - compiling code for homemade device

Post 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
Please visit my website -> https://sbc.rictor.org/
Atlantis
Posts: 122
Joined: 19 Jun 2018

Re: CC65 - compiling code for homemade device

Post by Atlantis »

8BIT wrote:
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.
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Re: CC65 - compiling code for homemade device

Post 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
Please visit my website -> https://sbc.rictor.org/
Post Reply