Jump to content
IGNORED

C Compiler


Recommended Posts

I've been putting together an RC2014 based TMS9995 system and whilst waiting for a 12Mhz can oscillator to turn up I decided to do something about tools.

 

I've retargetted Ragge's ANSI pcc to the TMS9995, including keeping the workspace fixed (not using BLWP chains down the stack), along with the ex MWC assembler kit I use for other things like Z8 and 1802, and my linker.

 

It's good enough at this point to build all the Fuzix codebase without exploding or generating invalid assembler and it's correct enough I've gott Fuzix running to the point of starting up, finding and loading init from the file systeem and making a system call before crashing on the syscall return path in some of my asm glue.

 

https://github.com/EtchedPixels/pcc-tms9995-support

 

has the support files and explains how to get and build the compiler phase, assembler and linker.

 

At this point it I imagine there are still going to be a few bugs to find and I have one known bug with varargs and the register argument passing scheme to tidy up. It's a nice clean and small compiler kit so hopefully any bugs are easy to swat.

 

Whilst it's all set up to build for Linux there isn't anything in there that ought to be non-portable code, so it ought to build on a Mac, and Windows has grown Linux emulation.

 

It in theory also knows how to build 9900 code and to generate TI99/4A EA5 files (euwch...) but I've only tested that so far on building a boot loader for the Geneve to replace MDOS.

 

Alan

 

 

 

  • Like 6
Link to comment
Share on other sites

There's not really a huge amount to it. It's a CPU card with a bit of glue (that I hope I got right) to generate Z80 style cycles on the bus for memory (and an I/O window at 0xFExx). Most of the design is from Chris Swan's wirewrap board which is I think mostly from one of the others. I've routed the CRU out as well to play with a TMS9902.

 

The rest is just standard RC2014 cards - so when the can oscillator turns up and if it works  (or after a bit of rewiring) it should just run with any old RC2014 cards except the Zilog Z80 specific parts, so the 512K RAM/ROM card, the TMS9918,  PPIDE etc. Not sure if the CF card will work, it's unbuffered and NMOS to unbuffered CF is a bit iffy in my experience with other processors.

 

Edited by EtchedPixels
typo
  • Like 3
Link to comment
Share on other sites

5 hours ago, EtchedPixels said:

Not sure if the CF card will work, it's unbuffered and NMOS to unbuffered CF is a bit iffy in my experience with other processors.

In the TMS9995 Mini-Cortex design, there's a diode in the Vcc to the CF card and a couple of signal pullup resistors that help to match the signal logic level voltages.

  • Like 1
Link to comment
Share on other sites

9 hours ago, TheMole said:

This is really cool, is there any documentation on how you can control the linker?

 

For example, can we output a raw binary format, position the .text, .bss, .data formats freely within the binary? That way we can also easily create cart images... :)

 

I guess "ld.c" ;)

 

The main linker options are

-b: produce a binary image

-o: set the output name

-m: map file (symbol table dump)

-A: align segments (so -A2 is a good idea on a TMS)

-B: set bss address (otherwise follows data)

-C: set code address

-D: set data address (otherwise follows code)

 

The cc front end tries to do the right things, so if you run

cc9995  -tti994a blah.c -o blah

 

It will link it at 0xA000 with a crt0 that hopefully makes sense and puts the stack in 0x2000-0x3FFF and then turns it into an EA5 BLAH0 BLAH1 - although I've not a chance to actually do anything on a TI and try it, I know EA5's seem to work because of trying to create a Fuzix loader for the Geneve.

 

The linker has no understanding of "link this at address A and put it at B". That could be added, but given it's a binary image it is easier just to have any post-processing tools load the image and chop it around as needed (eg to pack it into cartridge banks for a crt0 to load into RAM)

 

The supplied C library needs a few things plugged into the bottom to make it more interesting - some kind of console input/output and optionally some basic equivalent of a few Unix low level I/O calls to do disk stuff and map it as best as possible from the Lovecraftian horrors of the TI99/4A+ PAB and DSRLINK into simple I/O calls and then you get stdio on top.

 

If there are other groups of settings that make sense / tool bits I can add them to cc9995 - eg a layout for cartridges.

Edited by EtchedPixels
Link to comment
Share on other sites

Thank you for the quick reply!

 

12 hours ago, EtchedPixels said:

The linker has no understanding of "link this at address A and put it at B". That could be added, but given it's a binary image it is easier just to have any post-processing tools load the image and chop it around as needed (eg to pack it into cartridge banks for a crt0 to load into RAM)

 

 

My personal use-case is running code and loading data directly from banks on the cartridge. I'm using the following linker script with gcc:

/* Linker script to create TI99/4A cartridges */

/* Output straight to a flat binary format (i.e. not ELF) */
OUTPUT_FORMAT(binary)
OUTPUT(cartridge.bin)

/* TI memory layout */
MEMORY
{
	cart_rom (rx) : ORIGIN = 0x6000, LENGTH = 0x2000 /* cartridge ROM, read-only */
	lower_exp (wx) : ORIGIN = 0x2080, LENGTH = 0x1f80 /* 8k - 128 bytes       */
	higher_exp (wx) : ORIGIN = 0xa000, LENGTH = 0x6000
	scratchpad (wx) : ORIGIN = 0x8320, LENGTH = 0x00e0 /* 32b is for workspace */
}

/* Where we put sections */
SECTIONS
{
	. = 0x6000;
	.header 	: { bank0/cart_header.o(.text) } >cart_rom											/* Bank 0: Cart ROM header */
	_persistent_src = 0x601a;
	.persistent	: AT ( _persistent_src ) { _persistent = . ; persistent/*.o(.text); _persistent_end = . ;} >lower_exp	/* Bank 0: Code that never can get bankswitched out */
	.bank0 (LOADADDR(.persistent) + SIZEOF( .persistent )) : { _text = . ; bank0/*.o(.text); _text_end = . ;}	/* Bank 0: code */
	.bank1 0x6000 : AT ( 0x8000 ) { bank1/*.o(.text); }														/* Bank 1: code */
	.bank2 0x6000 : AT ( 0xa000 ) { bank2/*.o(.text); }														/* Bank 2: code */
	.data  0xa000 : AT ( 0xc000 ) { _data = . ; persistent/*.o( .data ) bank0/*.o( .data ) bank1/*.o( .data ) bank2/*.o( .data ); _data_end = . ;}							/* Bank 3: data */
	.bss (_data_end) : { _bss = . ; persistent/*.o( .bss ) bank0/*.o( .bss ) bank1/*.o( .bss ) bank2/*.o( .bss ) ; _bss_end = . ;}
	.fill  0xdfff : AT ( 0xdfff) { BYTE(0x00); }
}

/* Ensure banks don't call each other's functions directly */
NOCROSSREFS( .bank0 .bank1 .bank2 .bank3)

 

This works well for my purpose, but our gcc port is getting really hard to build with modern clang or gcc compilers these days, and I continue to have issues with strange behaviors and compiler crashes in more complex projects (I know others have not had this issue, so it might just be me). But having an alternative to gcc would be awesome!

 

Having said that, I'm already in awe of the fact that we have two cross-compiler options for our platform these days.

Edited by TheMole
  • Like 3
Link to comment
Share on other sites

  • 2 months later...

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