[Oberon] Oberon System definition file(s)

Skulski, Wojciech skulski at pas.rochester.edu
Thu Jul 18 11:57:00 CEST 2024


Joerg,

thank you for the comment. I want to make it clear that I am not proposing a *single file*, but rather a *single place* to define constants. The place may consist of several files (MemDef, RegDef, AsciiDef, etc). The point is the following. If I am working on porting the OS to the new board, I want to make changes in *one place*. For example, if I am adding more memory, then I want to modify one file (let it be MemDef.Mod). I want to know that no other spots are hiding in some module(s), where the memory layout is affected and may become inconsistent.

The memory is an obvious thing, is it not? How about peripherals? In how many places are these addresses written into the code? It should be one place. But it is not. I found these numbers written verbatim in several places. Now imagine that I want to remap the OS peripherals. I have to go over many files and change "-48" to "some other number". What happens if I overlook one such spot? A crash will happen. This is not a robust way of writing software. Are you saying that it is?

There are other obscure and undocumented constants. In my opinion these should not be undocumented. They should be named, exposed, and commented in full.

Four years ago I went over the entire Extended Oberon and I collected all these constants which I found in all these modules. I documented whatever I could in the SysDef.Mod.odc. I used BlackBox editor because I could fold these findings in the files itself. It is attached to this e-mail. The documentation portion starts after "END SysDef." It is unfolded in the attached file. The PDF is for those who do not have BlackBox installed.

I bumped the version control of this file to July/18/2024 for reference. However, this file dates back to four years ago. 

Wojtek
________________________________________
From: Jörg Straube [joerg.straube at iaeth.ch]
Sent: Wednesday, July 17, 2024 10:08 AM
To: Skulski, Wojciech; ETH Oberon and related systems
Cc: pdewacht at gmail.com
Subject: AW: [EXT] Re: [Oberon] Fighting a dragon ...

Wojtek

The idea is good but the way you propose is not.

Let’s look at the SW side first:
Please understand that Oberon is a programming language allowing separate compilation.
Your SysDef module is NOT just an include file like in C or assembler. The complier allocates an own module key to it.
Let’s assume we do as you propose. And let’s assume the FPGA gets more memory.
You have to change your constant MEMLIM and hence have to recompile SysDef.
All modules importing SysDef have to be recompiled, although not necessarily needed.
Eg FSOffset (FS for Filesystem) or REG12 have nothing to do with the memory.

Two alternative approaches:

  *   Split up this one monolithic SysDef.Mod in separate, logically independent modules:
Eg all register constants (REG15, REG14 …) in a file def.RISC5.Mod or def.CPU.Mod.
The logical register names (MT, SB SP..)  in a File def.Compiler.Mod, as the complier (basically ORG.Mod) defines how RISC registers are used in Oberon.

The constant FSoffset (FS = file system, has nothing to do with STACKORG) is currently used by BootLoader and Kernel
and in the future perhaps by some disk inspection tool that does not want to use Kernel.

This could be in an own def.Boot.Mod or def.SDCard.Mod. But it is debatable if you need an own module for one constant.


  *   Complimentary to the above: Each module exports variables where it exposes its implementation choices.
Eg Kernel defines where the heap is and allocates memory from the heap. So, it appears logical that Kernel exports its implementation choices, how Oberon organizes its heap.

Actually, it does it already: your constant STACKSIZE is basically Kernel.stackSize, your constant HEAPORG is basically Kernel.heapOrg.

If you have more memory, Kernel.Mod decides if and how it wants to use it, you change the IMPLEMENTATION of Kernel (NOT exported constants impacting the module key) and the rest of the system is untouched and benefits of more memory without recompiling everything as with your approach.

The module Modules.Mod handles the loading of modules, so decides on ModAllocAdr, MTOrg and so forth.

A lot of your “constants” are actually not needed as you can find them via
MEMLIM := SYSTEM.GET(MemLimAdr); or  MEMLIM := Kernel.MemLim
MTOrg := SYSTEM.GET(ModRootAdr); or MTOrg := Modules.MTOrg

