Jump to content

Photo

GCC for the TI


310 replies to this topic

#276 TheMole OFFLINE  

TheMole

    Dragonstomper

  • 744 posts
  • Location:Belgium

Posted Wed May 25, 2016 3:06 PM

There's no explicit support, but gcc is tremendously configurable and can easily be used to create code that uses the extra RAM pages provided by the SAMS (in much the same way that it can be used to create code for bankswitching carts, I created a thread on that last year explaining how I did it). All it would require is a little inline assembly to do the page switching (I believe page switching is CRU based on the SAMS? If it's 'memory mapped' like a cart you don't even need assembly).

 

Having said that, it would be awesome if the compiler could natively support bankswitched memory (both SAMS and latching carts), making it so that one wouldn't have to explicitly switch banks and copy state when running code in another bank (via so-called trampoline functions). The non-standard concept of 'far pointers' in the old DOS days was introduced to do exactly that. Not sure how feasible it is to add that the the tms9900 backend in gcc though :).

 

*edit* but the short answer is 'yes', you can use SAMS memory in gcc programs :).


Edited by TheMole, Wed May 25, 2016 3:07 PM.


#277 mindlord OFFLINE  

mindlord

    Star Raider

  • 76 posts

Posted Tue Sep 6, 2016 10:42 AM

Ok, so, How do I set this up to create flashrom99 compatible files?



#278 TheMole OFFLINE  

TheMole

    Dragonstomper

  • 744 posts
  • Location:Belgium

Posted Wed Sep 7, 2016 9:01 AM

Ok, so, How do I set this up to create flashrom99 compatible files?

Basically, you need to create a linker script (a text file with an .ld extension) that tells GCC the memory layout you're targeting. This is in and by itself not terribly hard, but it's a bit of an awkward syntax to work with: https://www.math.uta.../info/ld_3.html

 

Using linker scripts, you can:

  - create the required cart header

  - locate executable code and constants in cart space (the .text section)

  - locate variables in scratchpad (the .data and .bss sections)

 

If you give me a couple of days, I might be able to help out in creating that linker script, but I probably won't be able to get to it before the weekend.



#279 mindlord OFFLINE  

mindlord

    Star Raider

  • 76 posts

Posted Thu Sep 8, 2016 3:08 PM

Thanks I'll give this a look this weekend too.

 


Edited by mindlord, Thu Sep 8, 2016 5:53 PM.


#280 jedimatt42 OFFLINE  

jedimatt42

    Stargunner

  • 1,211 posts
  • Location:Beaverton, OR

Posted Thu Sep 22, 2016 1:59 PM

Should I be able to create a def in .asm, and then link to it and copy data from it in c code? 
 
I tried the following in 'images.asm'
 
 
  def image
image:
  DATA >0001, >0002, >0003.... 
 
Then in my main.c I have:
 
 
extern const char* image;
...
vdpmemcpy(gSpritePat, image, 32);
Things all link, but at runtime it seems to copy garbage data.

By contrast, if I transform the pattern data to c and embed in an array it works...
 
const char image[32] = { 0x00, 0x01, .... };
...
vdpmemcpy(gSpritePat, image, 32); 
And life is happy...

The reason I ask, is that Magellan handily outputs patterns in .asm DATA statements... And it just seems that I should be able to do this.

I haven't broken down and opened the generated bin, and checked that the addresses are correct when in the ASM... I suppose that is next...

-M@

#281 Tursi OFFLINE  

Tursi

    River Patroller

  • 4,746 posts
  • HarmlessLion
  • Location:BUR

Posted Thu Sep 22, 2016 3:12 PM

I usually do the C includes, but yeah, you should be able to do what you are showing.

 

A quick test gave me similar results:

 

 DEF TESTDAT
TESTDAT DATA 1,2,3,4,5

