the tool chain github is where the dev is mostly spending their time to answer questions and resolve issues, so i'd recommend you ask over there:
https://github.com/hth313/Calypsi-tool-chains
but i can answer some stuff.
I don't see a generic section in the manual for homebrew/custom boards and trying to figure out exactly what I need to do to get this to work.
when you download the utility it should come with an "example" folder that has a minimal linker setup, and in the "src\lib\lowlevel" folder there is the default cstartup.s that you can either modify directly or copy and then modify for whatever system you have.
though i agree that it should be made much easier to set up a custom environment. so a template example with better commented startup code would be very useful. (you can also ask for that on the github)
I don't know how to handle the exit. If I decide to exit my C program, I'd want to jump to the monitor prompt, which is at $E003.
in C, exiting from the main function is handled like with any other function, meaning it just returns control to whatever code called it. in the startup code you can see the "JSR main" that calls the main function, and once it finishes/returns it continues with the instructions following it. in the case of your startup code it will execute a "JMP" to the label named "exit"
so it you want it to jump to your monitor you could just define "exit" to equal $E003, or replace the "JMP exit" with "JMP $E003".
The next item is interrupts. When my board boots, IRQ location $FFFE in EPROM points to $00FD and puts an RTI instruction there. So, when writing in assembler, I'd put a JMP at $00FD, and the IRQ method address in $00FE/$00FF
I wouldn't recommend jumping execution to Zeropage. use an indirect jump instead, which gets it's target address (the address that it jumps to) from memory where the operand address (the one you write in the assembler) points to.
so for example "JMP ($00FE)" reads 2 bytes from address $00FE and $00FF and let's say that the value at the first address was $99 and at the second address $44, meaning that execution will jump to address $4499 and continue there.
this leaves your Zeropage nice and tidy without having to store any code there.
as for Interrupt code in C... it's somewhat complicated. your startup code has to get the address of the function (assembly or C) you want to call and write it to where your IRQ ROM code jumps to. the problem with doing it in C is that any temporary varibles the C environment uses (which are pretty much just in the Zeropage) have to be copied to somewhere else before you can actually call your C interrupt function, which adds a lot of latency to the IRQ function.
maybe also ask the dev about a simple example for interrupt handling since i've honestly never bothered with it myself and all my Interrupt code has been in pure assembly to avoid having to save any C memory values.
on a final note, i recommend including this header file i call "MemAccess.h" that i made that adds some macros for accessing memory and setting/clearing/checking individual bits of varibles/memory locations. which makes accessing memory a lot more readable IMO.
Code: Select all
#ifndef MEMACCESS
#define MEMACCESS
#include <stdint.h>
#define mread8(addr) *((uint8_t*)addr)
#define mread16(addr) *((uint16_t*)addr)
#define mread32(addr) *((uint32_t*)addr)
#define mwrite8(addr, val) *((uint8_t*)addr) = val
#define mwrite16(addr, val) *((uint16_t*)addr) = val
#define mwrite32(addr, val) *((uint32_t*)addr) = val
#define bitread(var, bit) (((var) >> (bit)) & 1U)
#define bitset(var, bit) ((var) |= (1U << (bit)))
#define bitclr(var, bit) ((var) &= ~(1U << (bit)))
#define bitwrite(var, bit, val) ((val) ? bitset(var, bit) : bitclr(var, bit))
#endif
I also recommend learning the "stdint" sytax for variables. so "uint16_t" instead of "unsigned int", "int8_t" instead of "char", etc. on a CPU like a 65C02 keeping track of your vairable's widths can save you a fair amount of execution time and memory.
Either way, I hope this was atleast somewhat helpful.