[Oberon] Standalone BootLoader format

Andreas Pirklbauer andreas_pirklbauer at yahoo.com
Tue May 12 20:56:06 CEST 2020


Tomas,

you have to study how the boot process works, in detail.

    > Do these 7 words' gap map over these limits below,
    > set by the BRAM loader?
    > 0 A branch instruction to the initialising body of module Modules
    > 12 The limit of available memory
    > 16 The address of the end of the module space loaded
    > 20 The current root of the links of loaded modules
    > 24 The current limit of the module area

By default, a standalone program (like your Counter.Mod) does not HAVE
ANY NOTION and therefore does NOT MAKE USE of ANY of these values.

Only the bootloader (BootLoad.Mod) - a very special standalone program -
has, by convention, any notion of the above memory locations 0, 12, 6, 20, 24.

Here is how this convention is implemented (for BootLoad.Mod!)

When Modules.bin gets created, ORL.Link writes some values to these locations
in the generaed boot file, in particular location 0, 16 and 20 (PS: My ORL.Link
also writes to 12 and 24, but the bootloader will actually overwrite these, see below).

See the last few lines of ORL.Link. So after executing ORL.Link Modules ~ 
these values reside in the file Modules.bin. The value in location 16 in the
boot file Modules.bin in fact tells the boot loader (BootLoad.Mod), how many
bytes it has to read from the boot file.


The bootloader (BootLoader.Mod), which itself resides at absolute address -8192,
reads Modules.bin (either from disk or over the serial line) and fills the memory
starting at address 0 with the content from Modules.bin, byte for byte.

How? By virtue of the *very first* ReadSD instruction in LoadFrom Disk

  PROCEDURE LoadFromDisk;
    VAR src, dst, adr, lim: INTEGER;
  BEGIN src := FSoffset + 4;   (*start at boot block*)

    ReadSD(src, 0);     (*<— this is how Mem[0, 12, 16. 20, 24] are actually filled*)

    SYSTEM.GET(16, lim);   (*<— this is the number of bytes the bootloader has to read*)

    INC(src); dst := 512;
    WHILE dst < lim DO ReadSD(src, dst); INC(src); INC(dst, 512) END
  END LoadFromDisk;

or, if you boot over the serial line, the first few RecInt’s in LoadFromLine

  PROCEDURE LoadFromLine;
    VAR len, adr, dat: INTEGER;
  BEGIN RecInt(len);
    WHILE len > 0 DO
      RecInt(adr);
      REPEAT RecInt(dat); SYSTEM.PUT(adr, dat); adr := adr + 4; len := len - 4 UNTIL len = 0;
      RecInt(len)
    END
  END LoadFromLine;

So, after LoadFromDisk or LoadFromLine have been executed, the values at address 0, 16, 20
are filled with whatever was at locations 0, 16, 20 in the bootfile Modules.bin.

The bootloader itself will overwrite some of these values, namely:

   SYSTEM.PUT(12, MemLim); SYSTEM.PUT(24, stackOrg);

These are hardcorded constants.

Note: In my linker, ORL.Link I also write some sensible values to these
locations (12 and 24) before writing the pre-linked binary Modules.bin
to disk - fully knowing that these values will be overwritten anyway.
But at least ORL would also works with bootloaders that don’t
actually overwrite these values. Just a small side comment.

BACK TO YOUR Counter.Mod
-----------------------------------------

Unlike BootLoad.Mod, Counter.Mod does NOT write those values 0, 12, 16, 20, 24.

if you will, all it has is a single “BR 7” branch location from the very first location
(code[0]) to the eigth position (code[8]) within the code section.

So, if you load Counter.rsc to location 0, then you will have that “BR 7” branch at
absolute memory address 0, which jumps to address 32. And wenn you declare
global variables in Counter.Mod, these global variables will be placed at absolute
memory addresses, 12, 16, 20, 24, 28 (6 words or 24 bytes). That’s it.

If, however, you load Counter.rsc to any other location, for example to location 
1024, then you will have that “BR 7” branch instruction at absolute memory
address 1024 and it will jump to address 1056, the first instruction of Counter.rsc.

And you can declare ANY number of global variables. These will simply start
filling ng the memory area starting at address (1016 bytes). Don’t declare more
than 1016 bytes worth of global variables, otherwise these will overwrite the code
section of Counter.rsc, which starts at address 1024.

-ap









More information about the Oberon mailing list