Page 1 of 1

SYSTEM.PUT Transfer Width

Posted: Mon May 03, 2021 6:54 am
by gray
With the Astrobe compiler, SYSTEM.PUT(adr, val) transfers either eight or 32 bits, depending on the type of 'val'. But what if 'val' is an expression?

I had this procedure interfacing a device in the FPGA hardware.

Code: Select all

PROCEDURE SetSignal*(dev: INTEGER; sig: BYTE);
BEGIN
  SYSTEM.PUT(Adr, LSL(sig, DataShift) + LSL(dev, SelectShift) + SetSignalCtrl)
END SetSignal;
The BYTE parameter had unfortunately "survived" from an older implementation of both the hardware and the software, where it was the correct type to use.

The above procedure does not work as intended. Here's why. Consider this simple test case.

Code: Select all

CONST Adr = -144;
VAR i: INTEGER; b: BYTE:
SYSTEM.PUT(Adr, i + b) (* case 1 *)
SYSTEM.PUT(Adr, b + i) (* case 2 *)
The two puts don't produce the same result. Case 1 transfers 32 bits, case 2 transfers eight bits. Below, 'i' and 'b' are on the stack at SP + 4 and SP + 8, respectively:

Code: Select all

 SYSTEM.PUT(Adr, i + b)
.  22   80E00004H  LDW   r0,  sp, 4
.  23   91E00008H  LDB   r1,  sp, 8
.  24   00080001H  ADD   r0,  r0,  r1
.  25   5100FF70H  MOV   r1,  r0, -144
.  26   A0100000H  STW   r0,  r1, 0

 SYSTEM.PUT(Adr, b + i)
.  34   90E00008H  LDB   r0,  sp, 8
.  35   81E00004H  LDW   r1,  sp, 4
.  36   00080001H  ADD   r0,  r0,  r1
.  37   5100FF70H  MOV   r1,  r0, -144
.  38   B0100000H  STB   r0,  r1, 0
Consequently, the above 'SetSignal' procedure only transferred eight bits, and thus didn't work. Some head-scratching ensued, and it took me quite some time to figure this out. With a new device design in the FGPA it's the first place where I suspect my mistakes.

If one is aware of the potential issue, it can easily be resolved in different ways. I could simply change the BYTE parameter to INTEGER, which was now appropriate for the new driver. In other cases we can formulate the expression in a different order, or use an intermediate local variable to "enforce" the transfer width.

The Astrobe manual contains a fair warning regarding the use of BYTE. And I shall better heed it going forward, and always check the assembly code when juggling with BYTE in device drivers.

At first, I had thought that SYSTEM.PUT should always use 32 bit transfers as soon as an expression is used, but this might not be the correct solution in every case either. Probably better keep manual control, and pay attention.