// http://harmlesslion.com - visit the web page for contact info
//
// uses libti99
#include "vdp.h"
extern const char *TESTDAT;
int main() {
 // init the screen
 {
  int x = set_graphics(VDP_SPR_8x8);  // set graphics mode with 8x8 sprites
  charsetlc();       // get character set including lowercase
  vdpmemset(gColor, 0x10, 32);   // all colors to black on transparent
  vdpchar(gSprite, 0xd0);     // all sprites disabled
  VDP_SET_REGISTER(VDP_REG_MODE1, x);  // enable the display
  VDP_REG1_KSCAN_MIRROR = x;    // must have a copy of VDP Reg 1 if you ever use KSCAN
 }
 VDP_SET_REGISTER(VDP_REG_COL, 0x07);
 // display a build date in lieu of a version
 writestring(16,5,"Testing: ");
 faster_hexprint(TESTDAT[0]);
 faster_hexprint(TESTDAT[1]);
 faster_hexprint(TESTDAT[2]);
 faster_hexprint(TESTDAT[3]);
 faster_hexprint(TESTDAT[4]);
 for (;;) { }

 return 0;
}

 

The above did not work, instead of some variant of the data provided (I would have expected 0001000200) I got what looked like pointers (E0002483C0).

 

Looking at the assembly code, it showed this around the TESTDAT pointer:

 

 mov  @TESTDAT, r1
 movb *r1, r1

 

And therein lies the issue. TESTDAT is a variable that /contains/ a pointer, GCC expects memory to be backing it. It's not a memory address itself according to the way we defined it.

 

TESTDAT contains the pointer value >A0E4 in my build (per the map), which is the correct address for the data (looking at the debugger).

 

I'm not sure the /right/ answer to this, honestly. This works, at the cost of two extra bytes in RAM for the variable:

 

extern const char *TESTDAT;
const char *tt = &TESTDAT;

 

(then dereference 'tt' instead of TESTDAT). The generated code is efficient enough, tt is just generated with a DATA statement:

 

tt
 data TESTDAT

 

It does seem like there should be a better way... the problem is that TESTDAT is a constant value, not a variable. The number representing TESTDAT doesn't exist anywhere in the code, so it can't be dereferenced.



#282 Tursi OFFLINE  

Tursi

    River Patroller

  • 4,746 posts
  • HarmlessLion
  • Location:BUR

Posted Thu Sep 22, 2016 3:15 PM

Ah, this works... some very ugly casting (so I wrapped it in a macro)
 
 
extern const char *TESTDAT;
#define DEREFLABEL(xx,off) *(((const char*)(&xx))+(off))
 
I then used it like this:
 
 faster_hexprint(DEREFLABEL(TESTDAT,0));
 faster_hexprint(DEREFLABEL(TESTDAT,1));
 faster_hexprint(DEREFLABEL(TESTDAT,2));
 faster_hexprint(DEREFLABEL(TESTDAT,3));
 faster_hexprint(DEREFLABEL(TESTDAT,4));
The resulting code was clean and exactly what we'd expect:

	li   r9, faster_hexprint
	movb @TESTDAT, r1
	bl   *r9
	movb @TESTDAT+1, r1
	bl   *r9
	movb @TESTDAT+2, r1
	bl   *r9
	movb @TESTDAT+3, r1
	bl   *r9
	movb @TESTDAT+4, r1
	bl   *r9

Edited by Tursi, Thu Sep 22, 2016 3:16 PM.


#283 jedimatt42 OFFLINE  

jedimatt42

    Stargunner

  • 1,211 posts
  • Location:Beaverton, OR

Posted Thu Sep 22, 2016 5:09 PM

You just saved me hours :) Thanks!

So now I have another experiment to run when I get home... It seems like TESTDAT is actually the first value in the block of data. So the mistake might be declaring it as a pointer.

