diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,236 @@ + + + + + +State +MachinesDescription of the structure and operation of state machines. +

The MultiMediaCard Controller uses state machines to manage the interactions +with the MultiMediaCard hardware.

+

State machines allows the controller to maintain the state of each submitted +session – allowing it to schedule a second session when the first becomes +blocked, for example.

+

To handle the complex sequence of bus operations involved, the controller +implements a state machine stack, allowing a parent state machine function +to invoke a child state machine function. The state machine stack allows nesting +of children down to a depth of 10 levels.

+

Each session object has its own individual state machine stack because +each session runs its own sequence of bus operations, with the controller +managing these multiple sequences. This means that each session object has +a state machine object, an instance of the TMMCStateMachine class.

+ + + +

The state machine remembers the next state and child function name, and +moves to that state as soon as control returns to the session.

+

The stack chooses the next session to be handled and manages the state +machine through the state machine dispatcher.

+ +
Structure of +the state machine stack

The stack itself is represented as an array +of TMMCMachineStackEntry objects contained within the state +machine object TMMCStateMachine.

The state machine +maintains a "pointer", TMMCStateMachine::iSP, to the current +state entry. This is not a true pointer, but just a value that indexes into +the array. However, for all practical purposes it has the effect of a pointer. +Each state entry in the stack is thought of as having a parent-child relationship +with the other.

Each state entry maintains three pieces of information:

    +
  • A pointer to the state +machine function.

  • +
  • A variable containing +the current state; the value and meaning of the state is defined by the state +machine function.

  • +
  • A bitmask of TMMCErr defined +error conditions; these are set by the parent state machine function so that +it gets the chance to trap those errors if the child state machine function +returns those errors. Errors are propagated up the stack, and any error conditions +not trapped at any level in the state machine hierarchy leads to the state +machine terminating with that error value.

  • +
+ +

In general, the overall state of the state machine reflects the +state of the current state entry; for example, TMMCStatemachine::State() returns +the state held in the current state entry.

While the flow of control +through a stack can be complex, the following diagram shows a short example +snapshot. Here, the current state in the current stack entry is Sn and +is handled by the function PF(). The code decides to pass +control to the child function CF(), but ensures that, on +completion, the next state in the current stack entry will be Sn+1.

+ +

For example, the DMMCStack::CIMUpdateAcqSM() function +implements the CIM_UPDATE_ACQ macro as defined by the MultiMediaCard System +Specification, and is a typical state machine function.

Most commands +and macros involve one or more asynchronous operations and while such operations +are outstanding, a session is blocked. While a session is blocked, its state +machine dispatch function is not called. As soon an asynchronous event removes +the blocking condition, control returns to the state machine.

+
Structure of +a state machine function

State machine functions are defined and +implemented in the DMMCStack class in pairs: one as a static +function, and the other as a member function. The static variant takes a TAny* pointer +that is cast to a DMMCStack pointer, and the DMMCStack member +function is then called:

