/************************************************************************************ * smHostListProc.c * * synopsis: This state machine controls the receipt and execution of primitive * lists. It performs all necessary reads and writes of status and command * register bits. These registers are used to communicate the status of the * list processing to the processor which sent the list and are set and read * via calls to low level register access routines. This state machine * calls the routines in listManager.c, readListWrapper and execPrim, which * actually process the primitive list, execute the primitives and write * reply data. * * in this file: smHostListProc, setPausedByPrim, setPausedBySlave, rstPausedBySlave, * incAttendSlvReply, decAttendSlvReply * * related files: * listManager.c: Routines which process the primitive list. * listProc.h: Defines states of the primitive list processing state machines and * the indicies of the primitive and reply list buffer structures. * * * Damon Fasching, UW Madison (510)486-5230 fasching@wisconsin.cern.ch ************************************************************************************/ #include #include "resources.h" #include "listProc.h" #pragma CODE_SECTION(smHostListProc, "xcode"); #pragma CODE_SECTION(setPausedByPrim, "xcode"); #if defined(I_AM_MASTER_DSP) #pragma CODE_SECTION(setPausedBySlave, "xcode"); #pragma CODE_SECTION(rstPausedBySlave, "xcode"); #pragma CODE_SECTION(incAttendSlvReply, "xcode"); #pragma CODE_SECTION(decAttendSlvReply, "xcode"); #endif #define RESUME_BIT_TOGGLED (resumeBit != resumeBitSave) #if defined(I_AM_MASTER_DSP) #define PAUSE_REQUESTED (pauseRqst || pausedByPrim || pausedBySlave) #else #define PAUSE_REQUESTED (pauseRqst || pausedByPrim) #endif #define TERMINATE_EARLY (abortRqst || FATAL(returnCode)) /* file level variables */ UINT32 pausedByPrim= FALSE; UINT32 pausedBySlave= FALSE; UINT32 attendSlvReply= FALSE; UINT32 hostListState= IDLE; /************************************************************************************ * smHostListProc * * synopsis: Primitive list handling state machine. Calls routines which handle * processing of the primitive list. Takes care of communication with the * upstream processor which transmitted the list. * * modifications/bugs * - Added PAUSED state which is entered by setting the pause bit in the * command register or when a pauseList primitive is encountered. dpf * - Added another mechanism to pause a list on the master. When a * slave list is started, there is an option to pause the master list * until the slave is finished. 4-11-01 dpf * - Fully decoupled the three mechanisms by which a list can be paused. * Each mechanism now has a unique resumption condition. 4-16-01 dpf ************************************************************************************/ INT32 smHostListProc(void) { static UINT32 listIndx; UINT32 prmIndx; UINT32 outputData; static UINT32 listDone; static UINT32 resumeBitSave; #if defined(I_AM_MASTER_DSP) static UINT32 slavesAborted; #endif UINT32 pauseRqst; UINT32 abortRqst, resumeBit; INT32 error; INT32 returnCode = SUCCESS; switch (hostListState) { /* * IDLE: not currently processing a primitive list */ case IDLE: /* If inListRdy was set, begin processing the list */ if (getInListRdy()) { setBusy(); error = readListWrapper(HOST_LIST, PRM, &listIndx); loadPrimListIndex(listIndx); /* if readListWrapper returned a fatal error, abort */ if (error < 0) { addError(&returnCode, error, "smHostListProc", "readListWrapper", __FILE__, __LINE__); if (FATAL(returnCode)) { assignOutListRdy(0); setDspAck(); hostListState= ACKNOWLEDGED; return returnCode; } } /* readListWrapper was ok: begin list execution */ pausedByPrim= pausedBySlave= FALSE; #if defined(I_AM_MASTER_DSP) slavesAborted= FALSE; #endif attendSlvReply= listDone= FALSE; setExecuting(); hostListState= EXECUTING; } break; /* * EXECUTING: processing a primitive list */ case EXECUTING: /* check if pause or abort has been requested via the command register */ abortRqst = getAbort(); pauseRqst = getPause(); /* if not finished and neither abort nor pause requested execute a primitive */ if ( ! (listDone || PAUSE_REQUESTED || TERMINATE_EARLY)) { /* read the primitive index and write it to the status register */ getPrimIndex(HOST_LIST, &prmIndx); loadPrimIndex(prmIndx); /* execute a single primitive */ error = execPrim(HOST_LIST, &listDone); if (error < 0) { addError(&returnCode, error, "smHostListProc", "execPrim", __FILE__, __LINE__); } } /* Abort slave lists if (master only) * an early termination condition has been detected and * slave reply data is expected in the reply buffer (master only) * Slaves which contributed to attendSlvReply decrement it as they abort. * On slaves, attendSlvReply = 0 always so the condition below is never met. */ if (TERMINATE_EARLY && attendSlvReply) { #if defined(I_AM_MASTER_DSP) if (!slavesAborted) { abortSlvListSMs(); slavesAborted= TRUE; } #endif } /* End list processing if * EITHER * 1) an early termination condition has been detected and * no slave reply data is expected in the reply buffer (master only) * OR * 2) the list is finished and * pause was not requested and * no slave reply data is expected in the reply buffer (master only) */ else if (TERMINATE_EARLY || (listDone && !PAUSE_REQUESTED && !attendSlvReply)) { /* if there is reply data, add reply list wrapper and set outListRdy bit */ outputData = replyAvailable(HOST_LIST); if (outputData) { addListWrapper(HOST_LIST, REP, listIndx); } assignOutListRdy(outputData); /* reinitialize list structures */ resetPrimListStructs(HOST_LIST); /* reset executing bit, and set the handshake bit (dspAck) go to ACKNOWLEDGED state and wait for reply handshake */ rstExecuting(); setDspAck(); hostListState = ACKNOWLEDGED; } /* otherwise go to PAUSED if requested */ else if (PAUSE_REQUESTED) { resumeBitSave= getResume(); setPaused(); hostListState= PAUSED; } /* end of EXECUTING state code */ break; /* * PAUSED: list execution has been suspended */ /* There are 3 ways to pause primitive list execution. * 1) the list sender sets the CR_PAUSE bit in the command register * The list will resume when CR_PAUSE is reset. * 2) a PAUSE_LIST primitive is encountered * The list will resume when CR_RESUME is toggled. * 3) a slave DSP is started executing a list with pauseMasterList requested * The list will resume when the slave is done executing its list. * ==> If CR_PAUSE is set while the list is already paused for another reason, * the list will not resume until CR_PAUSE is cleared AND the resumption * condition for the original reason is met. */ case PAUSED: /* check if abort is set, pause is clear or resume has been toggled */ abortRqst = getAbort(); pauseRqst = getPause(); if (pausedByPrim) { resumeBit= getResume(); if (RESUME_BIT_TOGGLED) { pausedByPrim= FALSE; } } /* if so, go to EXECUTING. In the case of abort, EXECUTING will exit cleanly */ if (!PAUSE_REQUESTED || abortRqst) { rstPaused(); hostListState= EXECUTING; } break; /* * ACKNOWLEDGED: finished list processing and set handshake bit, waiting for * upstream processor to respond by clearing inListRdy */ case ACKNOWLEDGED: /* if inListRdy has been reset, reset busy and finish the handshake (by resetting dspAck) and go back to the idle state */ if ( ! getInListRdy()) { rstBusy(); rstDspAck(); hostListState= IDLE; } break; /* end of ACKNOWLEDGED state code */ default: hostListState= IDLE; break; } return returnCode; } /************************************************************************************ * setPausedByPrim(): Sets pausedByPrim, causing the list execution state machine to * go to PAUSED. This is how a list is paused if a pauseList * primitive is encountered. The list is resumed when the RESUME * bit is toggled in the command register. ************************************************************************************/ void setPausedByPrim(void) {pausedByPrim= TRUE; return; } #if defined(I_AM_MASTER_DSP) /************************************************************************************ * setPausedBySlave(): Sets pausedBySlave, causing the list execution state machine * to go to PAUSED. This is how a list is paused if a * startSlaveList primitive is executed with pauseMasterList set. * rstPausedBySlave(): Resumes list if paused by for slave list execution. ************************************************************************************/ void setPausedBySlave(void) {pausedBySlave= TRUE; return; } void rstPausedBySlave(void) {pausedBySlave= FALSE; return; } /************************************************************************************ * incAttendSlvReply(): Increments * decAttendSlvReply(): Resumes list if paused by for slave list execution. ************************************************************************************/ void incAttendSlvReply(void) {++attendSlvReply; return; } void decAttendSlvReply(void) {--attendSlvReply; return; } #endif