Thursday, December 24, 2009

There's been more planning and thinking than actual work lately. I've reached a point where I'm not sure what to work on next. I think the next items are going to be heap managent or process management, file interface or something like that.

I've changed the ABI to make R13, R14 and R15 non-volatile. This was done to make blwp and xop reasonable to use. I was working on the system call interface, and was annoyed by the amount of work needed to make the system work if those registers were kept as volatile. R12 has been made volatile to support easy CRU operation. Originally, that was a non-volatile register. using CRU instrustions incurred a similar level of annoyance. So now the register usage looks like this: R0-R8,R12 are volatile, R10,R11, R13-R15 are non-volatile. Basically, all special-purpose registers are non-volatile except R12. R9 has no special purpose, but I figured I should keep it non-volatile anyways.

As mentioned above, I've added a system call interface to the project. It doesn't actually do anything useful, but it works. I keep thinking that if I restrict the *print* calls to the system call interface, I can save 120 bytes. I'll make a final decision on this later.

I'm currently looking at heap management algorithms, so I guess that will be next.

Just for the heck of it, I've been thinking about a wolf-3d clone for the TI. I'm not sure if I'll actually do it, since I've got a lot going on right now, but it willl give me a better idea of what real-world programs will need.

I've also been thinking about writing a compiler best-practices guide as I continue working. I keep going back to Tursi's GCC port and his misguided insistance on a zero register, At some point I would like a C compliler, and I would like it to be good.

Monday, December 14, 2009

Not a whole lot of work done, but I have been working on documentation lately. I've put together some notes on dynamically-loaded libraries, and system calls in general. I think it could work, and thinking down these lines is helpful for later.

I've also put together some notes for my modifications to the GAS assembler. I was thinking about the fact that I don't have an Editor/Assembler manual, and that it would probably help to ask around to get the missing pieces. In order for someone else to see my gaps, I need to document what I have so far.
The assembler documentation is very sparse, but I think it's a decent start.

While digging around for more info, I found the "nop" and "rt" pseudo-ops in example code in a couple places, so that seems legitimate. "Nop" is encoded as "jmp 0" and "rt" as "b *r11". While I was in there, I added "or" and "orb" as aliases for "soc" and "socb" since I can't ever remember the real instructions.

I had problems adding these instructions, since I made a dumb mistake in the parser. I was assuming there was an argument, and skipping the intervening space. This resulted in skipping the null terminator for the line, and getting "junk at end of line" errors. This has been fixed.

Saturday, December 12, 2009

So last night I finally had time to finish the decimal printing routines. Along the way I found I had really misunderstood the function for the DIV instruction. I had thought that the OV flag would be set when the resulting quotient was zero. Looking back on the references, I can't see where I ever got that idea.

The *printf* routines take 446 bytes, not too bad, but I would have liked it to be smaller. Also, the stdio.asm file is a mess. It works, but there is little organization, and the layout is poor, with unnecessary B instructions.

I should start thinking about making a user-callable library for syscalls or somethihng. I don't want to go too far down the road of assuming a single-user, single-tasking environment. That works for now, but will all need to be ripped up later.

Honestly, a good chunk of the code (126 bytes) is encoding flags to discriminate the *print* forms.

Saturday, November 21, 2009

I found a bug in the compiler. There is an overflow problem in the displacement calculation for jmp instructions. I found a case where I have a "jmp -310" which is not caught by the linker. This case compiles to 1064 -> "jmp 200".

6484: 10 64 jmp 200 # jmp print_final
Destination: 0000634e :

So this should be jmp -0x136 (-310) which is too big...
-0x136/2 = -0x9B = -155 =0xFF65

This seems to be fixed by making changs to binutils/bfc/elf32-tms99900.c. I'm now using "complain_overflow_signed" for these relocations.

Friday, November 20, 2009

It's been a while since I've had a chance to work on this project, so I took a while to get up to speed on wheere I left things last. This log has been a huge help and it's ben good to go back through it. One thing that's been missing in earlier updates has been the lack of details. These help better describe the day-to-day development.

I decided to basially rework a big chunk of stdio.asm, specifically the *print*_* routines. The original code was compact, but inflexible. and making extensions for formatted output was completely screwed up. Adding 32-bit support was impossible as well.

The hex routines seemed a good place to start. 32-bit hex conversion is now complete, and a new strlen routine is working. I've started putting together the framework for formatted output (for exmaple "%08X" or "%-12d"). It's incomplete and sketcky right now, but it should be ok.

I think there may still a problem with signed 32-bit support for the math.asm routines, but I haven't looked into it yet. Signed division is a big question, it's not obvious how that should work.

Sunday, September 20, 2009

I've started working on a 32-bit math library. I wanted to get an "uptime" command working, but to do this, I needed this library. I've done some tests with the DIV command, and confirmed that it will cause an overflow if the resulting value will not fit in a 16-bit value.

