6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed Jun 26, 2024 1:10 am

All times are UTC




Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sun Aug 19, 2018 5:43 pm 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 19, 2018 7:52 pm 
Offline

Joined: Mon May 25, 2015 1:12 pm
Posts: 92
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 19, 2018 9:21 pm 
Offline

Joined: Sat Jun 04, 2016 10:22 pm
Posts: 483
Location: Australia
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 19, 2018 10:08 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8230
Location: Midwestern USA
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.

Attachment:
File comment: Kowalski 6502 Simulator V1.2.14a
6502v1.2.14a.zip [540.44 KiB]
Downloaded 173 times

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 19, 2018 11:51 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8460
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 20, 2018 4:15 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10834
Location: England
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 20, 2018 4:54 am 
Offline

Joined: Wed Feb 12, 2014 1:39 am
Posts: 172
Location: Sweden
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


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 20, 2018 5:27 am 
Offline

Joined: Mon May 25, 2015 1:12 pm
Posts: 92
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 20, 2018 6:44 am 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
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:
__STACKSIZE__:  value = $0200, weak = yes;


It works after changing to:

Code:
__STACKSIZE__:  value = $0200, type = weak


Is it right solution?


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 20, 2018 8:10 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10834
Location: England
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:
    __STACKSIZE__: type = weak, value = $0800; # 2k stack



(Edited to add detail)


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 20, 2018 2:25 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1696
Location: Sacramento, CA
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/


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 30, 2018 5:10 pm 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
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:
; ---------------------------------------------------------------------------
; 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:
#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:
; ---------------------------------------------------------------------------
; 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:
#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:
# 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



Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 30, 2018 8:53 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1696
Location: Sacramento, CA
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


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/


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 31, 2018 4:03 am 
Offline

Joined: Tue Jun 19, 2018 8:28 am
Posts: 122
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.


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 31, 2018 1:02 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1696
Location: Sacramento, CA
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:
; 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/


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 29 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 18 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron