-2

I have a state diagram that I want to navigate through:

JTAG tap controller diagram

It got 6 steady states (states that only have 1 possible next states), and the rest of the states are used to move from state to state (2 possible next states). I want to write a function that takes in the current state and endstate, and returns a byte[] with the 0's and 1's that are used to move from start to end state. I want the method to find the fastest way to the destination as possible.

I've had some thoughts regarding how to solve this problem, but I haven't thought of a good (and preferably elegant) solution.

  1. A state can have either 1 or 2 next states - a state could be saved as a string array, where the next states are listed in the array (there might be a much better way to hold information of state/next state combinations, please enlighten me!)
  2. I might be able to find the end state through recursive functions, but I'm unsure how.
  3. Through Google searches on how to solve this problem, I've encountered Dijkstra's algorithm. It seems to me that this algorithm might not be useful in my scenario - or what?

I've thought about hardcoding it, but this makes the function awfully long. Surely there must be a smarter way to do this?

Any help will be much appreciated!

EDIT:

private STATE TapStateNext(STATE state, bool tms)
        {
            switch (tapState)
            {
                case STATE.TEST_LOGIC_RESET:
                    return tms ? STATE.TEST_LOGIC_RESET_B : STATE.RUN_TEST_IDLE;
                case STATE.TEST_LOGIC_RESET_B:
                    return tms ? STATE.TEST_LOGIC_RESET_A : STATE.RUN_TEST_IDLE;
                case STATE.RUN_TEST_IDLE:
                    return tms ? STATE.SELECT_DR_SCAN : state;
                case STATE.SELECT_DR_SCAN:
                    return tms ? STATE.SELECT_IR_SCAN : STATE.CAPTURE_DR;
                case STATE.SELECT_IR_SCAN:
                    return tms ? STATE.TEST_LOGIC_RESET_A : STATE.CAPTURE_IR;
                case STATE.CAPTURE_DR:
                    return tms ? STATE.EXIT1_DR : STATE.SHIFT_DR;
                case STATE.SHIFT_DR:
                    return tms ? STATE.EXIT1_DR : state;
                case STATE.EXIT1_DR:
                    return tms ? STATE.UPDATE_DR : STATE.PAUSE_DR;
                case STATE.PAUSE_DR:
                    return tms ? STATE.EXIT2_DR : state;
                case STATE.EXIT2_DR:
                    return tms ? STATE.UPDATE_DR : STATE.SHIFT_DR;
                case STATE.UPDATE_DR:
                    return tms ? STATE.SELECT_DR_SCAN : STATE.RUN_TEST_IDLE;
                case STATE.CAPTURE_IR:
                    return tms ? STATE.EXIT1_IR : STATE.SHIFT_IR;
                case STATE.SHIFT_IR:
                    return tms ? STATE.EXIT1_IR : state;
                case STATE.EXIT1_IR:
                    return tms ? STATE.UPDATE_IR : STATE.PAUSE_IR;
                case STATE.PAUSE_IR:
                    return tms ? STATE.EXIT2_IR : state;
                case STATE.EXIT2_IR:
                    return tms ? STATE.UPDATE_IR : STATE.SHIFT_IR;
                case STATE.UPDATE_IR:
                    return tms ? STATE.SELECT_DR_SCAN : STATE.RUN_TEST_IDLE;
                default:
                    throw new Exception("Illegal TAP controller state detected");
            }
        }
