Inline Assembler: 'bx(lr)' raises TypeError

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
MicroP_W691
Posts: 10
Joined: Mon Mar 09, 2020 10:47 am

Inline Assembler: 'bx(lr)' raises TypeError

Post by MicroP_W691 » Thu Oct 15, 2020 8:10 am

Hi, not sure what I'm doing wrong here, but I've been trying to use the inline assembler to process data coming in at a high rate. I have some very basic knowledge of assembly having written a few assembly functions to speed up timing-critical sections of C-Code before on embedded platforms, but I wouldn't go as far as to say I'm experienced.

I have followed examples in the documentation (which was surprisingly clear and well documented so Kudos), however i keep getting a type error if I add the

Code: Select all

bx(lr)
function to return from the subroutine. This is some psuedo-code to demonstrate the flow of my function:

Code: Select all

TRUE = const(1)
@micropython.asm_thumb
def asm_process(r0, r1, r2):
    vldr(s1, [r2, 4])       # Start Bit
    vcvt_s32_f32(s0, s0)
    vldr(s2, [r2, 8])       # length
    vcvt_s32_f32(s1, s1)
    vldr(s3, [r2, 12])      # scaling
    vldr(s4, [r2, 16])      # wrong_format_flag
   
    mov(r4, TRUE) # required as vmov requires register not constant
    vmov(s10, r4)
    b(START)

    label(CONVERT)
    push({lr}) # push to stack for inner loop
    add(r4, r0, r1) 
    sub(r4, 1)
    label(CONVERTLOOP)
    #convert data format code
    cmp(r4, r0) #check how many bytes left to convert
    bpl(CONVERTLOOP)
    pop({lr})
    bx(lr) #TypeError: function doesn't take keyword arguments
    # b(MAINPROCESS)

    label(START)
    vcmp(s4, s10) #check if flag set
    vmrs(APSR_nzcv, FPSCR) #move comparison from FPU
    beq(CONVERT)
    label(MAINPROCESS)
    #rest of code
If I add the 'bx(lr)' then I get:

Code: Select all

TypeError: function doesn't take keyword argument
However, if I comment that out and instead uncomment out the line below(directly going to that branch) then it doesn't raise the type error. I tried the Fibonacci example from the documentation http://docs.micropython.org/en/latest/r ... _tips.html and that works fine, including the 'bx(lr)' instruction so it must be my code.
I assume I'm doing something obviously wrong, but I just can't work out what it is! Any help would be hugely appreciated.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Inline Assembler: 'bx(lr)' raises TypeError

Post by pythoncoder » Thu Oct 15, 2020 9:18 am

I can't see anything obviously wrong. In my DFT code there are numerous instances of popping registers and issuing bx(lr).

I wonder if the error message is in some way misleading about which line has a problem. It might be worth putting some dummy instructions before the bx(lr) to see if the message changes. Clutching at straws here, mind...
Peter Hinch
Index to my micropython libraries.

MicroP_W691
Posts: 10
Joined: Mon Mar 09, 2020 10:47 am

Re: Inline Assembler: 'bx(lr)' raises TypeError

Post by MicroP_W691 » Thu Oct 15, 2020 10:08 am

I tried adding some random add and sub instructions between the pop({lr}) and the bx(lr) but unfortunately, this didn't make a difference. The Traceback doesn't tell me what line it failed on (reports the line where the function is called), so I only worked out it was that line by commenting out the instructions until I found that line as the source.

If I comment out that line with bx(lr), add a new label in the place where I want to return to called 'MAINPROCESS' and instead use b(MAINPROCESS) to jump back to that point (instead of the Link Register), then it all works. It just seems to be whenever that bx(lr) is called that it fails.

What specifically does the 'bx()' instruction do differently than just b(LABEL)? Is it just that it jumps to a specific address rather than a label?

EDIT: I also tried bx(r14) instead of lr (which I assume the compiler just swaps out anyway but thought it was worth a try) and I get the same error

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Inline Assembler: 'bx(lr)' raises TypeError

Post by pythoncoder » Thu Oct 15, 2020 12:48 pm

b(LABEL) is a jump to an absolute address whereas bx(lr) is an indirect jump where the address is specified by the register contents. Hence its use in returning from subroutines, where the return address will vary depending on where the subroutine was called from. Note that if you're returning using bx(lr) you must call it with bl(LABEL) which stores the return address in lr otherwise it will disappear up its own fundament.

It's going to be hard to offer any support here unless you can strip the code down to a minimum test case which exhibits the fault. I really don't think there's a problem with bx(lr) per se. There may well be a problem with the inline assembler's error reporting, but it's not one I've encountered.
Peter Hinch
Index to my micropython libraries.

MicroP_W691
Posts: 10
Joined: Mon Mar 09, 2020 10:47 am

Re: Inline Assembler: 'bx(lr)' raises TypeError

Post by MicroP_W691 » Mon Oct 19, 2020 7:45 am

Thank you, your reply helped me see where I was going wrong. I was using a comparison branch instruction instead of bl, so the link register wasn't being stored at the point where I branched off. For anyone else stumbling upon this post with the same issue, to resolve this:

I was originally using this (simplified example) to check if a flag was set to 1:

Code: Select all

cmp(r0, 1) #r0 is flag
beq(CONVERT) 
#then trying to jump back later with
bx(lr)
Instead, as per @pythoncoder's advice, this worked for me:

Code: Select all

cmp(r0, r1)
it(eq)
bl(CONVERT)
#able to jump back afterwords wth bx(lr)
Perhaps the TypeError: function doesn't take keyword argument error message is a bit misleading as bx(lr) is a valid instruction (even if nothing stored there), but at the end of the day I was doing something wrong so it's my error.

Thank you for your help.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Inline Assembler: 'bx(lr)' raises TypeError

Post by pythoncoder » Mon Oct 19, 2020 4:14 pm

The error message is odd. Perhaps the branch to an unknown (but presumably deterministic) location took you to some error trapping code in the firmware. Odd that you even got a REPL. When I make that kind of mistake the usual outcome is a hard crash. ;)
Peter Hinch
Index to my micropython libraries.

Post Reply