Jump to content
insomnia

GCC for the TI

Recommended Posts

Lucien: very cool that you've made a Windows build available for everyone. I know some people were looking for this (at least

arcadeshopper and Rasmus, if I remember correctly), and I'll probably use it in a pinch on a Windows machine as well. Much appreciated!

 

I haven't been able to further look at my clang build problem, so I haven't been able to use the new version yet. Perhaps I should try compiling with GCC for mac.

Share this post


Link to post
Share on other sites

With Lucien's permission, and if Retroclouds agrees, I think it might be worth adding this to the gcc section of the development resources thread.

  • Like 2

Share this post


Link to post
Share on other sites

With Lucien's permission, and if Retroclouds agrees, I think it might be worth adding this to the gcc section of the development resources thread.

 

Sure, no problem.

Share this post


Link to post
Share on other sites

I haven't been able to further look at my clang build problem, so I haven't been able to use the new version yet. Perhaps I should try compiling with GCC for mac.

 

I didn't respond earlier since I thought I could knock out a quick fix, but that doesn't seem likely.

 

I was able to replicate your error compiling on a Linux box with GCC so using clang sould be just fine. The error is occuring when trying to compile libgcc. The compiler itself is fine.

 

If you change the line in install.sh from "make all-gcc all-target-libgcc" to "make all-gcc", everything (except libgcc) will be build and installed correctly. This should be good enough to at least use the compiler. Libgcc consists of a lot of rarely used functions, so you should be OK.

 

I'm still in the investigation stage, but I suspect that the changes I made to prevent word to byte conversions is somehow interfering with the code that assigns registers and memory locations. The error occurs when GCC tries to find an instruction which will handle R27, which is used as a placeholder until a real register or memory location can be assigned. For obvious reasons, this will fail.

 

I'm trying to get a fix out ASAP, but it seems like it won't be as easy as I first thought. Sorry.

Share this post


Link to post
Share on other sites

 

I didn't respond earlier since I thought I could knock out a quick fix, but that doesn't seem likely.

 

I was able to replicate your error compiling on a Linux box with GCC so using clang sould be just fine. The error is occuring when trying to compile libgcc. The compiler itself is fine.

 

If you change the line in install.sh from "make all-gcc all-target-libgcc" to "make all-gcc", everything (except libgcc) will be build and installed correctly. This should be good enough to at least use the compiler. Libgcc consists of a lot of rarely used functions, so you should be OK.

 

I'm still in the investigation stage, but I suspect that the changes I made to prevent word to byte conversions is somehow interfering with the code that assigns registers and memory locations. The error occurs when GCC tries to find an instruction which will handle R27, which is used as a placeholder until a real register or memory location can be assigned. For obvious reasons, this will fail.

 

I'm trying to get a fix out ASAP, but it seems like it won't be as easy as I first thought. Sorry.

 

Yup, that did the trick, thanks! I hadn't noticed it was a problem in libgcc (the gcc source tree is a mystical and mythical beast that hasn't shown me all it's secrets yet... lot's of learning still to do on that front :) ). I should point out that this was the first time I tried compiling with your script, and I actually never tried compiling libgcc in the past, so this might or might not be a new problem. I don't use any of the library's functions, so I'm set for now. Thank you very much for helping me out!

 

For those that are interested in an OS X build, I can post it here. But it might be good to hold off on that until I can compile libgcc for a full package...

Edited by TheMole

Share this post


Link to post
Share on other sites

I just tried the compiler and wanted to report on a small change I needed to do (to my code) to make it compile with the new patch.

I'm using the extern keyword to define cross-file global variables in my code. With the previous version the following worked:

 

In file snd_engine.h:

extern unsigned char[BUFFER_SIZE] sfxbuffer;

In file snd_engine.c:

unsigned char sfxbuffer[BUFFER_SIZE];

In file main.c:

#include "snd_engine.h"

load_song(sfxbuffer, "DSK1.MAIN_M", SONG_SIZE);
play_song(sfxbuffer, SONG_NUMBER);

With the new patch, this setup fails at the linking step with an undefined symbol error on the variable sfxbuffer. Changing the definition of sfxbuffer in snd_engine.c to:

unsigned char sfxbuffer[BUFFER_SIZE] = { 0 };

solves the problem and the program compiles, links and runs fine.

 

I just wanted to report it to ensure this is intentional/known behavior, and is not a symptom of some other bug. According to the C standard, the first version should work (without the initializer).

 

Also of note, when compiling the version with the initializer with the old patch, the sfxbuffer ends up in the .data segment, whereas without it ends up in the .bss segment (which I believe is the correct behavior). With the new version it ends up in the .bss segment, so that looks good.

  • Like 1

Share this post


Link to post
Share on other sites

I just wanted to report it to ensure this is intentional/known behavior, and is not a symptom of some other bug. According to the C standard, the first version should work (without the initializer).

 

Nope you're right, no changes to your code should have been necessary. Behold my shame:

 

 

Input code:

int no_init[10];
int init_zero[10] = {0};

Output assembly:

    cseg
no_init
    bss 20

    def    init_zero

    def    init_zero
init_zero
    bss 20

The output SHOULD be:

    cseg
    def    no_init
no_init
    bss 20

    def    init_zero
init_zero
    bss 20

This is a side-effect of the earlier change made to keep variables from mistakenly being placed in the .bss section. Fortunately, this is an easy fix, and will get rollled into the next patch. In the mean time, what you've done here is the best workaround.

 

Thanks for the report.

Share this post


Link to post
Share on other sites

This is a side-effect of the earlier change made to keep variables from mistakenly being placed in the .bss section. Fortunately, this is an easy fix, and will get rollled into the next patch. In the mean time, what you've done here is the best workaround.

Any chance of a copy of this patch, even just the fix for this issue? :)

Share this post


Link to post
Share on other sites

Having a few small issues with my configuration tool - which is a stupidly large single-file program linking to my libti99.

 

Two issues are popping up somewhat at random...

 

First, this pattern:

 

void GromWriteData(unsigned int address, unsigned char port, unsigned char dat);

for (int i2=0; i2<32; i2++) {
	GromWriteData(0xE100, 15, i2);
is occasionally generating:

 

/cygdrive/c/cygwin/home/tursi/bin/tms9900-gcc -c main.c -O2 -std=c99 -s --save-temp -I../libti99 -o main.o
insn does not satisfy its constraints:
(insn 953 306 985 17 main.c:1162 (set:QI (reg:QI 79)
        (subreg:QI (reg:HI 79) 1)) 73 {movqi} (nil))
main.c: In function `loaddevice':
main.c:1307: internal compiler error: in reload_cse_simplify_operands, at postreload.c:396
I was able to fix it by changing the loop index to an unsigned char. This is in a block with four nested loops, so maybe that's part of it.

 

The second one is an out-of-range jump in a fairly messy bit of code, I think it's trying to optimize and mis-counting instructions...

 

/cygdrive/c/cygwin/home/tursi/bin/tms9900-gcc -c main.c -O2 -std=c99 -s --save-temp -I../libti99 -o main.o
/cygdrive/c/cygwin/home/tursi/bin/tms9900-ld crt0_ea5.o  main.o -lti99 -L../libti99 --section-start .text=a000 --section-start .data=2080 -M -o gromcfg.ea5.elf
> ea5.map
main.o: In function `L347':
(.text+0x23f7): relocation truncated to fit: R_TMS9900_PC8 against `.text'
That one I used a code rearrangement for - I think you may have already mentioned one of these...? I don't have the sample for that, but I've zipped up the constraints one (sorry, the code is not pretty).

constraints.zip

Share this post


Link to post
Share on other sites

This is actually a bit involved.

 

Just for some quick background, there are several tools used to compile a binary file: The compiler (GCC), the assembler(GAS), the linker (LD), and a tool to convert the result to a format the TI can use (for now that's just ELF2EA5 or ELF2CART).

 

The linker is responsible for defining the address for the code and can use a configuration file to do this. This allows you can assign locations for everything in the output file. There are a lot of options available, and GNU has a pretty good manual at http://ftp.gnu.org/o...ode/ld_toc.html

 

There is a "hello world" example for carts back in post #64 of this thread. It doesn't use a link file and instead uses command-line arguments to define locations in the output file. Here's a link file which is equivalent to that example, let's call it linkfile.ld:

 

SECTIONS{
. = 0x6000;
.text : {*(.text);}

. = 0x2000;
.data : {*(.data);}
.bss : {*(.bss);}
}
The dot symbol is the current output location. By modifying it, the locations of the sections will be defined. In this example, all .text sections are linked assuming they will be loaded starting at location 0x6000, the .data and .bss sections are loaded starting at location 0x2000. There are a lot of ways to write the link file to accomplish the same result. Check the ld manual for more details here.

 

This link file would be used by GCC by using the "-T" switch, like this:

tms9900-gcc -T linkfile.ld ctr0.o main.o -o hello.elf
Now, the segments you were wondering about are commonly called overlays, and there are a lot of examples which can be found online. None of these will be exactly what you are looking for, but the GNU tools are used for everything, and there are common concepts which would probably be helpful.

 

Here's an example link file using three overlays:

SECTIONS
{
. = 0x2000;
.data : { *(.data); }
.bss : { *(.bss); }

OVERLAY 0x6000 : AT (0x0000)
{
.otext1 { overlay1.o(.text); }
.otext2 { overlay2.o(.text); }
.otext3 { overlay3.o(.text); }
}
}
This will cause all .text sections of the overlay files to be at address 0x6000, and they will appear sequentially in the output file. The .data and .bss sections will start at address 0x2000. Here are the sections defined in the output file:

 

[email protected]:~/dev/tios/src/test_overlay$ tms9900-readelf -S hello.elf
There are 11 section headers, starting at offset 0x650:

Section Headers:
  [Nr] Name			  Type		    Addr	 Off    Size   ES Flg Lk Inf Al
  [ 0]				   NULL		    00000000 000000 000000 00	  0   0  0
  [ 1] .bss			  NOBITS		  00002000 000800 000006 00  WA  0   0  1
  [ 2] .otext1		   PROGBITS	    00006000 000200 000006 00  AX  0   0  2
  [ 3] .rela.otext1	  RELA		    00000000 0008ec 000000 0c	  9   2  4
  [ 4] .otext2		   PROGBITS	    00006000 000400 000006 00  AX  0   0  2
  [ 5] .rela.otext2	  RELA		    00000000 0008ec 000000 0c	  9   4  4
  [ 6] .otext3		   PROGBITS	    00006000 000600 000006 00  AX  0   0  2
  [ 7] .rela.otext3	  RELA		    00000000 0008ec 000000 0c	  9   6  4
  [ 8] .shstrtab		 STRTAB		  00000000 000606 000047 00	  0   0  1
  [ 9] .symtab		   SYMTAB		  00000000 000808 0000b0 10	 10   5  4
  [10] .strtab		   STRTAB		  00000000 0008b8 000034 00	  0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
An additional tool will then be required to split up the output file into pieces suitable for Classic99 or MESS or actual hardware or whatever. Unfortunately, no one has written a tool to do that yet.

 

Finally, GCC can produce position independent code (by using the "-fpic" switch), but that feature is currently broken for the TMS9900. If it were to work, the code would be compiled so it could be loaded to and run from any address. This probably not what you want.

 

 

So this has ELF support for the cartridge based TI/99 4a?

Share this post


Link to post
Share on other sites

 

So this has ELF support for the cartridge based TI/99 4a?

 

Not sure what you mean by ELF support. When compiling and linking something with gcc, you end up with an ELF binary. Before you can run it on a TI, whether that be cartridge or disk, you need to run it through elf2cart.exe or elf2ea5 respectively. Those tools basically strip the elf header, does endianness conversion if needed and copies the sections to the right locations. You end up with a TI native binary that can be put on cart of disk, so the TI doesn't know this ever was an ELF file and as such has no "ELF support" itself. Of course, since gcc spits out ELF binaries you could say it "adds ELF support", but since it's just an intermediary format I'm not sure that's what you meant.

Share this post


Link to post
Share on other sites

I needed this, so I took a look myself. Hopefully Insomnia is just catching up on his sleep and we'll see him soon.

 

Based on his problem description above and a diff between the last two patches, I was able to find the part to fix. It took a few passes to fix it so it actually worked, but it seems to be working now.

 

Rather than confuse things with another patch, I'll just give you the snippet of code to fix, and I'll also include my patched compiler.

 

To build it yourself, just head into your build folder under gcc-4.4.0\gcc\config\tms9900\tms9900.h

 

Find ASM_OUTPUT_COMMON (should be at line 1090), insert the three lines in bold below (watch the end of line backslashes, make sure there's no whitespace after them).

 

#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \
do { \
switch_to_section (bss_section); \
fputs("\tdef ", (STREAM)); \
assemble_name ((STREAM), (NAME)); \
fputs("\n", (STREAM)); \

assemble_name ((STREAM), (NAME)); \
fprintf ((STREAM), "\n\tbss %u\n", (int)(ROUNDED)); \
} while (0)

 

Then in the build\gcc\build folder, just "make all-gcc ; make install"

 

That fixes the unresolved symbol errors. Attached find my GCC executables build for Cygwin - you can drop them in your bin folder (backup your originals first). I don't know for certain which one is needed so these are all that the update rebuilt. Use at your own risk - I don't believe any of my other modifications are in here, I went back to running stock with the last patch. ;)

 

TursiGccCygwin.zip

 

  • Like 2

Share this post


Link to post
Share on other sites

Is there a GCC Zip file for Linux (like the windows one posted earlier) or any up to date Linux instructions for building this? I keep getting errors when following the guides.

Share this post


Link to post
Share on other sites

Is there a GCC Zip file for Linux (like the windows one posted earlier) or any up to date Linux instructions for building this? I keep getting errors when following the guides.

 

There's an installer script which handles all this for you: gcc-installer.tar.gz

 

This was added in post #202, but I've shamelessly copied the brief directions below:

 

To use this, run the install.sh script and pass as an argument the directory. The script will download the unmodified files from gnu.org, patch, build, and copy the output files to the location specified.

 

For example, after decompressing the archive, and running this script, tms9900-gcc and friends will be copied to /home/eric/tms9900/bin

$ tar -xzf gcc-installer.tar.gz

$ install.sh /home/eric/tms99900

 

This uses the latest set of patches (binutils patch 1.7, gcc patch 1.10) and should do what you need. Let me know if you have any problems.

 

By the way, I'm in the process of putting together a new GCC patch, so that should be ready in the next day or two. This will address all the problems seen since December. (Wow, has it really been that long? Sorry about that...)

  • Like 2

Share this post


Link to post
Share on other sites

 

There's an installer script which handles all this for you: gcc-installer.tar.gz

 

This was added in post #202, but I've shamelessly copied the brief directions below:

 

 

This uses the latest set of patches (binutils patch 1.7, gcc patch 1.10) and should do what you need. Let me know if you have any problems.

 

By the way, I'm in the process of putting together a new GCC patch, so that should be ready in the next day or two. This will address all the problems seen since December. (Wow, has it really been that long? Sorry about that...)

 

Thanks Insomnia, I tried the script but got the following errors:

 

make[1]: *** [_absvhi2.o] Error 1

make[1]: Leaving directory '/home/sam/Documents/build/gcc-4.4.0/build/tms9900/libgcc'

make: ** [all-target-libgcc] Error 2

=== Failed to build GCC ===

 

I'll get a full log of the execution posted on here by tomorrow as I've got to work late tonight.

Share this post


Link to post
Share on other sites

Oops, I forgot about that problem...

 

The compiler is fine, but there's a bug which causes the build of libgcc (which provides support for some 32-bit operations and other rarely-used function) to fail. The compiler itself is fine, but it contains a few known bugs which the next patch will fix. If you start reading from post #232 you can see the problems other people have seen with this version. It's nothing huge, but there are some rough edges to look out for.

 

To get past the immediate problem though, change the line in install.sh from "make all-gcc all-target-libgcc" to "make all-gcc", everything (except libgcc) will be built and installed as expected.

Share this post


Link to post
Share on other sites

By the way, I'm in the process of putting together a new GCC patch, so that should be ready in the next day or two. This will address all the problems seen since December. (Wow, has it really been that long? Sorry about that...)

Huzzah! Best news I've had in weeks! :)

Share this post


Link to post
Share on other sites

As promised, here's the new patch. The files are attached to post #1 in this thread, and the gcc_installer package there has been updated with the latest patches.

 

I have to admit, this one was harder than I expected. The biggest problem was finding a way to handle the ever-annoying word to byte conversions. From the start, this has been the sticking point for this port. Every attempt at an elegant fix up to now has failed in some edge case. I think the method used here should be simple enough to work without any mysterious compiler bugs in the future.

 

The compiler consists of about 200 different passes, each one doing some distinct operation (parse C code, remove dead code, register allocation, etc.). In this patch I've added a new pass to specifically handle these type conversions. The basic idea is to find every place where a data type conversion in an instruction is done, and put that conversion into it's own instruction. Temporary registers are used for the converted values, and the following passes will emit correct and optimized code.

 

Here's an example to try to show what I'm talking about:

 

char example(int A, char B) {return (char)A + B;}

By default, GCC assumes that for both the byte and word representations, the least significant bits are stored in the least significant byte of the register or memory location holding the value. However, this is not true for values stored in registers. In this case, we need to convert the A value to byte representation. Doing this within the GCC framework turned out to be tricky and error-prone. The new subreg pass converts this code to a more compiler-friendly form.

 

char modified(int A, char B) {char C = (char)A; return C + B;}

In this new form, it's easy to see what the output code should be:

 

mov r1, r3  * Copy A to C
swpb r3     * Convert to byte representation
ab r2, r3   * B += C  (a.k.a (char)A)
mov r3, r1  * Copy to return position

After some optimization passes:

 

swpb r1   * Convert A to byte representation
ab r2, r1 * Return (char)A + B

This method turns out to be a lot easier to implement than I thought. With any luck I'll never need to mess with type conversions again. (Fingers crossed).

 

The other changes in this patch are to fix problems mentioned earlier in the thread, and are pretty straightforward. As always, more details are on my blog, and I'd love to hear of any problems anyone sees.

 

Changes in this patch:

 

Fixed compilation error due to missing include in tms9900.h

Fixed problem declaring global variables, not always exported

Some instruction sizes were defined incorrectly, causing assembly errors

Fixed conditional jump displacement limits, they were too small

Added compilation pass to add needed SWPB instructions.

  • Like 2

Share this post


Link to post
Share on other sites

Brilliant. I look forward to putting this one through it's paces - and thank you again for sticking with it! I remember back in the day, I thought big endian was the way to go, but it's interesting to see how it complicates things like this. :)

  • Like 1

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.
Note: Your post will require moderator approval before it will be visible.

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...