Ioragi
  • 105
  • 1
  • 10
  • You could use your option 2, employing a recursive back-tracking method. If you add information about how your diagram is represented in memory to the question, I might show a proposed pseudo-code solution. – 500 - Internal Server Error Apr 02 '20 at 08:28
  • The diagram is not represented in any way yet. I've read this document http://www.sommer.jp/aa10/aa8.pdf, but I don't have the required knowledge to use the information. If you have tips/ideas how to represent my graph in memory, I'll be all ears! – Ioragi Apr 02 '20 at 08:54
  • Perhaps something like `class Entry { int ZeroNext; int OneNext; }` and then `List diagram = new ...`. – 500 - Internal Server Error Apr 02 '20 at 09:00
  • Would I just start from any state (Test-Logic-Reset might be a good start?) and write weather a 0 or 1 is required to go to the next state? What about the ones with more than one next state? I apologize for my stupid questions, I'm really at loss here. – Ioragi Apr 02 '20 at 09:05
  • Yeah, I should have said `State` instead of `Entry`. `ZeroNext` would be the index of the state following this one for zero, `OneNext` would be the index of the following state for one. Does that help? – 500 - Internal Server Error Apr 02 '20 at 09:24
  • I think so - I've added a prepresentation of my diagram, where tms is a bool. Is that what I need? – Ioragi Apr 02 '20 at 10:50
  • Does [this](https://stackoverflow.com/a/9674800/9338645) address your problem, as it looks like a path traversal problem to me. Also look up the [A*-Algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm). – Chrᴉz remembers Monica Apr 02 '20 at 10:59
  • @ChrᴉzsaysreinstateMonica, I'm honestly not sure... I don't even understand the OP's problem :( – Ioragi Apr 02 '20 at 11:03
  • @Ioragi You are the OP and you don't understand your own problem? I don't understand the use of this, but you are the one that needs to tell us what you want to achieve. – Chrᴉz remembers Monica Apr 02 '20 at 11:05
  • I don't understand the OP's problem in the link you sent me. I understand my own problem. I can't tell if the link you sent me is able to resolve my problem. – Ioragi Apr 02 '20 at 11:06
  • @Ioragi The question in my link may be a bit science-wavy, but the solution I linked may fit your problem. I'd advice you to look up path traversal problems in general and see if they may solve your problem. The most prominet one there is the A*-algorithm with a example implementation on wikipedia. – Chrᴉz remembers Monica Apr 02 '20 at 11:09

2 Answers2

1

I ended up solving the problem this way:

class States_path
{
    public enum States
    {
        RESET,
        IDLE,
        DRSELECT,
        DRCAPTURE,
        DRSHIFT,
        DRPAUSE,
        DREXIT1,
        DREXIT2,
        DRUPDATE,
        IRSELECT,
        IRCAPTURE,
        IRSHIFT,
        IRPAUSE,
        IREXIT1,
        IREXIT2,
        IRUPDATE
    }

    private States NextState(States current_states, bool tms)
    {
        switch (current_states)
        {
            case States.RESET:
                return tms ? States.RESET : States.IDLE;
            case States.IDLE:
                return tms ? States.DRSELECT : current_states;
            case States.DRSELECT:
                return tms ? States.IRSELECT : States.DRCAPTURE;
            case States.IRSELECT:
                return tms ? States.RESET : States.IRCAPTURE;
            case States.DRCAPTURE:
                return tms ? States.DREXIT1 : States.DRSHIFT;
            case States.DRSHIFT:
                return tms ? States.DREXIT1 : current_states;
            case States.DREXIT1:
                return tms ? States.DRUPDATE : States.DRPAUSE;
            case States.DRPAUSE:
                return tms ? States.DREXIT2 : current_states;
            case States.DREXIT2:
                return tms ? States.DRUPDATE : States.DRSHIFT;
            case States.DRUPDATE:
                return tms ? States.DRSELECT : States.IDLE;
            case States.IRCAPTURE:
                return tms ? States.IREXIT1 : States.IRSHIFT;
            case States.IRSHIFT:
                return tms ? States.IREXIT1 : current_states;
            case States.IREXIT1:
                return tms ? States.IRUPDATE : States.IRPAUSE;
            case States.IRPAUSE:
                return tms ? States.IREXIT2 : current_states;
            case States.IREXIT2:
                return tms ? States.IRUPDATE : States.IRSHIFT;
            case States.IRUPDATE:
                return tms ? States.DRSELECT : States.IDLE;
            default:
                throw new Exception("Illegal state detected!");
        }
    }

    private bool[] statePath(States current, States end_state)
    {
        return StatePathRecurse(current, end_state, 0);
    }

    private bool[] StatePathRecurse(States current, States end_state,int recursions)
    {
        // Function must not recurse over the entire diagram
        if(++ recursions == Enum.GetNames(typeof(States)).Length)
        {
            // Send error in form of empty bool[]
            return new bool[0];
        }

        bool[] path_false = CheckNextState(false);
        bool[] path_true = CheckNextState(true);

        // Which path to return? 
        // No matter what, the arrays must be larger than 0 before we can return it.
        // In case both arrays are filled, we must find wich is shorter
        if((path_false.Length > 0) && (path_true.Length > 0))
        {
            // Find the shortest path
            return (path_false.Length > path_true.Length) ? path_true : path_false;

        }

        // In case only one of the arrays are filled
        else
        {
            return path_false;
        }


        bool[] CheckNextState(bool tms)
        {
            States next = NextState(current, tms);

            if (next == end_state)
            {
                // Search done, return the correct bool
                return new bool[1] { tms };
            }

            else if (next == current)
            {
                // Looping in the a stable state - this is an error. 
                return new bool[0];
            }

            else
            {
                // Not done with the search - keep recursing

                bool[] cont = StatePathRecurse(next, end_state, recursions);

                if (cont.Length == 0)
                {
                    // Error! Array must have a length
                    return cont;
                }

                else
                {
                    // Array ok - send back
                    bool[] result = new bool[1 + cont.Length];

                    // Adding the last recieved tms to result
                    result[0] = tms;

                    // Combining the recursive bool[] cont to the result
                    cont.CopyTo(result, 1);

                    return result;
                }
            }
        }
    }


}
Ioragi
  • 105
  • 1
  • 10
0

Your question isn't clear to me, but looking at your code I can see that you're having issues.

You're better to handle this as a Hierarchical State Machine.

DR Scan and IR scan paths are two versions of the same state machine.

Handling these both in one switch statement will be too cumbersome and you'll soon become lost in navigating it.

With a hierarchical state machine you can end up with a top level file that switches between your Test States - Reset Test, Test Idle and Run Test.

With polymorphism the Run Test state will then refer to either DR Scan or IR Scan state functions.

Your DR Scan and IR Scan code each resides within its own source file.

ChrisBD
  • 9,104
  • 3
  • 22
  • 35