Programming in c is generally easier than assembly, so if I want to make anything complicated it would be nice to have. First, I have to mention Dirk Grappendorf’s 6502 Home Computer, which I referred to a lot. I also use the Makefile and cfg files that he used.

To start, there is a startup routine that is written in assembly. This works the same as a regular assembly program, where there is a segment for the vectors that point to the startup routine, like this:

		.import _main
		
		.segment "VECTORS"
		
		.addr _init
		.addr _init
		.addr _init
		
		.code
		
_init:		jsr _main

end:		jmp end

The only thing strange about this program is the _main routine that appears out of nowhere. This routine is actually our int main() from our main C program. All of the methods in C get converted to assembly routines with an underscore.

The main program, in C, looks like this:

#include "fga.h"

int main() {
	
	fga_mode(0);
	fga_clear_m();
	fga_goto(0, 0);
	
	fga_putsln_m("Hello, World!");
	
	return 0;
}

This looks a lot nicer than assembly but I can’t just use printf();, since there is no console or anything to write it to. Instead, I have a header with all of the routines to control the FPGA Graphics Adapter which lets me use a VGA monitor. Right now I’m only using the monochrome text mode, so using the existing assembly code was easy. Here’s what that header looks like:

#ifndef _FGA_H
#define _FGA_H

extern void __fastcall__ fga_mode(char c);
extern void __fastcall__ fga_clear_m();
extern void __fastcall__ fga_goto(unsigned char x, unsigned char y);
extern void __fastcall__ fga_write_m(char c);
extern void __fastcall__ fga_putc_m(char c);
extern void __fastcall__ fga_puts_m(const char* s);
extern void __fastcall__ fga_putsln_m(const char* s);

#endif

and the related assembly source starts like this:

		.include "io.inc65"
		.include "zeropage.inc65"
		
		.import popa
		
		.export _fga_mode
		.export _fga_clear_m
		.export _fga_goto
		.export _fga_write_m
		.export _fga_putc_m
		.export _fga_puts_m
		.export _fga_putsln_m

io.inc65 and zeropage.inc65 are definitions for io locations and zeropage locations. popa is a macro that’s made by the compiler. The way parameters are passed from a C program to the assembly program is through a stack. The parameter stack is different than the CPU stack though, so you can’t use pla or anything like that. When I call something like fga_putc_m(c);, the character c is loaded into the parameter stack and that stack pointer points to it.

For __fastcall__ functions though, the right-most parameter is passed through the “primary register” instead of the stack. The primary register changes depending on the width of the data-type, being A, A/X, and A/X/sreg for 1, 2, and 4 byte variables, respectively. sreg is just a 2 byte zeropage location. For functions with only one parameter, this means you don’t need to worry about the stack at all, it just comes in the registers. To return a value, you leave it in the registers. The wiki says all return values should be in X, but it seems like it’s actually A, so I’m not sure. For 16 bit values you would put it in A/X then.

Being able to program in C should make it easier to make higher level software, and eventually a real operating system. Low level stuff would still have to written in assembly, but either way I look forward to seeing what new things I can do.

Here are some relevant wiki articles:

Parameter-passing-and-calling-conventions

Parameter-and-return-stacks

The-primary-register

And here’s the code I wrote: c_programs