Jump to content
insomnia

GCC for the TI

Recommended Posts

Thanks for the update Insomnia!

 

However, I'm not sure I'm using the last version. I used (and modified) the install script from the first post, the patch file says 1.11 (and 1.7 for binutils), but I get the same problems as with the last version:

  • Build of libgcc crashes (removed that from build script)
  • Errors during compilation when converting bytes-ints
  • Errors with certain divisions.

I'm wondering if there's a way to verify the patch level from a compiled binary? It's not part of the version number, which just reports 4.4.0 :).

 

These are the error messages I get:

wolfie3.c: In function ‘cast_rays’:
wolfie3.c:403: internal compiler error: in subreg_highpart_offset, at emit-rtl.c:1304
 

for this code (SCREEN_DISTANCE is a '#define 3200', distance is an unsigned int)

// calculate slice height based on distance
int sliceheight, slicestart, sliceend;
if (distance) 
	sliceheight = SCREEN_DISTANCE / distance;
else
	sliceheight = SCREEN_HEIGHT;

And:

/Users/lousbergd/tms9900/bin/tms9900-ld crt0_ea5.o  utils.o tistdio.o wolfie3.o --section-start .text=0xa000 --section-start .data=0x2080 -M  -L./libti99 -lti99 -o wolf18a.ea5.elf > ea5.map
wolfie3.o: In function `L55':
(.text+0x1ce): undefined reference to `__divsi3'

For the expression in this code:

verdist = (int)( (long)(256 * ABS(checkx - playerx)) / (long)(ABS(COS255[rayangle])) );

I think the __divsi3 stuff might be related to libgcc not being built, and the first error is probably a type conversion error, but if I understand it correctly both of these should be fixed, right?

 

