<div dir="ltr"><div>Chris,</div><div><br></div><div>>On the surface this sounds OK but in reality the sheer number of addresses</div><div>>involved led us to use a different approach.</div><div><br></div><div>I like your way, in that it properly layers the concerns.</div><div>But the easier way is to translate the MCU spec file (which for ARM mcu's and many others is to be gotten in XML format) into a system constants file. A python program to do that is not difficult to construct.</div><div><br></div><div>I have never tried to do it for Oberon, but for Ada it is easy.</div><div>Look at this partial sequence (all made automatically as described above)</div><div><br></div><div><font size="1">with System; </font><br></div><div><font size="1">package AVR.ATtiny816 is<br></font></div><div><font size="1">.</font></div><div><span style="font-size:x-small">.</span></div><div><div><font size="1">   ------------------------------------------------------------</font></div><div><font size="1">   --  register INTCTRL  -  Interrupt Control</font></div><div><font size="1"><br></font></div><div><font size="1">   AC_INTCTRL_Addr : constant Address := 16#676#;</font></div><div><font size="1">   AC_INTCTRL      : Unsigned_8;</font></div><div><font size="1">   for AC_INTCTRL'Address use AC_INTCTRL_Addr;</font></div><div><font size="1">   pragma Volatile (AC_INTCTRL);</font></div><div><font size="1">   AC_INTCTRL_Bits : Bits_In_Byte;</font></div><div><font size="1">   for AC_INTCTRL_Bits'Address use AC_INTCTRL_Addr;</font></div><div><font size="1">   pragma Volatile (AC_INTCTRL_Bits);</font></div><div><font size="1"><br></font></div><div><font size="1">   AC_CMPC_Bit   : constant Bit_Number := 0;</font></div><div><font size="1">   AC_CMPC_Mask  : constant Unsigned_8 := 16#1#;</font></div><div><font size="1">   --  Analog Comparator 0 Interrupt Enable</font></div></div><div><font size="1">.</font></div><div><font size="1">.</font></div><div><font size="1">end AVR.ATtiny816;</font></div><div><br></div><div>By the way the 'Bits_In_Byte' type is an 8 bit boolean array. It makes it easier to program for pins or bits. Unsigned_8 can be understood as SYSTEM.BYTE. The Pragma Volatile is to stop GCC from optimizing the code for the register out of existence.</div><div><br></div><div>Then the second file:</div><div><br></div><div><div><font size="1">with AVR.attiny816;</font></div><div><font size="1">package AVR.MCU renames AVR.attiny816;</font></div></div><div><font size="1"><br></font></div><div>And on top of this you can build your IO layer, or whatever you fancy, without importing System again, also since GCC has smart ways of optimizing code so that I never have the need to put semi-assembly in my program. This might vary on the Oberon compiler.</div><div><br></div><div>Now I am of course not advertising Ada as a way of life, in fact she is a very temperamental  lady at times, and 'part of the problem' as NW once remarked. But it is good to compare notes.</div><div><br></div><div>j.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Aug 8, 2018 at 3:32 PM, Chris Burrows <span dir="ltr"><<a href="mailto:chris@cfbsoftware.com" target="_blank">chris@cfbsoftware.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">> -----Original Message-----<br>
> From: Oberon [mailto:<a href="mailto:oberon-bounces@lists.inf.ethz.ch">oberon-bounces@lists.<wbr>inf.ethz.ch</a>] On Behalf Of<br>
> Walter Gallegos<br>
</span><span class="">> Sent: Wednesday, 8 August 2018 4:04 AM<br>
> To: <a href="mailto:oberon@lists.inf.ethz.ch">oberon@lists.inf.ethz.ch</a>; Walter Gallegos<br>
> Subject: [Oberon] Oberon FPGA hardware point of view<br>
> <br>
</span><span class="">> A FPGA hardware designer point of view;<br>
> <br>
> In some projects (all my projects) the CPU executes software as<br>
> coprocessing; in parallel but outside the main data flow of hardware<br>
> DSP; hardware is faster and more efficient than software DSP.<br>
> <br>
> On this scenery, the memory map could change from one project to<br>
> another project. So, hardware/software designers need certain degree<br>
> of freedom to access memory mapped areas.<br>
> <br>
> I propose two modifications :<br>
> <br>
> 1/ Add memory mapped variables<br>
> <br>
> VAR [label] : [type] AT [address]<br>
> VAR [label] : ARRAY [size] OF [type] AT [address]<br>
> <br>
<br>
</span>On the surface this sounds OK but in reality the sheer number of addresses<br>
involved led us to use a different approach.<br>
<br>
Our technique follows Paul Reed's recent advice here i.e. separate all of<br>
the hardware specific details from everything else into the lowest level<br>
modules. This has worked out really well for us. It avoids the software<br>
maintenance nightmare of having to track down / modify hard-coded addresses<br>
and other hardware-specific details scattered throughout a system.<br>
<br>
With the Astrobe for ARM Cortex-M3, M4 and M7 Oberon systems we were faced<br>
with the prospect of having to maintain hundreds of memory-mapped addresses<br>
for similar, but different, memory-mapped peripherals for more than 60<br>
different types of microcontroller from two different manufacturers (NXP and<br>
STMicroelectronics). You might expect to have a couple of different sets of<br>
common definitions for each manufacturer but we ended up needing 11<br>
altogether. Not as bad as 60 perhaps but I'm convinced the designers could<br>
have done a lot better at eliminating inconsistencies. <br>
<br>
The scheme we have used is this: There is a single module, called MCU.mod,<br>
for each family of microcontrollers e.g. LPC176x (NXP Cortex-M3), STM32F7<br>
(STM Cortex-M7) etc. There are eleven of these, all with the same name but<br>
stored in a folder named after the microcontroller family. <br>
<br>
The *key* feature is: the *only* items contained in the MCU module are CONST<br>
declarations. <br>
<br>
Each named constant represents a peripheral register address. Much of the<br>
time just the base address of each peripheral is different from one MCU to<br>
another so we take advantage of the fact that CONSTs can contain arithmetic<br>
expressions. We can then specify a single base address for each device and<br>
the other related registers are common offsets from that base. <br>
<br>
e.g. <br>
<br>
for UART0:<br>
<br>
  U0Base* = 04000C000H;<br>
  U0RBR* = U0Base+000H;<br>
  U0THR* = U0Base+000H;<br>
  U0DLL* = U0Base+000H;<br>
  U0DLM* = U0Base+004H;<br>
  ...<br>
<br>
For UART2:<br>
<br>
  U2Base* = 040098000H;<br>
  U2RBR* = U2Base+000H;<br>
  U2THR* = U2Base+000H;<br>
  U2DLL* = U2Base+000H;<br>
  U2DLM* = U2Base+004H;<br>
  ...<br>
  ...<br>
<br>
RBR, THR, DLL, DLM etc. are the names used for each UART function exactly as<br>
used by NXP in their programming reference manual. In case you are<br>
wondering, yes - RBR, THR and DLL all map to the same absolute address.<br>
<br>
Now, just to be different, the corresponding base address for the LPC1347<br>
family is U0Base* = 040008000H. If that wasn't bad enough, sometimes the<br>
relative offset addresses are different as well! <br>
<br>
There are more than 500 of these definitions in the LPC176x version of<br>
MCU.mod and there are still a number of peripherals that we have not yet<br>
included.<br>
<br>
Now that we have isolated what is *different* in MCU.mod, we can then<br>
implement a common hardware-interface module (e.g. Serial.mod) which uses<br>
these constant definitions, with their generic names, when implementing the<br>
(still hardware-specific) functions:<br>
<br>
  IMPORT MCU, SYSTEM;<br>
<br>
  PROCEDURE PutCh*(ch: CHAR);<br>
  BEGIN<br>
    REPEAT UNTIL SYSTEM.BIT(ULSR, 5);<br>
    SYSTEM.PUT(UTHR, ch)<br>
  END PutCh;<br>
<br>
<br>
The next level up in the module hierarchy is the familiar common<br>
*hardware-independent* 'Out' module. This works with all the different<br>
microcontrollers providing functions Out.Char, Out.String. It includes the<br>
statement:<br>
<br>
  IMPORT Serial;<br>
<br>
And the functions just call PutCh in different ways.<br>
<br>
The mechanism that we use to specify which particular MCU.mod and Serial.mod<br>
files are actually used when we compile an application which targets a<br>
particular family of microcontrollers is to associate the application with a<br>
configuration file containing mcu-specific 'search paths'. An extract from<br>
the map file for an application called 'Info' shows the consequences:<br>
<br>
LPC1769:<br>
MCU             D:\AstrobeM3-v6.4\Lib\LPC1769\<wbr>MCU.arm<br>
Out             D:\AstrobeM3-v6.4\Lib\General\<wbr>Out.arm<br>
Serial          D:\AstrobeM3-v6.4\Lib\LPC1769\<wbr>Serial.arm<br>
Info            D:\AstrobeM3-v6.4\Examples\<wbr>General\Info.arm<br>
<br>
LPC1347:<br>
MCU             D:\AstrobeM3-v6.4\Lib\LPC1347\<wbr>MCU.arm<br>
Out             D:\AstrobeM3-v6.4\Lib\General\<wbr>Out.arm<br>
Serial          D:\AstrobeM3-v6.4\Lib\LPC1347\<wbr>Serial.arm<br>
Info            D:\AstrobeM3\Release\Examples\<wbr>General\Info.arm<br>
<br>
Most of the time the only functions we need to use with these CONST<br>
addresses are SYSTEM.PUT to write a value, SYSTEM.GET to read a value and<br>
SYSTEM.BIT to test the value of a single bit. <br>
<br>
If multi-byte data needs to be efficiently read or written to an Oberon<br>
ARRAY or RECORD, SYSTEM.ADR, SYSTEM.COPY and SYSTEM.VAL (or ARRAY OF BYTE<br>
parameters) are the Oberon features that can be used. Once the conversion<br>
has been done from a byte-stream to an application-specific Oberon data<br>
structure at the hardware interface the Oberon data structure can be used<br>
naturally in the application from then on. It only needs to be converted<br>
back to a byte-stream when the hardware needs to be updated. <br>
<br>
Regards,<br>
Chris Burrows<br>
CFB Software<br>
<a href="http://www.astrobe.com" rel="noreferrer" target="_blank">http://www.astrobe.com</a><br>
<div class="HOEnZb"><div class="h5"><br>
<br>
--<br>
<a href="mailto:Oberon@lists.inf.ethz.ch">Oberon@lists.inf.ethz.ch</a> mailing list for ETH Oberon and related systems<br>
<a href="https://lists.inf.ethz.ch/mailman/listinfo/oberon" rel="noreferrer" target="_blank">https://lists.inf.ethz.ch/<wbr>mailman/listinfo/oberon</a><br>
</div></div></blockquote></div><br></div>