SYSTEM.PUT Transfer Width
Posted: Mon May 03, 2021 6:54 am
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.
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.
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:
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.
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.