I think this would work (if you don't want the second 'tt' pointer in your binary...:
 
extern const char TESTDAT;
#define TESTDAT_PTR (&TESTDAT)

...

vdpmemcpy(gSpritePat, TESTDAT_PTR, 32);
I suppose the generated assembly should be looked at to see which is friendlier.

-M@

#284 jedimatt42 OFFLINE  

jedimatt42

    Stargunner

  • 1,211 posts
  • Location:Beaverton, OR

Posted Thu Sep 22, 2016 11:31 PM

Ok, I think this is funny... if I declare the truth in my C 'extern' statement, it works naturally...

I have a 32 byte pattern referenced wth a DEF in an assembly file.
 

        def tst_vader
tst_vader:
        DATA >0000, >1030, >6043, >CEFD
        DATA >FDCE, >4360, >3010, >0000
        DATA >0000, >080C, >06C2, >73BF
        DATA >BF73, >C206, >0C08, >0000

 
 
Then in my .c code, I actually declare it to be an array of 32 bytes...
 

extern const unsigned char tst_vader[32];

Now in C, when the symbol tst_vader is referenced, it is a pointer to the beginning of the array of data. Which is exactly what I want.
It is a byte array, and can be indexed and referenced naturally in C.  
 

vdpmemcpy(gSpritePat, tst_vader, 32);

This generated the following assembly code:
 

        li   r2, tst_vader
        li   r3, >20
        bl   @vdpmemcpy

which is exactly what I would expect.

-M@



#285 Tursi OFFLINE  

Tursi

    River Patroller

  • 4,746 posts
  • HarmlessLion
  • Location:BUR

Posted Thu Sep 22, 2016 11:37 PM

That's interesting :) But a lot cleaner than mine! :)

#286 mindlord OFFLINE  

mindlord

    Star Raider

  • 76 posts

Posted Sat Oct 1, 2016 4:39 PM

Heads up Taking the modulus of an unsigned char either results in undefined behavior, or a complete failure of gcc to parse the file. Took me two days to figure that one out. because sometimes it would compile, but behave erratically, other times not throwing errors about parse error at end of input or some-such. I'll try to make some code to reproduce the bug.



#287 Asmusr OFFLINE  

Asmusr

    River Patroller

  • 2,426 posts
  • Location:Denmark

Posted Sat Nov 5, 2016 5:31 AM

Would it be possible to add SAMS support using far pointers?



#288 insomnia OFFLINE  

insomnia

    Star Raider

  • Topic Starter
  • 71 posts
  • Location:Pittsburgh, PA

Posted Wed Nov 23, 2016 9:43 PM

Once again, it's patch time. They have been added to the first post of this thread

 

Life has been particularly distracting lately, so I haven't been able to spend as much time doing TI stuff as I would like.

 

I have finished a floating point library for ieee singe precision floats, and have been slowly building up the parts of libc which are OS-independent. I would still like to work with a later GCC version, but just haven't been able to get to it. The long-term plan is to write a new OS for the TI hardware, but that seems to be far in the future.

 

Anyway, here's the fixes I made while working on the other stuff:

 

  Added compilation pass to better use post-increment addressing
  Ensured word alignment for symbols
  Removed optimization of tests against zero, they emitted unnecessary opcodes
  Fixed 32-bit shift instructions
  Fixed shift instructions to handle shift by zero bits
  Fixed and instruction to use ANDI when appropriate
  Added optimizations for shift of 32-bit value by 16 bits
  Fixed multiply to prevent using MPY with an immediate operand

 

The test against zero code I removed was never called in a helpful manner. The idea was to take advantage of notes on register deaths to do some slightly faster, but destructive testing. Unfortunately, those notes are aways removed before the optimization could be used. The end result was to always insert a MOV to do testing, even if an earlier instruction already set the condition flags properly. We're better off without that junk.

 

The new compilation pass searches for places where pointer increments can be merged with an earlier use, resulting in more post-increment addressing. This can save a few instructions in certain use cases and is a fairly neat bit of code.

 

The multiply fix corrects a problem originally seen by TheMole this spring (Yikes! So long ago!), and was pretty straightforward.

 

The other fixes are pretty self-explanatory, and don't need much discussion.

 

One thing that didn't get added to this patch was a failed attempt to reorder the register usage to eliminate MOV instructions. If it worked, it could reduce most code by 7%, but in the end it was too difficult to avoid breaking 32-bit values or scrambling function arguments. Maybe I will get back to this at some point ant try again.

 

Several questions have been asked about GCC natively handling SAMS or paged memory, or far pointers in general. This is not really practical. There are too many different ways that vendors have extended the memory space to be able to support them all in the compiler. The right way to handle this is to make a library of functions to handle these extensions. I'm looking into finding some way to make this easier, but haven't put much time into that effort.

 

As always, If anyone finds any issues or sees a way to improve the generated code please let me know.



#289 Asmusr OFFLINE  

Asmusr

    River Patroller

  • 2,426 posts
  • Location:Denmark

Posted Thu Nov 24, 2016 4:18 PM

Several questions have been asked about GCC natively handling SAMS or paged memory, or far pointers in general. This is not really practical. There are too many different ways that vendors have extended the memory space to be able to support them all in the compiler. The right way to handle this is to make a library of functions to handle these extensions. I'm looking into finding some way to make this easier, but haven't put much time into that effort.

 

I don't think you have to worry about any other memory expansions than SAMS since this would account for about 95% of current users. The really cool thing would be to have a high level programming language that supported SAMS in a transparent manner. But I'm beginning to realize I have to write my own compiler to accomplish this goal.



#290 ElectricLab OFFLINE  

ElectricLab

    Chopper Commander

  • 196 posts
  • Location:Hillsboro, Oregon

Posted Mon Nov 28, 2016 5:05 PM

Question about gcc on for the TI:

I have been adding to my silly tank game, and have finally gotten to the point where it won't load in emulation (js99er.net) and I noticed that the binary has exceeded 8192, weighing in at 8290. I noticed that other binaries on the SD card for the FR99 that I have contains binaries that are 8192, 16384, 32768, so I was wondering if the binary must be a multiple of 8K in size in order to work.

 

The question is - is the fix as easy as altering my Makefile to signal the assembler or linker to have it pad to 16384 or am I way off base?

Right now my LDFLAGS is set to:

 

LDFLAGS=\

  --section-start .text=6000 --section-start .data=8320

 

Any help is appreciated!



#291 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,315 posts
  • Location:Silver Run, Maryland

Posted Mon Nov 28, 2016 7:05 PM

Question about gcc on for the TI:

I have been adding to my silly tank game, and have finally gotten to the point where it won't load in emulation (js99er.net) and I noticed that the binary has exceeded 8192, weighing in at 8290. I noticed that other binaries on the SD card for the FR99 that I have contains binaries that are 8192, 16384, 32768, so I was wondering if the binary must be a multiple of 8K in size in order to work.

 

The question is - is the fix as easy as altering my Makefile to signal the assembler or linker to have it pad to 16384 or am I way off base?

Right now my LDFLAGS is set to:

 

LDFLAGS=\

  --section-start .text=6000 --section-start .data=8320

 

Any help is appreciated!

 

For programs to work in the FR99, they must be set up to run from ROM.

 

If your program can be assembled to an E/A5 program, that can be converted with Fred's Module Creator to a ROM binary up to 32KiB.

 

If you are producing a ROM binary, anything larger than 8KiB must use bank-switching.  Each bank's code must start at >6000.  You will need the trampoline code to do the necessary switching.  There's plenty of help here once we know what you're trying to do.  I have not set up bank-switching in GCC, but I'm sure others here have. 

 

...lee


Edited by Lee Stewart, Mon Nov 28, 2016 7:10 PM.


#292 ElectricLab OFFLINE  

ElectricLab

    Chopper Commander

  • 196 posts
  • Location:Hillsboro, Oregon

Posted Tue Nov 29, 2016 12:37 AM

 

For programs to work in the FR99, they must be set up to run from ROM.

 

If your program can be assembled to an E/A5 program, that can be converted with Fred's Module Creator to a ROM binary up to 32KiB.

 

If you are producing a ROM binary, anything larger than 8KiB must use bank-switching.  Each bank's code must start at >6000.  You will need the trampoline code to do the necessary switching.  There's plenty of help here once we know what you're trying to do.  I have not set up bank-switching in GCC, but I'm sure others here have. 

 

...lee

 

Thanks Lee. I haven't tried to assemble to an E/A5 program since (I thought) it's easier and faster to make edits to the code in my editor, save to disk, alt-tab to a terminal, type 'make' to build a ROM binary, alt-tab to the browser and upload to js99er.net using its Open Cartridge button. Test code, alt-tab back to the editor and lather, rinse, repeat. 

 

Can an E/A5 binary be natively 32k without any trampolining or other gymnastics to do bank switching? I'd certainly like to learn the tricks that you guys have come up with, so I'll scour this thread some more in case it's been asked/answered before.

 

Thanks!



#293 Tursi OFFLINE  

Tursi

    River Patroller

  • 4,746 posts
  • HarmlessLion
  • Location:BUR

Posted Tue Nov 29, 2016 2:42 AM

E/A#5 can natively do up to 24k without any banking (the other 8k is in a non-contiguous memory space, good for stack space).

#294 mindlord OFFLINE  

mindlord

    Star Raider

  • 76 posts

Posted Sat Jan 7, 2017 11:56 AM

Just a note: Compiling with -Os instead of -O2 produces significantly tighter code. I saved almost 1 full Kilobyte of ROM by making this one change, and no perceivable change in execution speed. If you're trying to squeeze everything into 8K it is certainly a huge benefit.



#295 insomnia OFFLINE  

insomnia

    Star Raider

  • Topic Starter
  • 71 posts
  • Location:Pittsburgh, PA

Posted Sun Feb 19, 2017 12:14 PM

Hey everyone, I've got some more patches.

 

At  this point, the compiler is getting pretty mature, and finding a bug or a missing feature has become a rare event. I wanted to get these changes out since they work, and I'm not  sure what else to work on.

 

Anyway, here's what's new in this patch:

 

Changes to GCC, patch 1.14

  Tail call optimization

  Confirmed support for the C++ language

 

Tail call optimization can remove the need for a stack in some cases, which is helpful for recursion or cases where a call is the last operation in a function. This is a common optimization strategy, and a quick Google search can be more informative tha what I could write here.

 

The other feature that has now been tested is support for the C++ language. This can sometimes be more useful than C for certain dessigns. This also implies that all the other languages GCC supports: Java, Fortran and Ada, should work also. Unfortunately, I don't know Java or Ada well enough to test properly, and I doubt that many people are waiting desperately to use Fortran.

 

I've included a "hello world" example in C++ in the first post of this thread, as well as the patch and a new version of the GCC installer that uses the latest patches.

 

I've looked into far pointers, and unfortunately, I can't make them work in the compiler. GCC only uses one size for pointers. If we used 32-bit far pointers, we would have to use 32 bits for ALL pointers, resulting in much less efficient code in the general case. We would lose the use of at least one register. The stack could be up to twice as large. Code size would be larger,  and memory requirements would increase. In short, there's no real advantage. If far pointers are really needed, they will need to be emulated by function calls. I'm not happy about this, but that's where we stand.

 

I've also noticed that when using -O2 optimization, GCC likes to inline function calls as much as possible. If functions are not marked as static, they will be duplicated and not called in the output binary. This is done under the assumption that a non-inlined version will be needed for other code. So use static functions whenever possible.

 

If anyone has any problems, or finds a bug or improvement, please let me know.



#296 TheBF OFFLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed Mar 8, 2017 12:02 AM

So now that Insomnia has built a good C compiler for the TI-99, (merci) it becomes possible to build small C for the TI-99.

This would allow you to create something that resembles C programs on the TI-99 itself.

It would not compile very fast (means glacial speed) and of course it would never generate the code quality that we get with this GCC implementation.

Small C V1.0 was a 20K binary on DOS so it's possible. In fact I would think that 9900 code would have higher semantic density than '86 code

so it should be a little smaller.

 

I notice that Small C 1.1 however bloated to 33Kbytes. Such a tragedy. ;-)

 

