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 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 *)
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
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.