Tuesday, July 28, 2015

Some answers to old problems and why development shortcuts can be bad

This is a pretty long post, so for that I apologize, but two big topics to cover.

If you've been following this blog, in the last post I indicated that I was having a problem loading the Fortran standard library.  The FORLIB.RL seemed to be missing from my system.  I'm happy to report that I've gotten past this issue.  I found a floppy disk image that had a complete OS/8 Fortran IV system, I copied the FORLIB.RL to my main partition, and it works.

Interestingly, it seems to work without me having to load it.  As you may recall, to load all the modules for an application, you use the LOAD utility and specify all the modules, what order they are loaded (for purposes of overlaying code), and what the main program file name will be.  In reading through this section in the Handbook, I didn't see anything about loading the standard library, so I assumed that it just happened automatically.  Then, as I discussed in yesterday's blog, I ran into problems and noticed that in their sample LOAD session, they actually loaded the standard library explicitly but using a different file name (LIB.RL instead of FORLIB.RL).  It gives no explanation why it does this, so then I assumed that you had to explicitly load the standard library.

So I wrote a little test program and tried to load the FORLIB.RL in LOAD, but kept getting a BAD INPUT FILE error.  But then I noticed something: When I failed to load in the standard library, my little test program still ran correctly.  Apparently it does load in the standard library automatically if it finds FORLIB.RL.  This puzzled me because I wondered why would they load it in manually in the sample LOAD session, and why was it giving me the BAD INPUT FILE error?

After some thought, I think I have at least part of an answer.  I have no clue about the BAD INPUT FILE, but I think I understand why they were loading it in manually in LOAD.  This utility does two things.  Most obviously it allows the developer to load all the modules.  But it also allows for modules to be defined as overlays.  Such a module would not be loaded into memory when the program first starts, but as the program executes it can be swapped into memory as needed.  This allows a Fortran program to be as large as 300k even though there's only a maximum of 32k memory.  The standard library is quite large, so I assume by loading the FORLIB.RL manually, the sample session was showing how to turn it into an overlay module so that it's not eating up memory for the whole life of the program.  I'm still not sure why it was named LIB.RL though, but since I'm not really wanting to concern myself with overlays, I'm happy to ignore this issue.

But in looking at this issue, I did actually end up resolving an earlier issue concerning subroutines and functions.  I talk about the issue in two of my prior blogs: Random Linking Woes and Still learning, still haven't gotten anywhere.  Basically to do a subroutine or function, each has to be defined as a separate module.  But I couldn't figure out how to load these modules.

The problem really comes from the fact that I was using the COMPILE and EXECUTE commands.  These are nice commands sort of built in to OS/8.  They allow you to build and execute simple programs without knowing what you're doing.  In essence, they're development shortcuts.  Now I'm not opposed to such shortcuts, but as a professional developer now for more than two decades, I've always followed the rule that you should only use such shortcuts when you know what they're doing.  If you don't, then when things screw up as they inevitably do, you don't know how to fix it.  Unfortunately I didn't follow that rule with this project, so when I ran into issues with subroutines, I didn't really know how to get around it.

But this issue forced me to really break down and understand in more depth about how to build a Fortran app, and that's led me back to the solution for subroutines and functions.  As I mentioned in yesterday's blog, there are 3 steps to building an application:

  1. Compile - The F4 utility
  2. Loading - The LOAD utility
  3. Execution - The FRTS utility
When you use the COMPILE command, it does the first step, but not the second or third.  But the EXECUTE command does all three, and if successful, your app just "magically" runs without your really being aware of the steps involved.  Unfortunately, EXECUTE doesn't seem to be a very intelligent command, so it doesn't seem to really know how to load separate modules.  So it's perfectly good for simple applications, but not really useful for anything of any real size or complexity.

So let's assume you have a program with a MAIN.FT, a subroutine module SUB1.FT, and a function FUNC1.FT.  We're going to assume that this will all be part of the main application segment; we'll keep things simple and not use any overlays.  When building a Fortran application, you first use the F4 utility to build each module, like so:

.R F4
*PROG1<PROG1      <-- In OS/8, extensions are assumed so need them only if not standard
.R F4
*SUB1<SUB1
.R F4
*FUNC1<FUNC1

This produces an RL for each module.  The next step is to load all the RL files:

.R LOAD
*PROG1<PROG1
*<SUB1,FUNC1
*$             <-- This is the ALTMODE key, which echoes as $ and is ESC in simh
                                              Use TECO and you will become very familiar with this.

While I did the load in two lines above, it would have been equally valid to do them in one line with commas, or even in three separate lines.  It doesn't make a difference.  

Finally, you can execute PROG1.LD by:

.R FRTS
*PROG1
*$

And there you have it, all the steps to build a Fortran IV program on OS/8 complete with subroutines, functions, and whatever modules you want.  To build in overlay support, as far as I know, all you have to do is do some more steps in LOAD.  At that point, you could write a 300k Fotran program.  But that's really beyond the scope of this blog - and of this project.

As a quick final note, the one issue I see with the above is that almost all of these steps has to be repeated every time you build the application.  The only part you can skip is that you don't have to recompile a module if it hasn't changed, but otherwise everything above has to be done each time.  Unfortunately, as far as I know, OS/8 doesn't have any way to automate this.  

No comments: