@(#)building_vxworks_rom.txt	1.1
  How To Build One Big Monolithic Vxworks Embedded Kernel And Put It
  Into Rom So That Your Front End Doesn'T Really Require The Network.

			  by Dennis Nicklaus
			   December 10, 1998
			    For Tornado 1 only!!!!!!!!!!!!


This is a little instruction set that will show you how to build one
big object file which includes the VxWorks kernel and your application code,
so that you only need to download one file. Furthermore, and more importantly,
this shows you how to build this combined VxWorks and applications object file 
and install it in FLASH (non-volatile memory).  Once you have installed this
combined object file in Flash memory, you will boot the PPC directly out of that
Flash file and not need to download your vxWorks kernel or application objects
from over the net.  Theoretically, you can thus immediately begin your front
end controlling application without being connected to the Net, or if the net
is temporarily down and/or unavailable. Of course, most of the ACNET controls
utility depends on having a live network, but if you have local finite state
machines or control loops that can work on their own, this lets you start them
without the network.


These instructions are valid only for Power PCs, the Motorola 2300 and
2600 series, as far as I know.

You probably don't want to go through this until your application code is
pretty mature.

			 STEP 1. PREPARATION

Let your fingernails grow for a few days. You will need them
for moving the J15 Jumper header back and forth when you have to revert
to PPCBug to reload vxworks after you screw up your FLASH.

			Step 2. MAKE A BUNDLE

Link all of your applications into one file.  This isn't absolutely
necessary, as you can use as many object files as you want to. But
since most people are in the habit of having one object file for their
application that they download into vxWorks, I'll assume you want to
do this step. The rest of these instructions assume that this file is
called
		myapp.o


		Step 3. HOW THE PPC ROM IS ORGANIZED

The PPC MV2303 and MV2603s have two banks of NV memory, A and B.  They
aren't technically ROM because you can easily write (reprogram) to
them.

Bank B is 1 MB of socketed ROM.  You put the J15 jumper header over
pins 2-3 to make the PPC boot from Bank B.  Out of the box, your PPC
ought to have PPCBug installed in Bank B.  PPCBug is a small little
executive kernel that you have to use in order to program the other
bank of FLASH memory. You can reprogram the Bank B ROM, but you should NOT.

You want to leave PPCBug in bank B, and load vxWorks into bank A.
Bank A is 2MB or 4MB of soldered-in FLASH memory.  This is where
you'll load the vxworks kernel.  There are instructions available
elsewhere for the initial board setup and programming of Bank A from
Bank B PPCBug. Those instructions are out of the scope of this
document.  But briefly, if you have all the other set-up done
(internet address, etc.)  and you are booted from Bank B, you need the
following niop and pflash commands to download a very simple VxWorks
boot kernel:

  PPC1-Bug>niop
  Controller LUN =00?
  Device LUN     =00?
  Get/Put        =G?
  File Name      =? mv2303/boot.bin
  Memory Address =00004000? 
  Length         =00000000?
  Byte Offset    =00000000?
 
  Bytes Received =&333696, Bytes Loaded =&333696
  Bytes/Second   =&166848, Elapsed Time =2 Second(s)

  PPC1-Bug>pflash 4000:fff00 ff000100
  Program FLASH Memory (Y/N)? y

	 Step 4. LEARN TO PROGRAM THE BANK A FLASH YOURSELF

You don't need to use PPCBug to program bank A Flash memory. It is
actually pretty simple.  Once put into "read mode", you can pretty
much do random-access reads from FLASH.  However, a special Flash Read
function is provided.  Before you can write to Flash, you must erase
it.  Erasing FLASH is only done on a "per-block" basis --- that is,
you erase it a whole block at a time.  There is a special Flash Erase
function.  Once erased, again, you can pretty much do random-access
writes, but there is a special Flash write function which it is best
to use.  The read and write functions take extra care to make sure
that non-word boundary starting addresses and non-full-word lengths
are properly taken care of.  My little tests (e.g. with the vxWorks
shell "d" and "m" commands), didn't show me much need for those
provisions, but I guess I would still suggest using the special Flash
read and write functions just to be sure.

The three functions are
	FlashDevRead, FlashDevEraseBlock, and FlashDevWrite
They are in the scm project "flash" (/home/ad_projects/flash/clear)
in the file lowlvl.c. The lowlvl.h is also needed for some definitions, such
as block boundaries. In lowlvl.h, note that the blocks are NOT all the same size.
Play with these functions; learn to use them. They are your friends.

Next, you will want a function something like my fileflash() (in the
flash scm project, file fileflash.c).  This function basically copies a file from
disk into the FLASH boot address. 
	
All the vxWorks + applications images I have produced easily fit into under
1 MB of FLASH.  This leaves the rest of FLASH for you to use as NV storage
for your application, if you desire/require it.

			Step 5. START BUILDING

The above has been pretty straightforward. Unfortunately, now things
get more complicated.  You now have to go build special purpose
vxWorks kernels.  The path I followed is to build a vxWorks kernel
that includes its own symbol table, is put into ROM and is compressed.
The symbol table is needed if you want to be able to use the shell to
monkey with things.  As we use vxWorks here, you usually pick up the
symbol table separately from the object file over the network.  The
kernel is compressed because it saves greatly on the amount of ROM
required.

You should be familiar with the WindCFG tool.  Too bad, because it is pretty
useless for this process.  You pretty much need to do the "make" by hand,
and it isn't pretty.  But Kevin Martin and I have made some fixes since
I started which now makes it much easier for you.

5.A Modify some files

	$(BSP_DIR)/config.h
	$(BSP_DIR)/Makefile
	$(TGT_DIR)/config/all/configAll.h

	BSP_DIR will typically be /usr/wind_ppc/target/config/mv2303
	TGT_DIR	will typically be /usr/wind_ppc/target


5.A.i config.h
This is the easiest modification to make. All you need to do is make
sure that the difference between  RAM_HIGH_ADDRS and RAM_LOW_ADDRS is
big enough to hold your final, bundled, uncompressed VxWorks image file.
RAM_HIGH_ADDRS has generally been about 0x200000 by default. For the
Frig application, I had to increase it to about 0x400000, and things just 
fit.  I would guess that the 0x400000 value is a good starting point for
you, because Frig has about as much code as any front end would ever want.
You won't *know* if this is sufficient until later in the process.

5.A.ii Makefile
Make the definition of RAM_HIGH_ADDRS in Makefile the same as in config.h.


5.A.iii configAll.h

When you build the vxWorks kernels via a command line "make" (as you
must do in this case) instead of the WindCFG Configure and Build
commands, you have to manually indicate which features to include and
exclude.  This is done through the file:

	$(TGT_DIR)/config/all/configAll.h

There is a copy of the version of configAll.h that I used in building
the Frig kernel in the file configAll.h.frig.  It's a pretty generic
configuration that you might find suitable.


5.B  Start issuing commands.

5.B.i   General Configuration
I'm not sure if this step is absolutely necessary, but I think it is.
First, use the WindCFG tool to configure and build a vxWorks kernel pretty
much the way you'd want it if you weren't putting it into rom and weren't
linking your application into it, EXCEPT, you probably have to make (at least)
two changes.
Add: INCLUDE_STANDALONE_SYM_TBL to the Included Options side.
Move: INCLUDE_NET_SYM_TBL to the Excluded Options side.

Then push the Configure and Build buttons.  Let it finish building.

5.B.ii  First make attempt
"cd" to the appropriate BSP directory, e.g. 
% cd /usr/wind_ppc/target/config/mv2303

Get rid of old junk lying around:
% make clean

Now run your first pass through make with a command like this:

% make vxWorks.st_rom  ADDED_MODULES=/home/ad_projects/myapp/clear/myapp.o 

vxWorks.st_rom is the target which includes its own symbol table and is 
compressed and is to be loaded into ROM for booting.

You specify your application objects that you want to link in with the 
ADDED_MODULES definition.

If your make ends with error messages like this:
	symTbl.c:56: nondigits in number and not hexadecimal
	symTbl.c:56: syntax error before `00013a2c'
	make: *** [vxWorks.st.Z.s] Error 1

Then look at the file $(TGT_DIR)/h/make/rules.bsp and the information
there about KEEP_SYMTAB.   We believe we have fixed this problem so that
it should not arise for you, but if it does, that KEEP_SYMTAB stuff in rules.bsp
gives you a work-around.


5.B.iii  Check the Object Size

As part of the  build process, an intermediate step is:
	"ldppc -o tmp.2"
This tmp.2 file is basically the UNcompressed objectfile that then gets
compressed and wrapped up in some uncompression code before being 
made ready for downloading to ROM.
So I have also added a couple statements to the rules.bsp Makefile inclusion
to check how big that is.  I do "ls -l" and "vxsize" to test the size.
The "ls -l" is really superfluous, just there fyi.  But vxsize
checks to see if the final object, once it gets uncompressed at
boot time, will fit in the allotted space, between RAM_LOW_ADDRS and
RAM_HIGH_ADDRS, as seen in step 5.A.i.
The output from it will look something like this:
VX_CPU_FAMILY=ppc /usr/wind_ppc/host/parisc-hpux9/bin/vxsize -v 00400000  00100000  tmp.2
tmp.2: 1119872(t) + 237596(d) + 1079352(b) = 2436820 (1788260 bytes left)

First, note that vxsize is a total idiot of a program. It can't
subtract properly, apparently. (It does work for smaller sized object
files, I have no idea why it starts failing when they get up over 2
MB, but it does.)  Note that we have 0x300000 bytes of space available
(3MB), but vxsize apparently thinks we have 4MB. 2436820 +1788260 is
not = 3 MB.

So you have to check vxsize for yourself to make sure you have
allocated enough room in ram for the uncompressed object.  Compare the
total (2436820) with the space you have available (3MB in this
case). If your total exceeds the space available, then go back to
5.A.i and start over.

5.B.iv Finishing up.

Note that make also runs something called "romsize" to check whether
your final product will fit in your ROM or not. I don't think romsize
works very well either, actually.

You have to do one more step to make your final product:

% elfToBin <vxWorks.st_rom >vxWorks.st_rom.bin

vxWorks.st_rom.bin is the final product which you will load into FLASH.
Now check out how big it is.

% ll vxWorks.st_rom.bin
-rw-r--r--   1 nicklaus ad_microp 605288 Dec  3 17:09 vxWorks.st_rom.bin

And make sure it will fit into the amount of FLASH/ROM that you 
were intending to use.

			    6.  LOAD IT UP

To load your .bin file into FLASH, you could move it into the tftp
area (which requires root access), switch back to PPCBug from Bank B,
and use niop to download it.  But that wouldd be a lot of work for no
real reason.  Instead, you can just write the file contents directly
into FLASH, using the functions you learned about in Step 4.

You have to write the file into FLASH starting at FLASH address 0x100.
Remember you have to first erase all the FLASH blocks that you will
be using.  I have written a function fileflash(), found in the
flash scm project, file fileflash.c, which does the required FLASH programming.
Look at the source code to know how to use it.
Briefly, to load the above file, you would call:
	fileflash("vxWorks.st_rom.bin",605288)

Now reboot, and away you go!

	   7. ADDING A CALL TO YOUR ENTRY POINT FUNCTION

You need to change the file:
	$(TGT_DIR)/config/all/usrConfig.c
There is a line in there:
	#undef INCLUDE_USER_APPL
You need to get rid of that. (or comment it out).

Then right below that, notice that there is the following:
	#ifdef INCLUDE_USER_APPL
	    /* Startup the user's application */

	    USER_APPL_INIT;	/* must be a valid C statement or block */

You need to change USER_APPL_INIT to be a valid C statement, probably
a function call to your own initialization function.
After you make this change, you need to go through and rebuild, of course.
See for example, usrConfig.c.frig.


		  8.  WHAT'S MISSING IN THIS PICTURE

Your application probably isn't really independent of the network just yet.
You can use other parts of FLASH to store various parameters or set-up values,
things that might be in your start-up script at present.

If you still specify a startup script, then when your processor boots, it
will try to go over the network to try to find and read this startup script file.
If it can't get to the network (connection broken, network down,...) the
processor will hang indefinitely waiting to get that file.

So if you want to be network independent, don't have a startup script specified
through vxWorks bootChange().  Instead, you can put the equivalent of 
searching for a startup script in your own init functions, where you can
control what happens if the network isn't available.

Also note, if you have a vxWorks kernel file specified through
bootChange(), but then you boot out of ROM like this method describes,
the bootChange()-specified vxWorks kernel file not be loaded.

The Frig project also has a simple shell script file which is used to
copy in the Frig versions of the VxWorks files, make, then restore the
original VxWorks file versions.

			   9. JUST BIZARRE

If you have a global variable which starts with the string "Global",
or maybe it's just with a capital G, I don't know what the actual key
is, that global variable will NOT make it into the symTbl.c file.
Since the variable name is not in symTbl.c, you won't be able to use
it from the shell.

I don't know why this is. Maybe it has something to do with the -X flag
to ld.  (Although nothing in the ld man page would reinforce that belief.)