Not related, but for people trying to compile this on a Mac - and as a reminder for myself next time I want to compile this: note that you need to do a couple of things to make everything compile correctly:

  1. Modify the install script by replacing every instance of 'wget' with 'curl -O', since there's no wget on OS X anymore
  2. You will need to modify toplev.c and toplev.h to fix a host compiler version check that fails with clang (the floor_log2 and exact_log2 functions will redefine an inline function, which isn't allowed in c99, but gcc will allow this). Just remove the inline version in toplev.h and the test around the implementation in toplev.c.
  3. (for now, I think...) remove libgcc from the targets in the gcc config line in install.sh

Either way, a big thank you for all your efforts, I wouldn't be coding for the TI again if it wasn't for this!

Share this post


Link to post
Share on other sites

I'm wondering if there's a way to verify the patch level from a compiled binary? It's not part of the version number, which just reports 4.4.0 :).

This is a really good point I hadn't thought about before. In a future patch I'll need to have a better way to do this. For now, the easiest way to check if patch 1.11 is applied is to compile a file using the -da option. This will create a bunch of debug files describing each step of the compilation process. The content of these files is not important for this test.

 

[email protected]:~/dev/tios/src/temp$ cat dummy.c
int test() {return 1;}
[email protected]:~/dev/tios/src/temp$ tms9900-gcc -da dummy.c
/home/eric/dev/tios/toolchain/lib/gcc/tms9900/4.4.0/../../../../tms9900/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000a074
[email protected]:~/dev/tios/src/temp$ ls *tms9900_subreg
dummy.c.171r.tms9900_subreg
If patch 1.11 has been applied there will be a file ending with tms99900_subreg, otherwise you are likely using patch 1.10. From the problems you are seeing, I'm pretty sure you are using an older patch. As you said, the newer patch should fix everything you are seeing now.

 

Would you be okay with uploading your modified install script somewhere? I don't have access to a Mac, so I would like to incorporate your changes into a future version if you are OK with that. You've given me a lot of ideas on how things can be improved here.

 

I have install miniGW under Windows 7. Is it possible to "upgrade" miniGW with GCC for TI? Maybe some instructions?

If I'm not mistaken, miniGW provides a unix-like environment within Windows, and is similar to Cygwin. If that's the case, you can install the TMS9900 version of GCC alongside the PC version provided by miniGW. The new compiler will be named tms9900-gcc and shouldn't conflict with anything aleady installed. You could try to run the gcc_installer script from within the miniGW environment, I think that should work. If not, Tursi made a video linked earlier in this discussion which documents the process using an older patch. This is a question that has come up a lot, and I really should figure out a better answer for you.

 

By the way, thank you to everyone who has been using GCC and providing feedback. There is no way the compiler would be as functional as it is now without all your help.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks Insomnia. Actually, I get another error when trying your test:

Dannys-MacBook-Pro:wolfie-f18a lousbergd$ echo "int test() { return 1; }" > test.c
Dannys-MacBook-Pro:wolfie-f18a lousbergd$ /Users/lousbergd/tms9900/bin/tms9900-gcc -da test.c
/Users/lousbergd/tms9900/bin/../lib/gcc/tms9900/4.4.0/../../../../tms9900/bin/ld: cannot find -lgcc
Dannys-MacBook-Pro:wolfie-f18a lousbergd$ ls *_subreg
test.c.171r.tms9900_subreg

So, it does look like I'm using the latest version, but it seems that something else is going wrong.

 

I'm not on my home PC now, so I can't give you the install script I modified, but it was extremely simple (basically a find and replace of "wget" with "curl -O"). I'll make a patch for my changes to toplev.c and toplev.h and include the application of that patch in the script if it detects it's running on a Mac.

Share this post


Link to post
Share on other sites

TheMole, some of the problems you are seeing are due to a missing libgcc (__divsi3, test.c output). Since you are having problems building libgcc, that makes sense. The "internal compiler error" problem is king of worrying. That looks like the kind of type conversion problem I thought was fixed.

 

I did some research, and the toplev.h problem seems to be very common when compiling GCC with clang. I'll include a fix for thaqt in the next patch. There's no reason we should need patches for my patches. Since I don't have a Mac to test on, fixing the other errors might be tricky.

 

Unfortunaately, I'll need some help from you to do this. It would be helpful if you could edit wolfie3.c to find the smallest subset of code that causes compilation errors. Based on the filename, I'm guessing there are a lot of dense calculations there which probably stress the compiler beyond what I've seen so far. If you could make a list of the errors seen when building libgcc, that would also be helpful.

 

The libgcc errors are the most suprising to me. Libgcc is built by the copy of GCC that it is has just been built. I've built GCC from scratch using the installer script several times, and I haven't seen any errors when using my Linux box. I'm not sure how using a different OS would make a difference here.

Share this post


Link to post
Share on other sites

I'm currently traveling for work, but I'll prepare a file for you ASAP, probably second half of the week. I'm more than happy to help debug this. Just let me know where to look, and what you want me to do.

 

I think the reason libgcc won't build could be the same reason why my own code won't build. I'll dig up the exact error when I'm near my main computer later this week, but given libgcc implements a number of math functions it wouldn't surprise me the error is the same here.

Share this post


Link to post
Share on other sites

Turn out, I also have the latest version of the compiler on my laptop, and hotels are boring at night :).

 

Anyway, this is the minimum code needed to trigger the error:

/*************************/
/* TI-99/4A Ray caster   */
/* 2013 - Danny Lousberg */
/*************************/

// Includes
#include "lookup.h"					// Needed to calculate movement

// Defines
#define		MAX_INT 			32767
#define 	MAP_WIDTH 			24
#define 	MAP_HEIGHT 			24
#define 	CELL_SIZE 			32		// Size of each wall "cube" on the map: width, depth and height
#define		SCREEN_WIDTH		64		// Number of rays to cast, or number of columns, or slices
#define		SCREEN_HEIGHT		64		// Height of the rendering surface, in pseudo-pixels; not including bottom area
#define		FOV					64		// Field Of View, aka how wide the arc of rays needs to be
#define 	SCREEN_DISTANCE 	3200	// Distance to screen projection plane
										// Formula for this is (SCREEN_WIDTH / 2) / tan(FOV / 2)