TMMCErr DMMCStack::FunctionNameSMST( TAny* aPtr ) + { + return( STATIC_CAST(DMMCStack*,aPtr)->FunctionNameSM() ); + } + TMMCErr DMMCStack::FunctionNameSM() + { + enum states {EStBegin=0, EStNext,…, EStEnd }; // Enumeration of states for this state machine + DMMCSession& s = Session(); + + SMF_BEGIN + // State EStBegin + // Actions for state EStBegin + + SMF_STATE( EStNext ) + // State EStNext + // Actions for state EStNext + + SMF_END + } +

A state machine function can release control and wait to be +re-entered by returning zero. If its session is not blocked then that will +happen immediately. If the state machine function returns non-zero, the session +will be completed with that error code unless the parent state machine function +has explicitly intercepted such an error by setting the trap mask.

    +
  • Important points to note

  • +
  • Blocking on an asynchronous request

  • +

Important points to note

Each +state machine function must define a list of states that can exist. States +are defined as an enumeration whose first and last values must be labelled EStBegin and EStEnd, +respectively. EStBegin must have the value zero. Any other +intermediate states are program defined.

To make the state machine +functions more readable, a number of macros exist to help with the layout +of the function code, and to control program flow. The most basic macros are SMF_BEGIN, SMF_STATE and SMF_END that expand into a switch statement. The above code expands +to:

TMMCErr DMMCStack::FunctionNameSM() +{ +enum states {EStBegin=0, EStNext,…, EStEnd }; // Enumeration of states for this state machine +DMMCSession& s = Session(); + +TMMCStateMachine& m = Machine(); //SMF_BEGIN +const TMMCErr err = m.SetExitCode( 0 ); //SMF_BEGIN +for(;;) //SMF_BEGIN + { //SMF_BEGIN + switch(m.State()) //SMF_BEGIN + { //SMF_BEGIN + case EStBegin: //SMF_BEGIN + { //SMF_BEGIN + if(err) (void)0; //SMF_BEGIN + // State EStBegin + // Actions for state EStBegin + + } //SMF_STATE + case EStNext: //SMF_STATE + { //SMF_STATE + // State EStNext + // Actions for state EStNext + + case EStEnd: //SMF_END + break; //SMF_END + default: //SMF_END + DMMCController::Panic(DMMCController::EMMCMachineState);//SMF_END + } //SMF_END + break; //SMF_END + } //SMF_END +return(m.Pop()); //SMF_END +}

Notes:

    +
  • be aware that SMF_BEGIN +generates an open curly bracket while SMF_STATE generates a corresponding +close bracket, and SMF_END closes the switch statement.

  • +

You need to be aware of the code that is generated by these macros. +In particular, some such as SMF_BEGIN generate an opening curly brace, while +others such as SMF_STATE generate a corresponding close curly brace. Also, +you need to know whether a macro generates a break; or a return; statement. +Lack of awareness here may cause code to be generated that flows from one +case statement to another, which may not be your intent.

    +
  • SMF_BEGIN

  • +
  • SMF_END

  • +
  • SMF_NEXTS

  • +
  • SMF_CALL

  • +
  • SMF_CALLWAIT

  • +
  • SMF_CALLMYS

  • +
  • SMF_CALLMEWR

  • +
  • SMF_INVOKES

  • +
  • SMF_INVOKEWAITS

  • +
  • SMF_WAIT

  • +
  • SMF_WAITS

  • +
  • SMF_RETURN

  • +
  • SMF_EXIT

  • +
  • SMF_EXITWAIT

  • +
  • SMF_JUMP

  • +
  • SMF_JUMPWAIT

  • +
  • SMF_GOTONEXTS

  • +
  • SMF_GOTOS

  • +
  • SMF_STATE

  • +
  • SMF_BPOINT

  • +

Blocking on an asynchronous +request

The state machine can be made to block. This is done so +that you can wait for an asynchronous operation to complete. When the operation +completes, it unblocks the state machine. There are two stages to blocking +a state machine:

    +
  • Call DMMCStack::BlockCurrentSession() to +indicate that the state machine associated with the current session is to +be blocked

  • +
  • Execute one of the SMF_xxxWAIT +macros to return from the current state machine function and wait.

  • +

Note that the state machine function must return by calling +one of the SMF_xxxWAIT macros. It must not poll or sit in a loop! The state +machines are not threaded, and this means that CPU time can only be given +to other tasks if the function returns.

DMMCStack::BlockCurrentSession() takes +an argument describing the type of block. The state machine will only unblock +when an unblock request with the matching argument is called. In the platform +specific layer of the MultiMediaCard controller, you should always set the KMMCBlockOnASSPFunction bit +in the argument passed to BlockCurrentSession().

To +unblock the state machine, call DMMCStack::UnBlockCurrentSession() setting +the KMMCBlockOnASSPFunction bit in the flags argument passed +to the function, and also an error code. This will invoke the state machine +scheduler, which will re-start the state machine.

Note that further +state machine processing must take place in a DFC rather than within the interrupt +service routine (ISR), and this can be forced by ORing the session status, DMMCSession::iState, +with the KMMCSessStateDoDFC bit before unblocking +the session. The bit has the effect of queueing a DFC to resume the state +machine at some later stage, before returning to the ISR.

The following +code shows the idea:

TMMCErr DMMCStackAssp::DoSomethingSM() + { + enum states {EStBegin=0, EStDone,EStEnd }; // enumeration of states for this state machine + + SMF_BEGIN + // start the asynchronous operation + BlockCurrentSession( KMMCBlockOnASSPFunction ); + StartAsynchronousOp(); + + // block and wait. Go to state EStDone when the asynchronous op is complete + SMF_WAITS( EStDone ); + + SMF_STATE( EStDone ) + // operation is complete, check for errors and return from state machine + TInt errors = CheckForHardwareErrors(); + SMF_RETURN( errors ); + + SMF_END + } + void TMMCInterrupt::Service( TAny* aParam ) + { + Session().iState |= KMMCSessStateDoDFC; + UnBlockCurrentSession(KMMCBlockOnASSPFunction, KMMCErrNone); + } +
+
Example of +a state machine calling sequence

This shows the state machine calling +sequence that implements the reading of a single block on a MultiMediaCard, +where the card is not yet selected. Note that the lowest level state machine +function called is IssueMMCCommandSM(), which is implemented +by the base port.

+ +
+
\ No newline at end of file