[Oberon] oberonnet of things

Chris Burrows chris at cfbsoftware.com
Wed Aug 26 14:17:46 CEST 2015


> 
> Assigning variables to physical addresses is also needed for yet
> another
> reason: it is a common practice to assign a register to control some
> hardware. Reading/writing to such a variable is used to turn on/off
> some bits that control some hardware behaviors. This is done in
> Oberon System too, but I do not see a consistent mechanism in the
> language for doing so.
> (Maybe I missed it.) Something like
> 
>  VAR my_register : INTEGER AT ADDRESS "address value";
> 
> These facilities are not needed for a workstation where the OS is
> maintaining hardware via system calls. This is not our case. Oberon
> System is an embedded system and it needs embedded approach to its
> design. I am speaking from experience. We need all this.
> 
> Regards,
> Wojtek
> 

There is no need for an additional 'mechanism in the language' to do this.
We have been writing embedded software in Oberon for ARM7, ARM Cortex-M3 and
ARM Cortex-M4 microcontrollers for the last seven years. The in-line
pseudo-functions SYSTEM.GET, SYSTEM.BIT and SYSTEM.PUT provide a simple and
flexible way in Oberon to read and write registers mapped to absolute
addresses.

If you were using Astrobe to write embedded software for ARM Cortex-M3 and
M4 devices you would just need to import a module called MCU.mod which
contains CONST definitions for the peripheral register addresses. 

For example, the UART0 definitions in MCU.mod for the LPC177x / LPC178x
family include the following CONSTs:

  U0Base* = 04000C000H;
  U0RBR* = U0Base+000H;
  U0THR* = U0Base+000H;
  U0DLL* = U0Base+000H;
  U0DLM* = U0Base+004H;
  U0IER* = U0Base+004H;
  U0IIR* = U0Base+008H;
  U0FCR* = U0Base+008H;
  U0LCR* = U0Base+00CH;
  U0LSR* = U0Base+014H;
  ...
  ...

To send a single character via UART0 using polling is then simply:

PROCEDURE* PutCh*(ch: CHAR);
BEGIN
  REPEAT UNTIL SYSTEM.BIT(U0LSR, 5);
  SYSTEM.PUT(U0THR, ch)
END PutCh;

The mnemonics U0LSR (UART0 Line Status register), U0THR (UART0 Transmit
Holding Register) etc. would mean something to you if you had experience
with programming the NXP microcontrollers as it is the terminology used in
the NXP reference manuals for those devices.

The second parameter to PUT and GET is untyped, so you can also use SET
expressions if you want ot do bit manipulation e.g.:

VAR
  pconp: SET; 
BEGIN
  SYSTEM.GET(MCU.PCONP, pconp);
  IF uartNo = UART0 THEN 
    pconp := pconp + {3};  
    SYSTEM.PUT(MCU.PCONP, pconp)
  END;

Furthermore, if the second parameter is byte-sized (BYTE or CHAR) then a
byte-access instruction is generated:

  strb r9,[r11]

If it is word-sized (INTEGER, SET or REAL) then a word-access instruction is
generated:

  str r9,[r11]

We support more than 30 different microcontrollers grouped into seven
different families - that is just a subset of the devices available from ONE
microcontroller manufacturer (NXP - formerly Philips). Each of those seven
families has a separate Windows folder with their own specific MCU.mod file.
The number of address definitions in MCU.mod ranges from about 300 to 800
(just the most commonly used ones).

If your ambition is to similarly define a whole lot of extra hardware
capability in Verilog for an expanded RISC5 environment then you could use
the same sort of technique to access the resulting additional peripheral
addresses. There is nothing to stop you ...

Regards,
Chris

Chris Burrows
CFB Software
http://www.astrobe.com





More information about the Oberon mailing list