Jump to content
JesperGravgaard

KickC Optimizing C-Compiler now supports Atari 8bit XL/XE

Recommended Posts

Hi @JesperGravgaard is there any way to do debugging?

I'm using altirra and I think if there's a corresponding <filename>.atdbg file it will load it (although I've had various levels of success handcrafting one).

That file has standard altirra debug commands (e.g. setting break points etc).

 

Just wondering if you have any way of handling this currently before I try and write some bespoke scripts when launching (e.g) an eclipse build.

In fact, what environment do you use/suggest for development and launching xex files? I posted a simple external run command for eclipse I'm using at the moment, but it simply runs the kickc.bat with various parameters.

 

Edited by fenrock

Share this post


Link to post
Share on other sites

via the KickC command line there doesn't seem to be a way to pass the '–vicesymbols' to the Kick Assembler?

So if the assembler was run manually then you could add this and then rename the .vs file to .lbl and then this should be usable in Altirra.

  • Like 1

Share this post


Link to post
Share on other sites
On 9/29/2020 at 6:19 AM, JesperGravgaard said:

The default encoding on the ATARI XL platform is screencode_atari. I can see you already found the way to select the ATASCII encoding!

 

 

Hi, this looks great. That choice for the default encoding seems odd; I would expect that atascii would be default and screencode would be pragma. Why was that decision made?

Share this post


Link to post
Share on other sites
34 minutes ago, fenrock said:

Hi @JesperGravgaard is there any way to do debugging?

I'm using altirra and I think if there's a corresponding <filename>.atdbg file it will load it (although I've had various levels of success handcrafting one).

That file has standard altirra debug commands (e.g. setting break points etc).

 

Just wondering if you have any way of handling this currently before I try and write some bespoke scripts when launching (e.g) an eclipse build.

In fact, what environment do you use/suggest for development and launching xex files? I posted a simple external run command for eclipse I'm using at the moment, but it simply runs the kickc.bat with various parameters.

 

 

The underlying assembler i KickAssembler. As @Wrathchild writes KickAssembler can produce a .vs symbol file for the VICE emulator if you pass it the –vicesymbols option. I don't know Altirra well enough to know the format it expects, but the VICE symbol file is in a pretty simple format that would be easy to modify using a script.

 

I will be adding a command-line option to KickC that passes -vicesymbols on to KickAssembler (if you use -a to assemble or -e to assemble and run an emulator). In the meantime you can choose to call KickAssembler manually.

 

As an interesting aside. The VICE symbols file primarily contains symbols (variables / labels in the code) but it can also contain breakpoints. If you want to place a breakpoint in your KickC-code that will be output into the VICE symbol file this is currently possible using kickasm {{ .break }} 

 

 

 

 

 

 

 

 

 

Share this post


Link to post
Share on other sites
52 minutes ago, danwinslow said:

 

Hi, this looks great. That choice for the default encoding seems odd; I would expect that atascii would be default and screencode would be pragma. Why was that decision made?

The choice to use screencodes as default charset encoding was made to align with the other platforms supported by the compiler (such as C64) and because the current KickC atari 8bit library focuses on the chipset of the atari and does not have any ROM wrappers.

 

If you prefer ATASCII as the default charset you can achieve this pretty easily. Simply change the "encoding" setting in the /target/atarixl.tgt file in your KickC installation, or create a new platform target by making a copy of the tgt-file and changing the settings in that copy. After this you can compile to the platform you have configured using the -t xxx commandline option or the #pragma target(xxx) where xxx is the name of your tgt-file. 

Edited by JesperGravgaard
  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, JesperGravgaard said:

The choice to use screencodes as default charset encoding was made to align with the other platforms supported by the compiler (such as C64) and because the current KickC atari 8bit library focuses on the chipset of the atari and does not have any ROM wrappers.

 

If you prefer ATASCII as the default charset you can achieve this pretty easily. Simply change the "encoding" setting in the /target/atarixl.tgt file in your KickC installation, or create a new platform target by making a copy of the tgt-file and changing the settings in that copy. After this you can compile to the platform you have configured using the -t xxx commandline option or the #pragma target(xxx) where xxx is the name of your tgt-file. 

Makes sense, thanks!

Share this post


Link to post
Share on other sites

@JesperGravgaard I've got to a point where I'm debugging in Altirra.

The vice label file is almost usable, could it be possible to make two changes when the build target is Atari?

 

1) Use the extension 'lbl' (labels) instead of 'vs' (vice symbols?)

 

2) Each hex address is prefixed with 'C:'.

al C:4085 .source3
al C:504e .NumbersW

Can this be output as 6 wide, leading zero?

al 00B1F9 .AddOtherShip
al 00C877 .AddPlanetName

This way, Altirra (and probably the other A8 emulators too) will be able to load and use these directly.

 

  • Like 1