B



#297 Willsy OFFLINE  

Willsy

    River Patroller

  • 3,009 posts
  • Location:Uzbekistan (no, really!)

Posted Wed Mar 8, 2017 12:57 AM

We already have small c for the 4A. Called c99, it was written by Clint Pulley. There are a number of libraries available for it (bitmap, printf etc).

It's really neat. As far as I know it doesn't do any optimisation.

#298 TheBF OFFLINE  

TheBF

    Moonsweeper

  • 308 posts
  • Location:The Great White North

Posted Wed Mar 8, 2017 8:03 AM

I should have guessed as much or maybe check the programming resources page?

Amazing how much work people do for this old platform.

 

Have you every used it?  I think I will have to get it and see what the code looks like.

 

...another day.

 

B



#299 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,315 posts
  • Location:Silver Run, Maryland

Posted Wed Mar 8, 2017 9:44 AM

See also F.G. Kaal’s “C99 Compiler and Optimizers” for PC based on Clint Pulley’s C99.  Fred’s site is here and his C99 project is on his “Projects” page.

 

...lee



#300 Willsy OFFLINE  

Willsy

    River Patroller

  • 3,009 posts
  • Location:Uzbekistan (no, really!)

Posted Thu Mar 9, 2017 5:46 AM

I should have guessed as much or maybe check the programming resources page?
Amazing how much work people do for this old platform.
 
Have you every used it?  I think I will have to get it and see what the code looks like.
 
...another day.
 
B


Yes I wrote a sprite definer program with it. It works just fine but the edit/save/compile/assemble/load/link/test/repeat cycle is a pain in the ass. Give me Forth any day!

https://youtu.be/Jf_m0_O5RXc




0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users