Home > Blockchain >  Clarity About TST Instruction - ARM Assembly
Clarity About TST Instruction - ARM Assembly

Time:10-02

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 and Z flags according to the result.
  • Can update the C flag during the calculation of Operand2.
  • 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){} 
  • Related