I've got 32-bit addition, subtraction, compare, right and left shifts. I still need to get division working. I think the existing 16x16 MPY command will be OK, but as I type this I can see cases where a 32x16 routine would be handy. I can't see any reason for a 32x32 routine, since all results will exceed 32 bits. If some wierd case pops up which needs this, I can do this work later.

Saturday, September 19, 2009

So I figured out what was causing the color problem. It turns out that when the ISR hits, it reads the VDP status register. Doing this cancels any command that may be in progress (in this case, set write address). So what happpens is that at the start of a screen write, instead of resetting the write pointer, writing continues from the last frame, overwritting the color tables and other stuff in VDP memory.

Disabling interrupts while VDP commands are being written seems to have fixed the problem.

Thursday, September 17, 2009

I'm not sure what was going on, but the loss of keys is tied to the size of the emulator window. At small sizes, no keys are lost. At fullscreen, lots of keys get lost.

I've added code to prevent repeated keys due to held keys. Works nicely.

The color problem has not been fixed...

It looks like its time to start working on a shell.

Tuesday, September 15, 2009

So, I've got the keypress buffer working, it's a 16-deep circular queue. Seems to work OK, but the key scanning is really slow, I miss lots of keys typing at a normal speed. Even after scanning at 60 Hz, I miss events. There must be some kinda design flaw I'm not seeing, since I can't be that slow.

Another point, I don't have a good way to separate keypresses, so there's just a series of repeated scan codes if keys are held down too long.

Oh crap, I just thought of something. The scanning routine takes a while, and the ISR may be restarting before the scan is complete. I really hope that's not the case.

Crap, that's the problem. I ran a test by cutting down the scan to only two columns. In that case, all keys are seen. So I need to redo the scanner to be faster somehow.

One other annoyance. After a few seconds, the screen colors get corrupted. Ocassionally, a sprite will be turned on, I suspect a buffer overflow somewhere.

Monday, September 14, 2009

So I've got a working interrupt handler, keyed off the VDP. This generates 60 IRQs per second. In the ISR, a clock counter is updated and the keyboard scanned every 4 IRQs (15 times per second, or 66 msec).

I'm working on a queue to store scanned keys. This is simple enough, but I'm trying to squeeze out every drop of speed and size I can get, so this may take a while.

Initial testing shows that I can refresh the screen at about 30 FPS, which is pretty good.

I'm looking into the idea of using the 9901 to scan the keyboard. The problem is that it looks like I would need to increase the IRQ rate to cycle through the keyboard columns. I wonder if I can use hardware to cycle columns for me.

Saturday, September 12, 2009

The caps lock seems to be caused by a problem with MESS. I've dug into it a bit, but I'm not really interested in working on that right now. Too similar to what I'm doing at work. I'll just live with the broken caps for now.

Wednesday, September 9, 2009

The keyboard scanner can now display human-readable, ASCII. I'm ignoring the lack of caps lock for now since I don't use it anyway.

Tuesday, September 8, 2009

I've got a working keyboard scanning routine working, but there are a few drawbacks. The alpha-lock key cannot be scanned, and I don't have a translation to ASCII working yet. There's the start of some code to do the ASCII conversion, but it's got some work left to do. The lack of alpha-lock troubles me more though. Maybe I need to check the MESS code to see how that's implemented. Maybe it's different than actual hardware.

Saturday, September 5, 2009

I've noticed that there is a bug in the memcpy routine, here's an example of the test I ran. The first test varies the copy length, the second the destination address

I expect to see output like this:

I actually see this:
(empty) (empty)

I did another test, and using byte-copies with the screen buffer slows the system back down, losing us our 20% bump. So I need to get memcpy (and memset, which uses a similar method) working.

word memcpy test 2, don't append "\n"

So it looks like the lowest-order bit is being ignored for word copies.

After fixing memcpy, test runs for 0-A00 time
TIME Description
83.64 first pass, working memcpy

Friday, September 4, 2009

Been a while since I updated this...
The print routines are working fine now, and I can print strings, signed or unsigned decimal or hex to the screen or a buffer. Unfortunately, I don't have format specifiers, so everything prints as %X or %d, but I can't do %8X, or even %08X

I started working on a keyboard driver, and have verified that I can read the appropriate CRU bits. Looks promising. Even though there is a keyboard scanning routine in the firmware, I don't want to use that unless absolutely necessary.

During keyboard testing, I noticed just how slow the screen_write function is. Since I intend to do a lot of printing, I need this to be as fast as possible. Or at least reasonably quick.

To that end, I'm running a speed test here. This is the time, in seconds it takes to count up to 0xA00. Time is taken on a non-maximied screen, started when "2" is pressed on the TI program selection screen.

TIME Description
106.17 Baseline
57.23 No copy from VDP for screen scroll
83.13 First attempt with screen buffer, non-working