#define		ANGLE_STEP			1		// Should be FOV / SCREEN_WIDTH, so FOV needs 
										// to be a multiple of SCREEN_WIDTH, effectively 
										// giving a max resolution of 64 for 
										// realistic looking rendering
#define     SLICEPARAMBUFFER	0x2000	// Where in VRAM do we put our slice parameters? 4 bytes in a row at 0x2000 (8k)
#define		ABS(a)				(((a) < 0) ? -(a) : (a))

// World map
char worldmap[MAP_WIDTH][MAP_HEIGHT] =
{
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,2,2,0,2,2,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
	{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1},
	{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,1,2,2,0,2,2,1,0,0,0,3,0,3,0,3,0,0,0,1},
	{1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,1,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,2,2,2,2,2,2,2,2,2},
	{1,0,0,0,0,1,0,0,0,0,0,1,2,2,2,2,0,0,0,0,0,0,0,2},
	{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2},
	{1,0,0,0,0,0,0,0,0,0,0,1,2,2,2,2,0,0,0,0,0,0,0,2},
	{1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,2,0,0,0,0,0,0,0,2},
	{1,2,2,2,0,0,0,0,2,0,0,0,0,0,0,2,2,2,2,0,2,2,2,2},
	{1,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1},
	{1,2,0,2,0,0,0,0,2,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1},
	{1,2,0,2,2,2,2,2,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1},
	{1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
	{1,2,2,2,2,2,2,2,2,0,0,0,0,0,0,1,0,0,1,1,1,0,0,1},
	{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
};

//*********************
// VDP access ports
//*********************
// Write Address/Register
#define VDPWA	*((volatile unsigned char*)0x8C02)
// Write Data
#define VDPWD	*((volatile unsigned char*)0x8C00)

//*********************
// Inline VDP helpers
//*********************

// Set VDP address for write (adds 0x4000 bit)
inline void VDP_SET_ADDRESS_WRITE(unsigned int x)					{	VDPWA=((x)&0xff); VDPWA=(((x)>>|0x40);	}

// Set VDP write-only register 'r' to value 'v'
inline void VDP_SET_REGISTER(unsigned char r, unsigned char v)		{	VDPWA=(v); VDPWA=(0x80|(r));				}

void draw_slice(unsigned char column, int slicestart, int sliceend, unsigned char color)
{
	// Write parameters to VRAM
	VDP_SET_ADDRESS_WRITE(SLICEPARAMBUFFER);
	VDPWD = (unsigned char)column;
	VDPWD = (unsigned char)slicestart;
	VDPWD = (unsigned char)sliceend;
	VDPWD = (unsigned char)color;

	// Kick of slice rendering program
	VDP_SET_REGISTER(54, 0x20);
	VDP_SET_REGISTER(55, 0x04);
}

// The actual ray casting algorithm, called once per frame
// Basically, we iterate over each screen column and calculate the angle of view
// that is associated with that column. Then we "cast a ray" from the player's position
// along that angle until we hit a wall in our map.
// We use the distance to that wall to calculate the height of the slice to be 
// rendered for the current column (the further away, the smaller the slice)
void cast_rays(int playerx, int playery, int playerangle)
{
	int	column;								// column iterator, range: 0-SCREEN_WIDTH
	int rayangle;	
	unsigned int hordist, verdist;			// distance to the closest wall in horizontal _and_ vertical direction
	int mapx, mapy;							// temp values for checking a hit on the map, will be copied into hitx,hit
	int hitx, hity;							// coords in map space of the _closest_ hit (either vert or hort)
	unsigned int distance;					// distance of the _closest_ hit (either vert or hort)
	int xstep, ystep;						// How many units to step from one wall-boundary to the next
	int checkx, checky;						// coords of the first intersection, before we start "stepping"
	int side = 0;

	// First ray, left-most column starts at half the FOV counterclockwise from the player's angle
	rayangle = playerangle - FOV / 2;
	hitx = hity = 0;

    for(column = 0; column < SCREEN_WIDTH; column++)
    {
		// Normalize angle to 0-359 range
		if (rayangle < 0)
			rayangle += 360;
		if (rayangle >= 360)
			rayangle -= 360;

		// Initialize distance, will be used in comparison later on
		// and there is a code path that could leave this undefined
		distance = MAX_INT;


		// Check for horizontal intersections
		if ((rayangle != 0) && (rayangle != 180))
		{
			int hit;						// Boolean to stop checking for walls
	    
			// initialize to longest distance as we will be picking the shortest distance
			// to a hit between the two axis
			hordist = MAX_INT;

			// Calculate first intersection point on next cell along ray
			// First we calculate the Y coord (easiest)
			if (rayangle > 180)
			{
				// ray is facing up in the map; so we put the checkpoint RIGHT ABOVE (hence the - 1)
				// the boundary of the cell we are in on the Y-axis
				checky = ((playery / CELL_SIZE) * CELL_SIZE) - 1;
				xstep = -STEPX[rayangle]; // = (256 * -CELL_SIZE) / TAN255[rayangle];
				ystep = -CELL_SIZE;
			}
			else
			{
				// ray is facing down in the map; so we put the checkpoint right AT
				// the boundary of the cell BELOW the one we are in on the Y-axis
				checky = ((playery / CELL_SIZE) * CELL_SIZE) + CELL_SIZE;
				xstep = STEPX[rayangle]; // = (256 * CELL_SIZE) / TAN255[rayangle];
				ystep = CELL_SIZE;
			}
			checkx = playerx - ( (256 * (playery - checky)) / TAN255[rayangle] );

			hit = 0;
			mapx = checkx / CELL_SIZE;
			mapy = checky / CELL_SIZE;
			while (!hit)
			{
				// Ray has left the map; need to break out of the loop
				if ( (mapx < 0) || (mapy < 0) || (mapx >= MAP_WIDTH) || (mapy >= MAP_HEIGHT) )
				{
					hordist = MAX_INT;
					break;
				}
			
				// if we hit a non-zero field in the map, we're on the edge of a wall
				if (worldmap[mapx][mapy])
				{
					hit = 1;
					hordist = 1;
				}
				else
				{
					// No wall? Then we take steps to the next boundary and
					// reset the map coords to be checked
					checkx += xstep;
					checky += ystep;
					mapx = checkx / CELL_SIZE;
					mapy = checky / CELL_SIZE;
				}
			}
			
			// Only checked horizontal hits yet, so these are by definition our best guess for
			// the closest hit. We'll check these values against the vertical results later on
			// so we store in the variables for the final result for now...
			hitx = mapx;
			hity = mapy;
			distance = hordist;
		}
		else
		{
			// Angles 0 and 180 have a cos of zero
			// or in other words, we will never see a horizontal intersection
			hordist = MAX_INT;
		}

		// Check for vertical intersections
		if ((rayangle != 90) && (rayangle != 270))
		{
			int hit;						// Boolean to stop checking for walls
	    
			// initialize to longest distance as we will be picking the shortest distance
			// to a hit between the two axis
			verdist = MAX_INT;

			// Calculate first intersection point on next cell along ray
			// First we calculate the X coord (easiest)
			if ( (rayangle < 270) && (rayangle >= 90) )
			{
				// Going left, check against left boundary of current cell
				checkx = ((playerx / CELL_SIZE) * CELL_SIZE) - 1;
				ystep = -STEPY[rayangle]; // = (-CELL_SIZE * TAN255[rayangle]) / 256;
				xstep = -CELL_SIZE;
			}
			else
			{
				// facing right, check against LEFT boundary of NEXT cell
				checkx = ((playerx / CELL_SIZE) * CELL_SIZE) + CELL_SIZE;
				ystep = STEPY[rayangle]; // = (CELL_SIZE * TAN255[rayangle]) / 256;
				xstep = CELL_SIZE;
			}
			// The below should simply be "checky = playery - ( ((playerx - checkx) * TAN255[rayangle]) >> 8 );"
			// But this result overflows when angles approach 90 or 270, likelyhood increase the bigger 
			// the distance between test point and player gets
			// So, for high result values of TAN255, we just pre-scale the numbers before the multiplication
			// For the lower numbers, we don't do prescale since we'de lose too much precision
			if ( ABS(TAN255[rayangle]) > 1000 )
				checky = playery - ( ((playerx - checkx) * (TAN255[rayangle] >> 4)) >> 4 );
			else
				checky = playery - ( ((playerx - checkx) * TAN255[rayangle]) >> 8 );

			hit = 0;
			mapx = checkx / CELL_SIZE;
			mapy = checky / CELL_SIZE;
			while (!hit)
			{
				// Ray has left the map; need to break out of the loop
				if ( (mapx < 0) || (mapy <0) || (mapx >= MAP_WIDTH) || (mapy >= MAP_HEIGHT) )
				{
					verdist = MAX_INT;
					break;
				} 

				// if we hit a non-zero field in the map, we're on the edge of a wall
				if (worldmap[mapx][mapy])
				{
					hit = 1;
					verdist = 1;
				}
				else
				{
					// No wall? Then we take steps to the next boundary and
					// reset the map coords to be checked
					checkx += xstep;
					checky += ystep;
					mapx = checkx / CELL_SIZE;
					mapy = checky / CELL_SIZE;
				}
			}
		}
		else
		{
			// cos of 90 and 270 is zero, so there is never an intersection with a vertical wall
			verdist = MAX_INT;
		}
  	
		// See which of our hits we should take into account
		// Default was horizontal, but we take vertical if that distance is shorter
		side = 0;
		if (verdist <= hordist)
		{
			hitx = mapx;
			hity = mapy;
			distance = verdist;
			side = 1;
		}

		// calculate slice height based on distance
		int sliceheight, slicestart, sliceend;
		if (distance) 
			sliceheight = SCREEN_DISTANCE / distance;
		else
			sliceheight = SCREEN_HEIGHT;

		slicestart = (SCREEN_HEIGHT - sliceheight) / 2;
		sliceend = slicestart + sliceheight;

		// Start of rendering this slice
		// Color of wall slice
		char color;
		if (side != 1)
		{
			// Front view, light colors
			switch(worldmap[hitx][hity])
			{
				case 1:  color = 15;  break;   // white
				case 2:  color = 2;   break;   // green
				case 3:  color = 5;   break;   // blue
				default: color = 11;  break;   // yellow
			}
		}
		else
		{
			// Side view, dark colors
			switch(worldmap[hitx][hity])
			{
				case 1:  color = 14;  break;   // gray
				case 2:  color = 12;  break;   // dark green
				case 3:  color = 4;   break;   // dark blue
				default: color = 10;  break;   // dark yellow
			}
		}

		// draw the pixels of the stripe as a vertical line
		draw_slice(column, slicestart, sliceend, color);
				
		// Prepare for next column
		rayangle += ANGLE_STEP;
	}
}

int main(int argc, char *argv[])
{
	while(1)
	{
	}

    return 0;
}

Note that this code doesn't perform anything useful anymore, and I took some of the calculations out, so the algorithm itself won't work either.

 

Don't know how significant this is, but I found it strange that although the error during compilation is reported in line 278, commenting out line 312 will actually make it go away...

 

Attached is a folder containing all that's needed to build this (and trigger the bug). Again, for others that would be tempted to download this: it does not contain a working program...

wolfie-error.tar.gz

Share this post


Link to post
Share on other sites

Just a guess but is that a Divide by zero error?

Share this post


Link to post
Share on other sites

Just a guess but is that a Divide by zero error?

 

Not divide by zero, that would be a runtime error. The error I get is at compilation time, where divide by zero cannot be verified yet.

Share this post


Link to post
Share on other sites

I found and fixed the compier crash for wolfie3. It turned out to be a mistake in one of the four descriptions for division. That description was allowing the use of a constant as the numerator, rather than requiring that value be stored in a register. At a later time, code which assumes the use of a register chokes when it finds a constant instead, causing a crash.

 

The error only showed up in this code because it contains lots of calculations, increasing the pressure on the compiler to make maximum use of the registers. While doing instruction selection it saw that this division form did not require a register and acted accordingly. The normal behavior is to put all constant values in registers before use. For less demanding code, that register usage would be left in place, and no error would be seen. Once I tracked it down, this was actually a pretty easy fix.

 

Before I put together any new patches, I'd like to figue out why libgcc is failing to build on mac. Mole, could you attach the build errors you are seeing? That would be really helpful. Also, if anyone else has feature suggestions or bug reports, I'd love to hear them so I can beef up the patch a little bit.

  • Like 1

Share this post


Link to post
Share on other sites

Great news, thanks!

 

Regarding libgcc: I just tried rebuilding the entire thing from scratch, and libgcc did build as expected this time. I must have been playing around with a dirty build before. My apologies for sending you on a wild goose chase...

 

Regarding new features, it would be great if the compiler could 'natively' support paged/banked memory configurations (like an AMS or 512k cart type setup). Not sure if this is a compiler feature though, it might be something that is best achieved with a separate set of tools?

Share this post


Link to post
Share on other sites

After much procrastination, I've got patches.

This is a pretty slim patch, with only a few changes. I suppose this is a good thing, since it implies the bug count is reaally low (hopefully zero, but how often does that happen?). Part of the reason for the delay was that I've been tryng to move the TI changes into GCC version 5.2. Version 4.4.0 was the most recent when I started, but there have been many improvements since then. So far I haven't been able to get a good build, but I'll keep trying.

Anyway, these are the changes this version:

Fixed bug when dividing by constant value
Improved type testing for instruction arguments
Added text to "--version" flag output to show patch version
Added changes to improve builds in an OSX environment

Yep, not a very impressive list, but each bug fixed is progress.

Here's the output showing the patch version:

[email protected]:~/dev/tios/src/temp/$ tms9900-gcc --version
tms9900-gcc (GCC) 4.4.0 20090421 (TMS9900 patch 1.12)
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

One of the problems that bugged me was that the installer script used to be hard coded to use a specific patch set. That's been changed to use the most recent patch in the current directory when the installer script is run. This should be handy for more easily using future patches. I've also addded a check to use either wget or curl, whichever is found first, to get the source packages.

The first post in this thread has been edited to include the new GCC patch. I made an archive for use under Cygwin in a Windows environment. It's too big for an attachment, so here's a link:
tms9900_cygwin.tgz

As always, if anyone finds a bug or an improvement, let me know.

  • Like 2

Share this post


Link to post
Share on other sites

Excellent news, will try this ASAP tonight when I get home from work! Thank you!

 

You might also be interested in the discussion on creating bankswitched cartridges we had a while ago here. I now have a pretty good system up and running, but if you're still looking for features to add native support for "far" function calls would surely help make this a bit more generic and perhaps even efficient.

 

Moving to gcc 5.2 would be cool.

Share this post


Link to post
Share on other sites

I found and fixed the compier crash for wolfie3. It turned out to be a mistake in one of the four descriptions for division. That description was allowing the use of a constant as the numerator, rather than requiring that value be stored in a register. At a later time, code which assumes the use of a register chokes when it finds a constant instead, causing a crash.

 

The error only showed up in this code because it contains lots of calculations, increasing the pressure on the compiler to make maximum use of the registers. While doing instruction selection it saw that this division form did not require a register and acted accordingly. The normal behavior is to put all constant values in registers before use. For less demanding code, that register usage would be left in place, and no error would be seen. Once I tracked it down, this was actually a pretty easy fix.

 

Before I put together any new patches, I'd like to figue out why libgcc is failing to build on mac. Mole, could you attach the build errors you are seeing? That would be really helpful. Also, if anyone else has feature suggestions or bug reports, I'd love to hear them so I can beef up the patch a little bit.

So, more than half a year later, I finally got around to installing the new version of the compiler. The install script still has some issues on Mac (tree and wget are not installed by default, neither are the gmp and mpfr libraries), so I broke down and installed HomeBrew to install both the two command line tools for the install script, as well as the missing libraries. Having done that, the installation works like a charm!

 

However, this new version is not able to compile Alex Kidd, I get the following error:

unrecognizable insn:
(insn 140 138 141 7 persistent/collision.c:175 (set (reg:SI 165)
        (mult:SI (reg/v:HI 118 [ map_y ])
            (const_int 170 [0xaa]))) -1 (nil))
persistent/collision.c: In function ‘collide_world’:
persistent/collision.c:498: internal compiler error: in extract_insn, at recog.c:2048
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
make: *** [persistent/collision.o] Error 1
dannys-mbp:Alex Kidd Cartridge lousbergd$ 

I haven't been able to chase down what is causing the problem in the code, the line that where the error occurs (line 175) seems innocent enough. Line 498 is simply the last line of code in the file.

int  map_x, map_y;  // Function local variables

if (coldet_map[map_y][map_x]) // Line 175, this is where the error occurs
{
  // Some code here
}

and coldet_map is defined as follows:

// globals.h
#define MAX_LEVEL_SIZE 8160
#define MAX_COLDET_SIZE (MAX_LEVEL_SIZE / 4)
extern unsigned char coldet_map[12][MAX_COLDET_SIZE / 12];


// globals.c
unsigned char coldet_map[12][MAX_COLDET_SIZE / 12];

Share this post


Link to post
Share on other sites

I realize this question isn't directly related to the GCC compiler itself, but rather Tursi's LIBTI99 implementation. Didn't seem to fit anywhere else and since other people might try to use it I thought it would be good to ask here.
The MAKEFILE in the library seems to be missing a step somewhere. The file TESTLIB already exists in the ZIP file, so it never actually gets created by the compilation process, but does get copied the first time you run make. Puzzled me at first when I made simple changes to testlib.c, and the resulting changes didn't show up when I ran Classic99 again and loaded the TESTLIB file in E/A. I ran "Make Clean," which deletes the TESTLIB file. Now the make fails to find the file to copy it, obviously because it was just deleted, but the MAKEFILE never makes it.

This bit, the one that actually compiles the testlib.c file, links, converts and copies it to the classic99 DSK1 folder doesn't function as expected.

test: library testlib.o $(OBJECT_LIST_EA5) 
	$(LD) $(OBJECT_LIST_EA5) testlib.o $(LDFLAGS_EA5) -L. -lti99 -o testlib.ea5.elf > ea5.map
	$(ELF2EA5) testlib.ea5.elf testlib.ea5.bin
	$(EA5PLIT) testlib.ea5.bin
	$(CP) TESTLI* /cygdrive/c/classic99/dsk1/

There seems to be a missing step between using EA5SPLIT and copying TESTLIB to the folder. EA5SPLIT does not create a file with this name, nor does any of the previous steps. I've tried renaming testlib.ea5.bin to TESTLIB and copying it manually but Editor Assembler will not load this file. I/O Error 2 - Invalid file type or something like that. I compared this with the HELLO makefile that comes with Insomnia's basic setup and it does things in a different way, making a cart image instead of a ea5 file, so no help there.

Thanks for any assistance here.

Share this post


Link to post
Share on other sites

A new thread for LIBTI99 would probably be better than confusing the GCC thread, since it's someone else's project... but I haven't used TESTLIB for a long time. It's not a comprehensive test by any means, just something I threw together to ensure it worked at all. (For instance, most people aren't going to have Classic99 in the same place as me...)

 

That said, I'm not sure what error you are getting. When I do a make clean, it deletes TESTLIB, and make then recreates it as expected. Perhaps you have a different version of EA5SPLIT than I do... I've no idea what I'm running there. :) What does your version actually do with that command line? Mine strips the .ea5.bin and creates the TESTLIB file based on the input name.

 

/cygdrive/c/cygwin/home/tursi/bin/tms9900-gcc -c testlib.c -O2 -std=c99 -s --save-temp -I./ -fno-builtin -o testlib.o
/cygdrive/c/cygwin/home/tursi/bin/tms9900-as crt0_ea5.asm -o crt0_ea5.o
/cygdrive/c/cygwin/home/tursi/bin/tms9900-ld crt0_ea5.o  testlib.o --section-start .text=a000 --section-start .data=2080 -M -L. -lti99 -o testlib.ea5.elf > ea5.map
/cygdrive/c/cygwin/home/tursi/elf2ea5 testlib.ea5.elf testlib.ea5.bin
/cygdrive/c/cygwin/home/tursi/ea5split/ea5split testlib.ea5.bin
/usr/bin/cp TESTLI* /cygdrive/c/classic99/dsk1/

Share this post


Link to post
Share on other sites

Would the problem have anything to do with the fact that the makefile section quoted for “test” nowhere mentions “EA5SPLIT”? The name I see is “EA5PLIT”—no ‘S’.

 

...lee

Share this post


Link to post
Share on other sites

That said, I'm not sure what error you are getting. When I do a make clean, it deletes TESTLIB, and make then recreates it as expected. Perhaps you have a different version of EA5SPLIT than I do... I've no idea what I'm running there. :) What does your version actually do with that command line? Mine strips the .ea5.bin and creates the TESTLIB file based on the input name.

^--- This. Apparently, I had a bum version of EA5SPLIT that wasn't creating any output, nor throwing an error. I downloaded the version here and it worked as expected. So, not really a GCC or TI99LIB problem. Goes to show that man is only as good as his tools.

 

@Lee Stuart: Fortuantely, that exact typo appears everywhere it needs to appear in the Makefile to prevent it from being a problem. :grin:

 

Thanks for the help though, maybe I can make something fun now.

  • Like 2

Share this post


Link to post
Share on other sites

I'm getting relocation errors like this one:

(.text+0x36b): relocation truncated to fit: R_TMS9900_PC8 against `.text'

When creating an array of INTs like this one in the global scope

int animation[] = {0,1,2,1,999,3,1,999,4,5,6,5,999};

then referencing them in the main function. The compiler throws an error for each instance of the animation[] array it encounters.

 

I re-ran the installer script just to make sure it was fully patched.
I don't HAVE to put the array in the global scope, but just thought I'd mention the problem to see if it was expected behavior.

 

EDIT: Actually I tried moving it into main and I still get errors when attempting to use it. Strange.

Edited by mindlord

Share this post


Link to post
Share on other sites

 

I'm getting relocation errors like this one:

(.text+0x36b): relocation truncated to fit: R_TMS9900_PC8 against `.text'

 

Hey everyone, life has been eating up all my time, so I haven't done much TI stuff lately.

 

At any rate, this is a bug in the compiler.

 

What this error is saying is that GCC tried to output a conditional statement using an instruction like "jeq $+X". The assembler detected that X was too large to fit in the instruction and reported an error. In all likelihood, the problem is only loosely related to the animation array, which may explain why you are still seeing the problem after moving it around.

 

This kind of problem is caused by GCC incorrectly calculating the length of a code branch. I thought I fixed all these types of errors, but apparently there is more work to be done.

 

if you could post your code, or some smaller piece which reproduces the error, I should be able to fix this relatively quickly.

 

Mole, your bug is way overdue for review, and I will look at that one too.

 

If anyone else has seen compiler bugs or other annoyances let me know.

  • Like 3

Share this post


Link to post
Share on other sites

Great to see you again, Insomnia, and looking forward to any fixes. I haven't run into anything too serious, although there was some long int versus int oddness when I worked on the Text Elite port. (When I went to all 16-bit ints it all worked). I don't have a test case because I was never sure if the long int code was considered finished.

Share this post


Link to post
Share on other sites

Great to see you around Insomnia! It's going to be hard for me to put together a short piece of code that triggers the bug I was talking about a couple of weeks ago. It only happens when the code base gets rather large. Let me know if it would help if I shared the entire code base with you.

Share this post


Link to post
Share on other sites

Indeed, after shuffling out some functions into separate files, my bug went away too, but I suspect I can recreate it.

EDIT: Try as I might, I can't reproduce this. I might be able to get the .a files from the old build.

Edited by mindlord

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