Syd
Syd

Reputation: 11

Assembly Code only returns two of possible four values in comparison

I am currently writing a Program that requires C++ and Arm Assembly language to be implemented. The C++ code uses functions from the assembly file to perform particular tasks on a STM32F4discovery board touchscreen. One of the particular functions is a function that returns what quadrant the user is touching currently, and we had to write that function in assembly. No matter what I do, this function always returns quadrant 1 or 3. I think I am having an issue with branching properly, as this is one of my weak points, but I do not know for sure. Here is the function in context of the C++ code:

//all of this is above main
extern "C" uint32_t getQuad(uint16_t, uint16_t);
TS_DISCO_F429ZI ts; //touch screen sensing object
TS_StateTypeDef TS_State;
//other code here
ts.GetState(&TS_State); 
uint16_t x = TS_State.X;
uint16_t y = TS_State.Y;
uint32_t quad = getQuad(x, y);

And here is the function in the assembly file

                AREA Program3_F20_Gibbs, CODE, READONLY
                GLOBAL getQuad
                ; uint32_t getQuad ( uint16_t x, uint16_t y)
getQuad         LDR R0, [R0]
                LDR R1, [R1]
                
                CMP R0, #120
                BLE TwoThree
                
                CMP R1, #160
                BLE Four
                MOV R0, #1
                BX LR
                
TwoThree        CMP R1, #160
                BLE Three
                MOV R0, #2
                BX LR
        
Four            MOV R0, #4
                BX LR
        
Three           MOV R0, #3
                BX LR

I should probably also note that this quadrant system follows an x/y coordinate system with a bit of difference. Quadrant one has x/y coordinates with x > 120 and y > 160, Quadrant two has x/y coordinates with x < 120 and y > 160, Quadrant three has x/y coordinates with x < 120 and y < 160, and Quadrant four has x/y coordinates with x > 120 and y < 160. If I need to give any more info, please let me know, and thank you for any help in advance!

Upvotes: 0

Views: 109

Answers (2)

You can get away without any (conditional) branch:

getQuad
    cmp     r0, #120
    adr     r12, %f1
    addls   r12, r12, #2
    cmp     r1, #160
    addls   r12, r12, #1

    ldrb    r0, [r12]
    bx      lr

1
    dcb 1, 4, 2, 3

You really don't need to write it in assembly:

static inline uint32_t getQuad(uint16_t x, uint16_t y)
{
    static const uint8_t array[4] = {1, 4, 2, 3};
    uint8_t *pSrc = array;

    if (x <= 120) pSrc += 2;
    if (y <= 160) pSrc += 1;

    return (uint32_t) *pSrc;
}

It's a very short function, hence you better inline it, and put it in the header file.
The pesky function call overhead is gone then.

PS: le (less of equal) is for signed value. You should us ls (lower or same) instead. le works in this case, but if you are dealing with 32bit values, it could cause disastrous problems that are hard to debug.

Upvotes: 2

paxdiablo
paxdiablo

Reputation: 882206

Your logic seems sound except for the fact there should be some <= type operations in the text:

Quadrant one has x/y coordinates with x > 120 and y > 160, Quadrant two has x/y coordinates with x <= 120 and y > 160, Quadrant three has x/y coordinates with x <= 120 and y <= 160, and Quadrant four has x/y coordinates with x > 120 and y <= 160.

However, unless the calling convention is very strange, you probably don't want to be doing this at the start:

LDR R0, [R0]
LDR R1, [R1]

This is what you do if you're passing the addresses of variables and you want to dereference those addresses to get the values. Therefore you will be using the wrong values to figure out which quadrant you're in.

Upvotes: 1

Related Questions