So here I have the following code (ARMv6 assembly):
wait$:
ldr r2,[r0,#24] //read 32 bits from addr 24 in r0 and store in r2
tst r2,#0x80000000 //????
bne wait$
I understand all of the lines other than the tst
instruction. I have done some research online and the best definition I could find was:
Test if a register is zero or minus. Perform a logical AND between a register and itself.
I had some trouble understanding what it meant so I then tried to make the C equivalent to an tst
instruction and this is what I got:
if(valRead & 0x80000000 != 0){}
The code above does not seems to be working. What is an easier to understand definition of tst
and what is the equivalent to it in C?
CodePudding user response:
TST{cond} Rn, Operand2
Description:
Instruction tests the value in a register against Operand2
. It updates the condition flags on the result, but does not place the result in any register.
The TST instruction performs a bitwise AND operation on the value in Rn
and the value of Operand2. This is the same as an ANDS instruction, except that the result is discarded.
This instruction:
- Updates the
N
andZ
flags according to the result. - Can update the
C
flag during the calculation ofOperand2
. - Does not affect the
V
flag.
Modern compilers rarely use tst
instruction in such simple operations (only one bit tested).
void foo(void)
{
volatile int x[7];
while(x[5] & (0b1L << (31)));
}
foo:
sub sp, sp, #32
.L2:
ldr r3, [sp, #24]
cmp r3, #0
blt .L2
add sp, sp, #32
bx lr
More complex pattern is required for the tst
instruction
int foo(void)
{
volatile int x[7];
while(x[5] & (0b10011UL << (31-5)));
}
foo:
sub sp, sp, #32
.L2:
ldr r3, [sp, #24]
tst r3, #1275068416
bne .L2
add sp, sp, #32
bx lr
CodePudding user response:
What is an easier to understand definition of
tst
and what is the equivalent to it in C?
Some background
There is no equivalent in C because higher-level languages work differently than a CPU with "status registers" (such as ARM or x86):
In high-level languages like C or C , conditional code execution can be done directly:
if(a < b) ...
On a CPU with a "status register", conditional code execution is done in two steps:
- In the first step, you perform some calculation (such as
a-b
).
In the so-called "status register" the CPU stores some "relevant" information (e.g. the sign) about the result. - In the second step, the actual conditional code execution is done.
This can only be done depending on the information in the "status register".
A simplified example:
The operation if(a < b) ...
could be performed the following way on a CPU with a "status register":
/* Subtract b from a */
c = a - b;
/* (a < b) means that (a - b) is negative */
if(status.last_result_was_negative) ...
... however, the result of the operation (c
in the example) is not needed.
The TST
and CMP
instructions
To perform an if(...)
operation, two operations are often needed:
- A subtraction:
it is needed for==
,<
,>
,<=
,>=
and!=
. - An AND operation:
It is needed to check if some bit(s) in a value is (are) set:
if(a & 0x8000) ...
... and in both cases, the result of the operation (the difference or the result of the AND operation) is not needed.
For this reason, there are two instructions (CMP
and TST
) that perform an operation (CMP
performs a subtraction and TST
performs an AND operation) but discard the result:
The TST
operation performs an AND operation, sets the information in the "status register" according to the result but it discards the actual result.
This makes sense in lines like if(a & 0xF000) ...
where you are only interested that the "status register" holds the information if the result of the operation a & 0xF000
was zero or not, but you are not interested in the actual result of a & 0xF000
.
if(valRead & 0x80000000 != 0){}
You need brackets:
if((valRead & 0x80000000) != 0){}
Otherwise the compiler undestands:
if(valRead & (0x80000000 != 0)){}
... which is the same as:
if((valRead & 1) != 0){}