• AVR Freaks

Hot!Trying to make a fast state machine (mixed ASM and C)

Page: 1234 > Showing page 1 of 4
Author
davea
Super Member
  • Total Posts : 500
  • Reward points : 0
  • Joined: 2016/01/28 13:12:13
  • Location: Tampa Bay FL USA
  • Status: offline
2020/10/08 20:53:47 (permalink)
0

Trying to make a fast state machine (mixed ASM and C)

void DO_STATE(void) {
    Bank_save = BSR;
    asm("BANKSEL _S_state ");
    asm("MOVF _S_state,W ");
    asm("BRW ");
// asm("goto _ST_0 "); // undefined symbol "_ST_0"
    goto ST_0;
    goto ST_1;
    goto ST_2;
    goto ST_3;
ST_0:
    LATCbits.LATC5 = 0;
    ++S_state;
    goto END_STATE;
ST_1:
    LATCbits.LATC5 = 1;
    ++S_state;
    goto END_STATE;
ST_2:
    LATCbits.LATC5 = 0;
    ++S_state;
     goto END_STATE;
ST_3:
    LATCbits.LATC5 = 1;
    S_state = 0;
END_STATE:
    asm("BANKSEL _Bank_save ");
    asm("MOVF _Bank_save, W ");
    asm("MOVWF BSR ");
}

i have tried every I could think of.... 
disassembly shows it's wacked
and I might be too
davea
#1