Share this post


Link to post
Share on other sites

Zeropage usage and the Atari target

 

@JesperGravgaard It might be useful to provide a #pragma option to state the base zeropage address that usage can begin at.

Currently it looks like this is just address 2 or 3, which would make sense on a C64 target I should think with the first two bytes of zeropage mapped to h/w.

For the Atari, this is typically going to be $80 as a default as the OS will still make use of the lower half, e.g. CLOCK at $14,$13,$12 and Attract mode register at $4D.

So if the programmer is happy to override this themselves, e.g. because they'll switch out the OS and handle clocks themselves, then this can be lowered via the pragma.

Or would it be better defined in the tgt or ld file and then overridden in a custom one if needed?

 

image.png.291be607d092e619432d5e7bd7edaab1.png

Edited by Wrathchild
screenshot added
  • Like 1

Share this post


Link to post
Share on other sites
9 minutes ago, Wrathchild said:

Zeropage usage and the Atari target

 

@JesperGravgaard It might be useful to provide a #pragma option to state the base zeropage address that usage can begin at.

 

 

 

You can achieve this by reserving the zero-pages you do not want the compiler to use. To start at 0x80 add the following pragma

#pragma zp_reserve(0x00..0x7f)
  • Thanks 2

Share this post


Link to post
Share on other sites
1 hour ago, Wrathchild said:

@JesperGravgaard I've got to a point where I'm debugging in Altirra.

The vice label file is almost usable, could it be possible to make two changes when the build target is Atari?

 

 

 

Thank you for the LBL-format description!

 

If you have sed you can convert the VS-file to the LBL-format using the following command:

 

sed 's/al C\:/al 00/' helloxl.vs > helloxl.lbl 

 

I may have a look at offering the conversion directly in the C-compiler as a command-line option.

 

Share this post


Link to post
Share on other sites

:D currently I use regex replace in notepad++

 

This shouldn't really need another option as only specific to the A8 target (if sticking with the -vicesymbols option) so could be handled internally

21 hours ago, JesperGravgaard said:

I will be adding a command-line option to KickC that passes -vicesymbols on to KickAssembler

 

Share this post


Link to post
Share on other sites

Hi @JesperGravgaard

Got some time to play with kickC some more, and I'm trying to write a drop in conio.c/h for atari

I have a question on the following code:

 

char  * _ROWCRS	= 0x54;   // 1-byte cursor row
word  * _COLCRS	= 0x55;   // 2-byte cursor column
word  * const _SAVMSC	= 0x58;   // 2-byte saved memory scan counter

word currentTop = *_SAVMSC;
char currentRow = *_ROWCRS;
word currentCol = *_COLCRS;
word screenAddress1 = currentTop + mul40(currentRow) + currentCol;
word screenAddress2 = ((word)*_SAVMSC) + mul40(*_ROWCRS) + ((word)*_COLCRS);

// later...
word mul40(char c) {
	word c8 = (word) c << 3;
	word c32 = c8 << 2;
	return c8 + c32;
}

I don't understand why I have to put "(word)" around _SAVMSC and _COLCRS in the assignment to screenAddress2, when I didn't need to assigning them individually from variables.

 

Without it around _SAVMSC, I get:

Unknown fragment for statement [181] (word~) putchar::$4 ? *((const nomodify word*) putchar::_SAVMSC) + (word~) putchar::$3
Missing ASM fragment Fragment not found vwuz1=_deref_pwuc1_plus_vwuz2. Attempted variations vwuz1=_deref_pwuc1_plus_vwuz2 

And without it around _COLCRS, I get:

Unknown fragment for statement [183] (word) putchar::screenAddress2#0 ? (word~) putchar::$4 + *((const word*) putchar::_COLCRS)
Missing ASM fragment Fragment not found vwuz1=vwuz2_plus__deref_pwuc1. Attempted variations vwuz1=vwuz2_plus__deref_pwuc1 

I tried (but failed) to understand your fragments code, it's a bit beyond my 6502 just yet :)

 

Edited by fenrock
conio typo

Share this post


Link to post
Share on other sites
42 minutes ago, fenrock said:

I don't understand why I have to put "(word)" around _SAVMSC and _COLCRS in the assignment to screenAddress2, when I didn't need to assigning them individually from variables.

Hi @fenrock, The (word) should not be needed, however since KickC is missing a fragment you have found a very nice work-around tricking it to use a fragment it already knows.

 

If you add the following file to the /fragment/mos6502-common/ folder of KickC the code will compile and work without the (word) cast. The fragment in question handles the case word z1, z2, *c1; *z1=*c1+z2; where z1 and z2 are located on zeropage and c1 is a constant.

 

https://gitlab.com/camelot/kickc/-/blob/master/src/main/fragment/mos6502-common/vwum1=_deref_pwuc1_plus_vwum2.asm

 