I understand that the concept of abstraction and separate compilation brings the drawback of several files and not ONE file as you might like.
Kernel.Mod decides on heap allocation, Modules.Mod on module allocation, FileDir.Mod on file allocation, Display on display memory etc. Every implementation decides independently on how it organizes its HW resources and exports its decisions to the rest of the system either via constants or more flexibly as variables or procedures.

Now to the HW point of view:
I agree that some of the issues you address are not solved: How does the Bootloader know, that he can set the stack pointer to 80000H?
It apparently assumes that it has at least 512kB (=80000H) of memory. These bootstrapping issues should not be solved with SysDef nor with my approaches explained above.
These issues should be solved with “dynamic HW”: I mean the SW should be able to ask HW capabilities. E.g “How much memory do we have installed”?
“What’s the address and size of the video frame buffer?” These “constants” burnt in HW may well be at one place if you like. In the Project Oberon environment, RISC5Top.v is most probably the best place for this.

One idea how the SW can “talk” to the HW is to use the last possible IO port (-4) for this. Something like this

System.PUT (-4, 0); (* 0 = get info on all devices *)
len := System.GET(-4); IF len = 0 THEN (* HW does not support device enumeration *)
ELSE
   FOR i := 1 TO len DO dev[i] := System.GET(-4) END; (* this lists all devices in the system: memory, IO Ports, graphics… *)
END;

System.PUT (-4, dev[3]); (* Example: get info on device with number dev[3] *)
ch := System.GET(-4); IF ch = 0X THEN (* HW does not support device info *)
ELSE
  i := 0; REPEAT driver[i] := ch; INC(i) ch := SYSTEM.GET(-4) UNTIL ch = 0X; (* max 32 chars *)
  Modules.Load(driver, D); P := Modules.ThisCommand(D, “Init”); P;   (* initializes the driver and reads the rest of the HW info of this device *)
END;

The HW first returns the name of the device driver of the specific device.
Then, the device driver is loaded and gets the remaining device info.

Such a scheme is not implemented yet.

br
Jörg


Am 17.07.24, 12:17 schrieb "Skulski, Wojciech" <skulski at pas.rochester.edu>:
>But I really think we need some standard way how to find out these limits. My proposal would be to put them all in a module like Limits.Mod and give them standard names.

Hans,

this is a known dragon raising its ugly head again. Oberon System needs parametrizing. Your proposed Limits.Mod is only a part of it. I proposed SysDef.Mod defining the memory size, memory locations, stack, etc. These are all constants, but these are constants that must be changed when porting to a new board. For example, the 1 MB size of the memory was imposed by a particular board which was popular 10 years ago. The location and size of graphics RAM followed from this limitation. Then the peripheral addresses were defined one after another, which was sufficient only because their implementations were very simple. This again was due to hardware limitation. FPGA was 94% full and nothing else would fit. All these design decisions were hardwired all over the code without any central definition. It almost looks as if Oberon System programmers are fond of repeatedly typing hex numbers in every possible place. This makes their software genuinely non portable. The first step towards portability would be parametrizing all these numbers so they can be managed in one central location. Wirth himself made this point in his textbooks, and then nobody followed, including himself.

I am attaching my proposition from 4 years ago. It was shot down using arguments whose logic I could not follow. Like for example, it would take too long to recompile the OS if this file is modified. (Recompiling the whole OS takes ~3 seconds under Michael's emulator, and this was "too long".) Also, this file can be divided into a few smaller files (RegDef.Mod, MemDef.Mod, etc). This obvious idea was ignored by the key developers.

So I am not optimistic that this community will ever adopt your Limits.Mod. Your idea is both great and obvious, and therefore it is very likely to be swept under the rug.

Wojtek
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SysDef_July_18_2024.Mod.odc
Type: application/octet-stream
Size: 24169 bytes
Desc: SysDef_July_18_2024.Mod.odc
URL: <http://lists.inf.ethz.ch/pipermail/oberon/attachments/20240718/3c79de15/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SysDef_July_18_2024.pdf
Type: application/pdf
Size: 34670 bytes
Desc: SysDef_July_18_2024.pdf
URL: <http://lists.inf.ethz.ch/pipermail/oberon/attachments/20240718/3c79de15/attachment.pdf>


More information about the Oberon mailing list