73 Replies Related Threads

    ric
    Super Member
    • Total Posts : 28941
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/08 21:20:36 (permalink)
    0
    It's pointless trying to preserve BSR.
    As soon as the compiler sees inline assembly, it assumes BSR is trashed, and reloads it on the next SFR access.
    Examine the assembly output from
    void DO_STATE(void)
    {
        switch (S_state)
        {
            case 0:
                LATCbits.LATC5 = 0;
                ++S_state;
                break;

            case 1:
                LATCbits.LATC5 = 1;
                ++S_state;
                break;

            case 2:
                LATCbits.LATC5 = 0;
                ++S_state;
                break;

            default:
                LATCbits.LATC5 = 1;
                S_state = 0;
                break;
        }
    }


    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #2
    davea
    Super Member
    • Total Posts : 500
    • Reward points : 0
    • Joined: 2016/01/28 13:12:13
    • Location: Tampa Bay FL USA
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/08 21:46:26 (permalink)
    0
    Yes, that is normally how I do it
    but there are about 25 instructions used to do it that way
    asm("BRW "); seams like good way as long the states 0 to 10 or so are used
    PIC16LF15323
    is this a no win situation ?
    was unsure about BSR
     
     
    #3
    ric
    Super Member
    • Total Posts : 28941
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/08 21:57:36 (permalink)
    0
    Are you in free mode?
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #4
    davea
    Super Member
    • Total Posts : 500
    • Reward points : 0
    • Joined: 2016/01/28 13:12:13
    • Location: Tampa Bay FL USA
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/08 22:01:27 (permalink)
    0
    was in mode 3
    and tried mode 0 
    still no link to ST_X:
    in ASM or C
    post edited by davea - 2020/10/08 22:02:30
    #5
    davea
    Super Member
    • Total Posts : 500
    • Reward points : 0
    • Joined: 2016/01/28 13:12:13
    • Location: Tampa Bay FL USA
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/08 23:21:31 (permalink)
    0
    void DO_STATE(void) {
        asm("BANKSEL _S_state ");
        asm("MOVF _S_state,W ");
        asm("BRW ");
        asm("goto ST_0 "); this is OK
    // asm("goto ST_1 "); undefined symbol "ST_1" !!!!!!!!!!!!!!!!
    // asm("goto ST_2 ");
    // goto ST_0;
    // goto ST_1;
    // goto ST_2;
    // goto ST_3;
    asm("ST_0: ");
    ST_0:
        LATCbits.LATC5 = 0;
        ++S_state;
        goto END_STATE;
    asm("ST_1: ");
    ST_1:
        LATCbits.LATC5 = 1;
        ++S_state;
        goto END_STATE;
    what I have found 
    the goto table must be in ASM 
    as C warns any after the first 1 as unreachable
     
    #6
    ric
    Super Member
    • Total Posts : 28941
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 00:18:16 (permalink)
    0
    I assume in reality you want to put more C code in each state. Will there really be 4 states, or do you want to allow for any number?
    If the code will simply update output pins, you could save a lot of bank swift hing by forcing the state variables into bank 2 (unless this this us a device with LAT registers in bank 0)

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #7
    dan1138
    Super Member
    • Total Posts : 3990
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 00:32:25 (permalink)
    +1 (1)
    @davea,
     
    I got this to work:
    /*
     * File:   main.c
     * Author: dan1138
     * Target: PIC16LF15323
     *
     * Created on October 8, 2020, 10:08 PM
     */
    #pragma config FEXTOSC = OFF, RSTOSC = HFINT32, CLKOUTEN = OFF, CSWEN = ON
    #pragma config FCMEN = OFF, MCLRE = ON, PWRTE = OFF, LPBOREN = OFF
    #pragma config BOREN = OFF, BORV = LO, ZCD = OFF, PPS1WAY = OFF, STVREN = ON
    #pragma config WDTCPS = WDTCPS_31, WDTE = OFF, WDTCWS = WDTCWS_7, WDTCCS = SC
    #pragma config BBSIZE = BB512, BBEN = OFF, SAFEN = OFF, WRTAPP = OFF
    #pragma config WRTB = OFF, WRTC = OFF, WRTSAF = OFF, LVP = ON, CP = OFF

    #include <xc.h>

    volatile unsigned char NextState = 0;

    void State_0(void)
    {
        NextState++;
    }
    void State_1(void)
    {
        NextState++;
    }
    void State_2(void)
    {
        NextState++;
    }
    void State_3(void)
    {
        NextState++;
    }
    void State_4(void)
    {
        NextState++;
    }
    void State_5(void)
    {
        NextState = 0;
    }

    void StateRun(void)
    {
        WREG = NextState;
    __asm("BANKSEL NVMADRL");
    __asm("MOVWF   NVMADRL");
    __asm("CLRF    NVMADRH");
    __asm("MOVLW   0xFf&(State_Table)");
    __asm("ADDWF   NVMADRL,1");
    __asm("MOVLW   0xFF&(State_Table>>8)");
    __asm("ADDWFC  NVMADRH,1");
    __asm("BCF     NVMCON1,6");
    __asm("BSF     NVMCON1,0");
    __asm("MOVF    NVMDATH,0");
    __asm("MOVWF   PCLATH");
    __asm("MOVF    NVMDATL,0");
    __asm("MOVWF   PCL");

    __asm("State_Table:");
    __asm("dw _State_0");
    __asm("dw _State_1");
    __asm("dw _State_2");
    __asm("dw _State_3");
    __asm("dw _State_4");
    __asm("dw _State_5");
    }

    void main(void)
    {
        for(;;)
        {
            StateRun();
        }
        /* Make compiler stop complaining about functions not called */
        State_0();State_1();State_2();State_3();State_4();State_5();
    }

    But I think it is a real bad hack.
    #8
    1and0
    Access is Denied
    • Total Posts : 11501
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 01:34:19 (permalink)
    +2 (2)
    The PIC16LF15323 has only one page of program memory. Do this:
    #pragma config FEXTOSC = OFF, RSTOSC = HFINT32, CLKOUTEN = OFF, CSWEN = ON
    #pragma config FCMEN = OFF, MCLRE = ON, PWRTE = OFF, LPBOREN = OFF
    #pragma config BOREN = OFF, BORV = LO, ZCD = OFF, PPS1WAY = OFF, STVREN = ON
    #pragma config WDTCPS = WDTCPS_31, WDTE = OFF, WDTCWS = WDTCWS_7, WDTCCS = SC
    #pragma config BBSIZE = BB512, BBEN = OFF, SAFEN = OFF, WRTAPP = OFF
    #pragma config WRTB = OFF, WRTC = OFF, WRTSAF = OFF, LVP = ON, CP = OFF

    #include <xc.h>
    #include <stdint.h>

    volatile uint8_t NextState = 0;

    void State_0(void)
    {
        NextState++;
    }
    void State_1(void)
    {
        NextState++;
    }
    void State_2(void)
    {
        NextState++;
    }
    void State_3(void)
    {
        NextState = 0;
    }

    void StateRun(void)
    {
        WREG = NextState;
        asm("brw          ");
        asm("goto _State_0");
        asm("goto _State_1");
        asm("goto _State_2");
        asm("goto _State_3");
    }

    void main(void)
    {
        while(1) {
            StateRun();
        }
    }

    #9
    NorthGuy
    Super Member
    • Total Posts : 6404
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 06:22:08 (permalink)
    0
    XC8 should be able to build a jump table from the switch statement automatically. If I remember correctly, they have pragmas to select a particular type of switch generation.
     
    It will be faster if in your store the destination function offset directly in your state variable (as opposed to storing an offset to the table). Then you can pass it directly to BRW. This way you don't need a table and save one extra indirection - two instruction clocks. The C equivalent to this approach is a function pointer (as opposed to a switch statement).
    #10
    1and0
    Access is Denied
    • Total Posts : 11501
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 07:06:46 (permalink)
    +1 (1)
    NorthGuy
    XC8 should be able to build a jump table from the switch statement automatically. If I remember correctly, they have pragmas to select a particular type of switch generation.

    There is but I've not been able to get it to work in Free mode; it's must be a feature of the Pro mode. :(
     

    It will be faster if in your store the destination function offset directly in your state variable (as opposed to storing an offset to the table). Then you can pass it directly to BRW. This way you don't need a table and save one extra indirection - two instruction clocks.

    To do that, ALL the state functions would have to be located within the next 256 addresses.
    #11
    NorthGuy
    Super Member
    • Total Posts : 6404
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 07:22:22 (permalink)
    +1 (1)
    1and0
    To do that, ALL the state functions would have to be located within the next 256 addresses.



    Of course, but this is usually not a problem. If you're trying to do something fast then your processing functions are typically very short.
     
    If you have a few big ones, you can insert a "goto" within the 256 addresses which will take you to the function itself. Since the function is big, the processing time is likely not to be very important for this particular function. This will not affect fast short functions.
    #12
    1and0
    Access is Denied
    • Total Posts : 11501
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 07:41:27 (permalink)
    +1 (1)
    NorthGuy
    Of course, but this is usually not a problem. If you're trying to do something fast then your processing functions are typically very short.
     
    If you have a few big ones, you can insert a "goto" within the 256 addresses which will take you to the function itself. Since the function is big, the processing time is likely not to be very important for this particular function. This will not affect fast short functions.

    It's easy with pure assembly, but I'm not so sure in C as I've never tried this. It seems to be lot of trouble in C to save one instruction cycle. Remember, you save two cycles on the jump but spend one more cycle on assigning the state variable; i.e. INCF vs MOVLW/MOVWF. Also, that GOTO on the big ones will negate this.
     
    <edit> Well, I'm assuming "state_var++" compiles to an INCF. I've seen Free mode does this: MOVLW 1; MOVWF fubar; MOVF fubar,w; ADDWF state_var. :(
     
    post edited by 1and0 - 2020/10/09 07:47:18
    #13
    NorthGuy
    Super Member
    • Total Posts : 6404
    • Reward points : 0
    • Joined: 2014/02/23 14:23:23
    • Location: Northern Canada
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 08:19:09 (permalink)
    0
    1and0
    It's easy with pure assembly, but I'm not so sure in C as I've never tried this.

     
    Of course. It's often easier to get rid of C and do everything in assembler.
     
    1and0
    Remember, you save two cycles on the jump but spend one more cycle on assigning the state variable; i.e. INCF vs MOVLW/MOVWF.

     
    Yes, that's true. However, you don't necessarily change the state variable on every pass.
    #14
    dan1138
    Super Member
    • Total Posts : 3990
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 09:12:14 (permalink)
    0
    @1and0, Thanks for the idea of using a "goto" state table.
     
    Here's a version that works for enhanced mig-range PIC16F1xxx with more than one code page:
    /*
     * File:   main.c
     * Author: dan1138
     * Target: PIC16LF18877
     *
     * Created on October 9, 2020, 9:45 AM
     */

    #pragma config FEXTOSC = OFF, RSTOSC = HFINT32, CLKOUTEN = OFF
    #pragma config CSWEN = ON, FCMEN = OFF, MCLRE = ON, PWRTE = OFF
    #pragma config LPBOREN = OFF, BOREN = OFF, BORV = LO, ZCD = OFF
    #pragma config PPS1WAY = OFF, STVREN = ON, WDTCPS = WDTCPS_31
    #pragma config WDTE = ON, WDTCWS = WDTCWS_7, WDTCCS = SC, WRT = OFF
    #pragma config SCANE = available, LVP = ON, CP = OFF, CPD = OFF

    #include <xc.h>

    volatile unsigned char NextState = 0;

    void __at(0x7800) State_0(void)
    {
        __asm("incf _NextState,1");
    }
    void __at(0x6800) State_1(void)
    {
        __asm("incf _NextState,1");
    }
    void __at(0x5800) State_2(void)
    {
        __asm("incf _NextState,1");
    }
    void __at(0x4800) State_3(void)
    {
        __asm("incf _NextState,1");
    }
    void __at(0x3800) State_4(void)
    {
        __asm("incf _NextState,1");
    }
    void __at(0x2800) State_5(void)
    {
        NextState = 0;
    }

    void StateRun(void)
    {
        WREG = NextState;
    /* check that WREG selects an element within the state table */
    __asm("SUBLW (State_TableFirstState-State_TableLastState)/(State_TableFirstState-State_TableNextState)");
    __asm("btfss STATUS,0");
    __asm("bra   State_TableEerror");
    __asm("addwf WREG,1");
    __asm("brw         ");
    __asm("State_TableLastState:  movlp (_State_5>>8)\n goto 0x7ff&_State_5");
    __asm("                       movlp (_State_4>>8)\n goto 0x7ff&_State_4");
    __asm("                       movlp (_State_3>>8)\n goto 0x7ff&_State_3");
    __asm("                       movlp (_State_2>>8)\n goto 0x7ff&_State_2");
    __asm("State_TableNextState:  movlp (_State_1>>8)\n goto 0x7ff&_State_1");
    __asm("State_TableFirstState: movlp (_State_0>>8)\n goto 0x7ff&_State_0");
    __asm("State_TableEerror:");
    /* When we get here the selected state was not in the state table */
    }

    void main(void)
    {
        for(;;)
        {
            StateRun();
        }
        /* Make compiler stop complaining about functions not called */
        State_0();State_1();State_2();State_3();State_4();State_5();
    }

    post edited by dan1138 - 2020/10/09 10:13:06
    #15
    1and0
    Access is Denied
    • Total Posts : 11501
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 09:21:44 (permalink)
    0
    dan1138

     
    __asm("State_TableLastState:  movlb (_State_5>>8)\n goto _State_5");
    __asm("                       movlb (_State_4>>8)\n goto _State_4");
    __asm("                       movlb (_State_3>>8)\n goto _State_3");
    __asm("                       movlb (_State_2>>8)\n goto _State_2");
    __asm("State_TableNextState:  movlb (_State_1>>8)\n goto _State_1");
    __asm("State_TableFirstState: movlb (_State_0>>8)\n goto _State_0");
    __asm("State_TableEerror:");


    Use MOVLP ;)
     
    <edit> For XC8, we can do this:
    __asm("State_TableLastState:  ljmp _State_5");

    <edit> Don't use LJMP, XC8 does double MOVLP for consecutive LJMP which is crazy.
     
    post edited by 1and0 - 2020/10/09 09:35:36
    #16
    1and0
    Access is Denied
    • Total Posts : 11501
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 09:39:58 (permalink)
    +1 (1)
    From what I briefly tested, it seems LJMP is a macro for
            movlp   high(target)
            goto    target
            movlp   high($)

    Go Figure!!!
    #17
    dan1138
    Super Member
    • Total Posts : 3990
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 10:06:50 (permalink)
    +1 (1)
    1and0
    From what I briefly tested, it seems LJMP is a macro for
            movlp   high(target)
     
            goto    target
     
            movlp   high($)
     

    Go Figure!!!



    It gets ugly when the target address is outside the 0x000-0x7FF range.
     
    The compiler complains about a "main.c:59:: error: (1357) fixup overflow storing 0x800 in 2 bytes at 0xFF4/0x2 -> 0x7FA (dist/default/debug\16F18877_StateMachine.X.debug.o 47/0x26)"
     
    This mean the "goto" needs a 0x7FF mask on the target address to compile.
    #18
    1and0
    Access is Denied
    • Total Posts : 11501
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 10:26:59 (permalink)
    0 (2)
    dan1138
    It gets ugly when the target address is outside the 0x000-0x7FF range.
     
    The compiler complains about a "main.c:59:: error: (1357) fixup overflow storing 0x800 in 2 bytes at 0xFF4/0x2 -> 0x7FA (dist/default/debug\16F18877_StateMachine.X.debug.o 47/0x26)"
     
    This mean the "goto" needs a 0x7FF mask on the target address to compile.

    Wow ... can't get any worse!  It's like the BANKMASK() for data memory address.  Is there a PAGEMASK() for program memory address? LoL: LoLLoL: LoLLoL: LoL
    #19
    dan1138
    Super Member
    • Total Posts : 3990
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Trying to make a fast state machine (mixed ASM and C) 2020/10/09 12:56:16 (permalink)
    0
    1and0
    dan1138
    It gets ugly when the target address is outside the 0x000-0x7FF range.
     
    The compiler complains about a "main.c:59:: error: (1357) fixup overflow storing 0x800 in 2 bytes at 0xFF4/0x2 -> 0x7FA (dist/default/debug\16F18877_StateMachine.X.debug.o 47/0x26)"
     
    This mean the "goto" needs a 0x7FF mask on the target address to compile.

    Wow ... can't get any worse!  It's like the BANKMASK() for data memory address.  Is there a PAGEMASK() for program memory address?

    Oh but it does get worse...
     
    There are assembler macros for BANKMASK() and PAGEMASK() but they are not available for inline assembly code in an XC8 C language source file.
     
    What is worse is that the "ljmp" directive is available, "BUT" it may or may not generate the "MOVLP" opcode if the compiler "knows" the part only has one code page.
     
    It just plain stupid for the compiler to add a "MOVLP" opcode after a "GOTO" statement.
    #20
    Page: 1234 > Showing page 1 of 4
    Jump to:
    © 2020 APG vNext Commercial Version 4.5