The last compile-phase in KickcC generates ASM code based on small ASM fragment files matching simple C statements. It almost never fails on 8bit numbers - but is still learning to handle all combinations for 16bit numbers.

 

By the way KickC can create the multiply by 40 code for you. So the following also works, and generates code that is very similar to your mul40():

word screenAddress1 = currentTop + (word)currentRow*40 + currentCol;

 

Edited by JesperGravgaard
  • Like 1

Share this post


Link to post
Share on other sites

Excellent, thanks @JesperGravgaard that works a treat.

 

I've got one more - maybe I should take these to github.

 

word *wp = &(*SAVMSC + mul40(*ROWCRS) + *COLCRS);
word screenAddress1 = *SAVMSC + (word)(*ROWCRS)*40 + *COLCRS;
word *wp2 = &screenAddress1;
word *wp3 = &(*SAVMSC + (word)(*ROWCRS)*40 + *COLCRS);

wp assignment works, but the equivalent using inline *40 for wp3 pointer assignment throws an exception when compiling:

dk.camelot64.kickc.model.InternalError: Cannot cast declared type!(volatile number) putchar::$11
	at dk.camelot64.kickc.model.iterator.ProgramExpressionBinary$ProgramExpressionBinaryAssignmentLValue.addLeftCast(ProgramExpressionBinary.java:279)
	at dk.camelot64.kickc.passes.PassNAddNumberTypeConversions.lambda$step$0(PassNAddNumberTypeConversions.java:36)
	at dk.camelot64.kickc.model.iterator.ProgramExpressionIterator.execute(ProgramExpressionIterator.java:55)
    ...

I tried various combinations of brackets but couldn't get it to work.

 

Note, my C is very rusty, I'm basically trying to find the screen address where to put a character by adding (row*40 + column) to address pointed to by SAVMSC, so I can then put the character at that address (a char argument to my function). I think word* might be wrong anyway as I'm not going to be able to put a char there. As I say, I'm very rusty with C. Give me kotlin or java any day :)

 

Edited by fenrock

Share this post


Link to post
Share on other sites

@fenrock You have found a bug! It affects address-of, when used on some expressions. This forced the compiler has to create an anonymous variable to hold the value to be able to get a pointer - and this then fails for some expressions. 

 

I will make a fix ASAP https://gitlab.com/camelot/kickc/-/issues/536

 

You are welcome to continue posting here. You can also report any problems directly into the KickC issue tracker if you prefer that.

 

In the meantime the following works because w3 is now a "normal" named variable.

 

word w3 = *SAVMSC + (word)(*ROWCRS)*40 + *COLCRS;
word *wp3 = &w3;

Share this post


Link to post
Share on other sites
35 minutes ago, fenrock said:

Note, my C is very rusty, I'm basically trying to find the screen address where to put a character by adding (row*40 + column) to address pointed to by SAVMSC, so I can then put the character at that address (a char argument to my function). I think word* might be wrong anyway as I'm not going to be able to put a char there. As I say, I'm very rusty with C. Give me kotlin or java any day :)

@fenrock You probably want something like the following code then. Notice that SAVMSC is now a pointer to a pointer (char**). 

 

char * const ROWCRS = 0x54; // Row on the screen that the cursor is currently on
word * const COLCRS = 0x55; // Column that the cursor is on, ranging from 0 to 319.
char ** const SAVMSC = 0x58; // The lowest address of the screen memory, corresponding to the upper left corner of the screen
 
void main() {
  char* cursor = *SAVMSC + (word)*ROWCRS*40 + *COLCRS;
  *cursor = 'x';
}

 

 

Edited by JesperGravgaard

Share this post


Link to post
Share on other sites
1 hour ago, JesperGravgaard said:

@fenrock You probably want something like the following code then. Notice that SAVMSC is now a pointer to a pointer (char**). 

 

excellent, i'm trying to get my head back around pointers. clearly getting memory locations and words mixed up. this will open a lot of doors now to further code.

 

Another one in this game of tennis...

 

void gotoxy(unsigned char x, unsigned char y) {
	word * _COLCRS			= 0x55;   // 2-byte cursor column
	char * _ROWCRS			= 0x54;   // 1-byte cursor row

	// setting y is fine
	*_ROWCRS = y;

	// setting x fails
	*_COLCRS = x;           // fails to compile
	*_COLCRS = (word) x;    // fails to compile

	// assign it first...
	word xw = x;
	*_COLCRS = xw;          // works
}

This fails to compile, the first one gives:

Unknown fragment for statement [110] *((const word*) gotoxy::_COLCRS) ? (byte) gotoxy::x#0
Missing ASM fragment Fragment not found _deref_pwuc1=vbuz1. Attempted variations _deref_pwuc1=vbuz1 

second one gives:

