Shop OBEX P1 Docs P2 Docs Learn Events
JMPREL — Parallax Forums

JMPREL

I'm working on a little program that uses a state variable to jump to specific handlers:

loop                    jmprel    state
                        jmp       state_0
                        jmp       state_1
                        jmp       state_2
                        jmp       state_3 

At the top of each state handler the code looks to see if it should run based on an IO pin assignment -- if the associated pin # is negative the state doesn't run. The active pins do not change, so is there way way that I can check all of the pins in use and modify how the jump code works?

Comments

  • evanhevanh Posts: 16,234

    That description sounds more like a bit mask than a state select. Each pin controls one function each, right?

  • JonnyMacJonnyMac Posts: 9,225
    edited 2025-01-25 17:07

    Well, it is setup like a simple state machine that will iterate through each of the possible IO pins; if a pin is used, a handler is called. My simple framework is fine, I was just wondering if there was a more elegant way to gate the JMPREL part.

    This better illustrates the framework.

                            neg       state, #1
    
    next_state              incmod    state, #3
                            jmprel    state
                            jmp       state_0
                            jmp       state_1
                            jmp       state_2
                            jmp       state_3
    
    check_0                 testb     s0pin, #31            wc      ' state 0 pin used?
            if_nc           call      s0_handler                    ' if yes, run code for s0pin
                            jmp       #next_state 
    
  • evanhevanh Posts: 16,234

    For a jump table, JMPREL is perfectly tidy. And as long as the table is located in cog address space then a double branch like that is efficient too.

    I once chose to make an alternative, using a 16-bit table, because all the target routines were also located in cog address space.

            getnib  pb, cmdaddr, #7    ' first 4 bits is command
            altgw   pb, #cmdjmp        ' lookup table of 16-bit pointers
            getword pb
            jmp pb
    
    cmdjmp
        word    cs_low          ' CMD0  - Probably a null-command due to CS low unintentionally
        word    queryconfig     ' CMD1  - QueryFeatures
        word    cs_low          ' CMD2
        word    cs_low          ' CMD3
        word    readblock       ' CMD4  - BlockRead
        word    writeblock      ' CMD5  - BlockWrite
        word    rdwrblock       ' CMD6  - BlockReadWrite
        word    cs_low          ' CMD7
        word    cs_low          ' CMD8
        word    cs_low          ' CMD9
        word    cs_low          ' CMD10
        word    cs_low          ' CMD11
        word    cs_low          ' CMD12
        word    cs_low          ' CMD13
        word    cs_low          ' CMD14
        word    cs_low          ' CMD15
    
  • Do you know the used pins at compile time? In this case the new #ifdef could be used?

    If the decision must be made at run time:
    In my 4-axis stepper driver I work a lot with tables. One table could hold the flags "is used" a second table could hold the addresses of the driver routines. Or perhaps combined zero for unused. So you can iterate with a loop.

  • JonnyMacJonnyMac Posts: 9,225

    Do you know the used pins at compile time? In this case the new #ifdef could be used?

    No; the app sets those pins as required.

    Thanks for the feedback, guys.

  • You could create a bitfield of all enabled pins. Then you can simply do a TESTB on that and skip jumping around if the pin is disabled.

  • JonnyMacJonnyMac Posts: 9,225
    edited 2025-01-26 00:41

    I had thought about that too, but on reading you comment I think I caught myself wanting to be clever when it's not necessary. This is simple and does the trick (I use this in my normal serial code).

    pri test_loop(p0, p1, p2, p3, p4)  
    
      org
    
    .main                   waitx     ##CLK_FREQ
    
                            testb     p0, #31               wc 
            if_nc           call      #.state0
                            testb     p1, #31               wc 
            if_nc           call      #.state1
                            testb     p2, #31               wc 
            if_nc           call      #.state2
                            testb     p3, #31               wc 
            if_nc           call      #.state3
                            testb     p4, #31               wc 
            if_nc           call      #.state4
                            jmp       #.main
    
    
    .state0                 debug("State 0 (RX0)")
                            ret
    
    .state1                 debug("State 1 (TX0)")
                            ret                       
    
    .state2                 debug("State 2 (RX1)")
                            ret
    
    .state3                 debug("State 3 (TX1)")
                            ret
    
    .state4                 debug("State 4 (DMX)")
                            ret       
    
      end
    

    Given the way DMX works a state machine is required there (I have that working) -- I think just dragged the state machine idea into the main part of the program. Simple is best.

  • If you're not pinching at every cycle and byte, yeah, do the simpler thing :smile:

  • evanhevanh Posts: 16,234

    @JonnyMac said:

    .main
                            testb     p0, #31               wc 
            if_nc           call      #.state0
                            testb     p1, #31               wc 
            if_nc           call      #.state1
                            testb     p2, #31               wc 
            if_nc           call      #.state2
                            testb     p3, #31               wc 
            if_nc           call      #.state3
                            testb     p4, #31               wc 
            if_nc           call      #.state4
                            jmp       #.main
    

    Round robin task switching.

Sign In or Register to comment.