Fast ARRAY and RECORD moves

Download pre-release library modules and new examples to use with the Cortex-M4 and Cortex-M3 versions of Astrobe. Forum members can also upload their own source code examples.

Fast ARRAY and RECORD moves

Postby cfbsoftware » Mon Sep 16, 2013 1:29 pm

The auto-increment / auto-decrement versions of SYSTEM.GET and SYSTEM.PUT in v4.5 Astrobe and later allow you to implement very efficient array processing functions. For example, the following are useful general-purpose functions for moving /copying blocks of data:

Code: Select all
 PROCEDURE* MoveWords*(fromAdr, toAdr, nBytes: INTEGER);
 VAR
   word, lastAdr: INTEGER;
 BEGIN
   lastAdr := fromAdr + nBytes;
   REPEAT
     SYSTEM.GET(fromAdr, word, 4);
     SYSTEM.PUT(toAdr, word, 4);
   UNTIL fromAdr = lastAdr
 END MoveWords;

 PROCEDURE* MoveBytes*(fromAdr, toAdr, nBytes: INTEGER);
 VAR
   byte: BYTE;
   lastAdr: INTEGER;
 BEGIN
   lastAdr := fromAdr + nBytes;
   REPEAT
     SYSTEM.GET(fromAdr, byte, 1);
     SYSTEM.PUT(toAdr, byte, 1);
   UNTIL fromAdr = lastAdr
 END MoveBytes;
 
 PROCEDURE Move*(fromAdr, toAdr, nBytes: INTEGER);
 VAR
   nBytes4, nBytes1: INTEGER;
 BEGIN
   nBytes1 := nBytes MOD 4;
   nBytes4 := nBytes - nBytes1;
   IF nBytes4 > 0 THEN
     MoveWords(fromAdr, toAdr, nBytes4);
   END;
   IF nBytes1 > 0 THEN
     MoveBytes(fromAdr + nBytes4, toAdr + nBytes4, nBytes1);
   END
 END Move;


The main loop of MoveBytes and MoveWords consist of just four instructions. MoveWords is typically four times faster than MoveBytes because it loads/stores four bytes in each instruction and can be used for INTEGER arrays or records that are multiples of four bytes. Move can be used if it is not known if the data is a multiple of four bytes. It uses MoveWords for all except the last (less than four) bytes of data.

An example of their use is a function to shift all the bytes in an array by one position. The normal way to do this would be something like:
Code: Select all
PROCEDURE* ShiftArray(VAR a: ARRAY OF BYTE);
 VAR
   i: INTEGER;
 BEGIN
   FOR i := 1 TO LEN(a) - 1 DO a[i-1] := a[i] END
 END ShiftArray;

However, if maximum performance is a priority, an alternative implementation is:
Code: Select all
 PROCEDURE ShiftArray(VAR a: ARRAY OF BYTE);
 BEGIN
   Move(SYSTEM.ADR(a[1]), SYSTEM.ADR(a[0]), LEN(a) - 1)
 END ShiftArray;

A test with 1000-byte arrays showed that this second version that uses GET and PUT is about five times faster.
cfbsoftware
Site Admin
 
Posts: 299
Joined: Fri Dec 31, 2010 12:30 pm

Return to General