Unknown fragment for statement [110] *((const word*) gotoxy::_COLCRS) ? (word)(byte) gotoxy::x#0
Missing ASM fragment Fragment not found _deref_pwuc1=_word_vbuz1. Attempted variations _deref_pwuc1=_word_vbuz1 

Another fragment needed?

 

EDIT: The field can take a word, but conio.h defines the function to be:

Quote

void cputcxy (unsigned char x, unsigned char y, char c);

and in fact, the x/y max on normal text screens would fit in a char.

Edited by fenrock

Share this post


Link to post
Share on other sites

Hi @JesperGravgaard

I'm getting an odd behaviour in the previous code we fixed.

 

The following code fragment:

void cputc(char c) {
	char screenCode;
	if (c == '\r') { // 0x0d
		*COLCRS = 0;
		setcursor();
	} else if(c == '\n' || c == 0x9b) { // 0x0a LF, or atascii EOL
		newline();
	} else {
		putchar(convertToScreenCode(&c));
		// *COLCRS++;   /// UNCOMMENT THIS LINE CAUSES THE ERROR
	}
}

void putchar(unsigned char code) {
	**OLDADR = *OLDCHR;
	char * cursor = cursorLocation();

	char newChar = code | reverseFlag;
	*cursor = newChar;
	*OLDCHR = newChar;
}

char * cursorLocation() {
	char *cursor = *SAVMSC + (word)(*ROWCRS)*40 + *COLCRS;
	return cursor;
}

When I uncomment the line *COLCRS++; then compiling is throwing the error:

Unknown fragment for statement [113] (byte*) cursorLocation::return#2 ? (byte*~) cursorLocation::$1 + *((word*) COLCRS#24)
Missing ASM fragment Fragment not found pbuz1=pbuz2_plus__deref_pwuz3. Attempted variations pbuz1=pbuz2_plus__deref_pwuz3 
File D:\dev\workspace\kickc-test\.\src\atari-io.c
Line 123
*SAVMSC + (word)(*ROWCRS)*40 + *COLCRS

This is extremely strange, as the extra line has nothing to do with the bit that starts failing (well, it refers to a memory address also referenced in the line erroring, but shouldn't affect it in this case).

 

I've tried cutting this down into a small standalone example, but when I reduce all the things around it, it doesn't fail.

So I think it might be around total size of the program messing with tracked registers causing things to go in/out of zero page, or similar.

 

I've attached the minimum I can get it to fail as (see src.zip).

The offending line is line 84, which seems to tip the code into failing.

 

I run this with:

kickc.bat -target=atarixl -odir=build src/atari-io.c

if you comment line 84 out, it compiles fine.

 

src.zip

Edited by fenrock
typo

Share this post


Link to post
Share on other sites
On 10/11/2020 at 4:08 PM, fenrock said:

When I uncomment the line *COLCRS++; then compiling is throwing the error:

That line will increment the pointer address by 2 bytes as it's defined as a "word" is that what you meant to do.

 

To make it work to increment the data pointed to by COLCRS, you need brackets i.e. (*COLCRS)++

that will increment the data not the pointer.

 

Not too sure why the compiler is complaining unless the definition of COLCRS has been set as an area that

can't be changed, only had a quick look and it appears to be a page zero location.

Share this post


Link to post
Share on other sites
On 10/14/2020 at 10:46 AM, TGB1718 said:

That line will increment the pointer address by 2 bytes as it's defined as a "word" is that what you meant to do.

 

To make it work to increment the data pointed to by COLCRS, you need brackets i.e. (*COLCRS)++

that will increment the data not the pointer.

 

Not too sure why the compiler is complaining unless the definition of COLCRS has been set as an area that

can't be changed, only had a quick look and it appears to be a page zero location.

Yes that was one error in my code, and probably triggered the issue.

 

I've finished my implementation of conio.c for atari now and am trying to setup a Merge Request with @JesperGravgaard so hopefully we'll see ability to do printf etc on Ataris soon!

 

Share this post


Link to post
Share on other sites
48 minutes ago, fenrock said:

I've finished my implementation of conio.c for atari now and am trying to setup a Merge Request with @JesperGravgaard so hopefully we'll see ability to do printf etc on Ataris soon!

Thank you @fenrock ! 

 

I will be merging your conio.c implementation into KickC master, and it will be included in the next release.

 

  • Like 1

Share this post


Link to post
Share on other sites

KickC version 0.8.5 adds a number of improvements and new features.

Of specific interest for the Atari 8bit it adds support for creating "real" XEX-files with multiple segments - supporting both run-address and init-addresses. This is achieved through a new KickAss linker plugin https://gitlab.com/jespergravgaard/kickass-plugin-atari-xex. The plug-in was developed in cooperation with @fenrock

Get the new release here: https://gitlab.com/camelot/kickc/-/releases

  • Thanks 2

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...