July 31, 2025

Sun 3 bootrom souce - to ANSI or not to ANSI?

I thought about this long and hard and decided that it by far would be the best thing to convert this code to ANSI C.

My general approach (so far) is to mess with the code as little as possible, but I am not going to make this a strict rule.

I will need to add "protos.h" to the collection of header files in the "h" directory. Then I will need to add an include line for this to each soure file.

The code also has a half hearted effort towards prototypes in the form of statements like this:

extern /*struct pgmapent*/ getpgmap();  /* (addr) */
extern                     setpgmap();  /* (addr, entry) */
The above are from sun3/cpu.map.h I will place true ansi prototype in protos.h and then put these sorts of things under a NOTANSI conditional, which I simply won't define. All of this in the spirit of not deleting anything, both as a nod towards history, but also in case I make a mistake and need to look back at the original code.

And I will need to hand edit each and every C source file changing function definitions from the traditional style to the ANSI style. Sometimes I will make a function return explicitly "void" where it was previously simply defaulting to "int". Also when I notice that a function is used only within the file it is defined in, I will add a "static" declaration.

This is the plan, we will see how it plays out. Some routines are defined in assembly language code and it will be useful to set up ANSI C prototypes for these.

Function pointers

Back in the day, function pointers were just function pointers, all the same. In the new world of ANSI C, a function pointer has specific arguments and a return type. This raises issues.

We could "fix" things by liberal use of casting, but this is a case where it would be better (and cleaner) to just do the right thing. Doing the right thing involves looking deeper into the code than the usual "code monkey" type work that a lot of this entails.

A concrete example turns up in sys/commands.c where a pointer in a structure gets used. We see this on line 937:

(*gp->g_vector_cmd)((long)calladx, gp->g_lineptr);
Here "gp" points to a structure of global variables. A nice idea to bundle them all together like this in my opinion. The value gets set in reset.c by this code:
                extern  void  vector_default();
                gp->g_vector_cmd = vector_default;
So, where is vector default define? In sys/commands.c as it turns out. Our first task is to edit commands.c making the function declaration ansi, then we can add a prototype to protos.h. We begin with:
void
vector_default(addr, string)
        char *addr;
        char *string;
{
And end up with:
void
vector_default ( char *addr, char *string )
No special magic there. Then in "h/globram.h" we make this change:
    // void         (*g_vector_cmd)(); /* Addr of vector cmd */
    void            (*g_vector_cmd)( char *, char *); /* Addr of vector cmd */
I'll note that there are many other function pointers in globram.h that will need attention.
We also need to change the case in the call on line 937 in commands.c
		// (*gp->g_vector_cmd)((long)calladx, gp->g_lineptr);
		(*gp->g_vector_cmd)((char *)calladx, gp->g_lineptr);
The bootrom code pretty much randomly uses either int, long, or "char *" to hold addresses. Something that could be cleaned up, but it would be a lot of work, with little reward.

It isn't clear to me why a function pointer is used here at all. The value is never changed. Perhaps the sun programmers had ideas about things that never developed, or just made a habit of doing things in this way if they thought they might have more general urges someday. The address of this pointer is made public in the table generated in romvec.s, so this could be patched by the "user", but I find this a very unlikely scenario. Probably this was used in ways that I cannot imagine.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org