The savings seems to be in the scrolling section. By using word copies instead of byte copies, I seem to gain a bit of speed. Unfortunately, what was a reasonably well laid out bit of code will be mangled by maintainng the screen buffer. Oh well. I'd rather have the 20% speed-up.

Monday, August 24, 2009

The bug in the compiler has been fixed. It's a one-line fix to tms9900_parse_name, but at least I can use arbitrary function names.

Sunday, August 23, 2009

I've got stdio.asm to the point where it's pretty useful, I've got a hex and decimal print-to screen and print-to-buffer routines working. Remaining routines are print signed decimal, 32-bit support and formatted output (ex: 0x%04X)

I found an annoying bug in the compiler, it seems to do lazy symbol matching when processing expressions. a line like "bl @sprintf" seems to be processed as if it were "bl @sp", resuling in a "register value used as expression" error.

Monday, August 17, 2009

I've just transitioned everything over to the new Compaq laptop. Everything seems to be good, and the emulator starts up much faster.

I'm working on stdio.asm, it will hold printf and sprintf. Right now, it's just a placeholder.

Saturday, August 15, 2009

I continue to fail to update this log at a regular rate. Grr..

I've been focusing on getting printing functions working. This will help debugging and future testing. In fact, these functions were used to help debug themselves. Neat!

I want to get a mostly-complete printf working, and I've been getting the pieces together to make that happen. I think I'll stop with printf, and not implement alternate printing functions like puts. Although, sprintf would be very handy.

Sunday, August 2, 2009

After a lot of undocumented hassle, I've got the first working semi-useful cartrige image. It puts the screen in graphics mode 1 and displays an ASCII chart. As part of this, I have a simple tool to generate the lookup table used for the font.

I need to start thinking about stacks and heaps.

Wednesday, July 22, 2009

I've been having problems with the MESS emulator, so I decided to go back to the known-good cartridge images. The plan was to decompile the image, then compile the assembly output and compare the two images. I'm glad I did that since I found a problem with class VII instructions. I was adding extra arguments in some cases and not using trailing immediate 16-bit words on others. So now there are three variant of class VII instructions, and everyone's happy.

Thursday, July 9, 2009

I've been putting distance between myself and GCC for now. Mainly because I'm not sure how useful it would be at this point. Also because I want to make some solid progress to keep myself motivated. GCC will produce inefficient code to start with, and will require many optimization rounds. I need to become more familiar with TMS9900 assembly in order to do that optimization. I would also like to get a working foundation going sooner, even if its written in assembly.

I've been spending a lot of time at work lately spelunking through code, and I'm not too excited to do some more when I get home. Besides, there is a lot of stuff to get working that I can use the assembler for. Also I need to exercise GAS some to confirm that it works well enough to trust it fully. I think it should be fine, but you never know...

There is now a tool ELF2CART which will extract the .text section from a TI ELF file. This is handy for stripping the ELF headers and unneeded sections for use in a TI cart. Seems to work fine.

At this point, I need to get TI init code working, confirm that the jump instructions work, and get some basic output on the screen.

Tuesday, June 23, 2009

So I've decided to give GCC a shot. I'm not entirely sure this is a good idea, but I keep coming back to it. I'm also going to try keeping this log up by doing the writeup before doing actual work since I'm usually pooped out at the end of a work session.

Saturday, June 20, 2009

The linker is now done. I'm pretty sure the toolchain is done too, with the exception of the C compiler. Since I'm gonna have to squeeze the hell out the code to make a kernel fit on the TI, I'll probably need to write everything in assembly anyway.

Sunday, June 7, 2009

It's apparently ben a while since I updated this log. Oops.

I've been working in the project pretty much every day, but sometimes only for an hour or two.

Anyway, I've made a lot of progress. The assembler is done, and seems to work nicely. The binutils functions are done and working too.

I'm restarting work on the linker. This was stopped earlier because I got stuck and frustrated. My first attempt crashed pathetically, and the second failed with an "internal linker script syntax error".

Saturday, May 2, 2009

So I figured I should start a log of what's been going on here. I've thought about starting a web page about all this, but I'm not entirely sure about that yet.

So far, I have a working disassembler, a lot of research on the TI, and I am starting on a port of GCC to the TMS9900 processor. The disassembler is written in perl, and doesn't know about the object format. It just converts a byte stream into assembly. It is up to the user to figure out what is code and what is data.

The plan right now is to use the ELF object format instead of the DX80 format from TI. This is mostly due to the number of tools which can work with the ELF format. After a while I will probably make a DX80 format for GCC.

I'm torn on the object format choice. Mainly because I don't want to throw away all the old TI stuff. Unfortunately, the old software will assume it has all hardware resources at its disposal, and I won't have any way to contain it.

I've recently got the GAS port to assemble Type I instructions (simple ALU instructions), as long as they do not use constants.