/********************************************************************** * * SOURCE FILE: ucodams-n.c (n is the verions number) * * Micro code for the AMS micro_sequencer * *********************************************************************** * PROGRAM DESCRIPTION * * The AMS microsequencer is a Moore Finite State Machine: it is fully * synchronous and state transitions happen on the rising edge of the * board clock. The state of the machine after a clock edge (NextState) * is function of the state of the machine before the edge (CurrentState) * and of the input signals before the clock edge. In each clock cycle the * value of the output signals is function ONLY of the machine state. * In formulas: * generically speaking: * state = f1 (state, inputs) this defines a generic state machine * output = f2 (state) this specialise to a Moore FSM * being precise at what happens at each clock edge, when both machine * state and machine outputs are registered: * State := NextState * output := NextOutput * in the above equations the := operator is used to indicate a register * update by the clock rising edge (ABEL style). * The above register update is what the hardware implements in the AMS * microsequencer registers, the microsequencer main task is to compute * NextState and NextOutput before each clock edge, this is done by two * functions that are implemented via a RAM: * * NextState = f1 (state, inputs) * NextOutput = f2 (NextState) * * where f1 and f2 are the same functions as before. Note that NextOutput * could also be written as function of state and inputs, indeed: * NextOutput = f2 ( f1(state, inputs) ) = f3 (state, inputs) * but using f2 in place of f3 makes things simpler and more clear. * * The AMS MS-RAM implements the functions f1 and f3 by suitably mapping * CurrentState and inputs into NextState and NextOutput. The task of this * program is to write the RAM content as an ASCII file containing the * hexadecimal codification of the RAM content from address 0 to address N. * In writing the code we will use f3 = f2(f1). * * The MS-RAM is a 128k x 24 memory, that thus accomodates up to * 17 inputs and 24 outputs. The MS state is coded as in an 8 bit register * (up to 256 different states), leaving space for up to 9 input signals * and up to 16 output signals. Unused inputs are forced to 0 in the * hardware, unused outputs are kept at 0 by this program. * * The program has no input, needed flags are read from stdin. * The program produces the RAM content as output. This output is * written in various formats (user selects one or more at run time): * OPENMODELER: 3 files as needed to initialise the RAM simulation with * the LAI view of the ram chips when running Cadence at CERN * VERILOG: 3 files as needed to initialise the RAM simulation with * the VLOG_BEHAVIORAL view when running Cadence in Pisa * VME: 1 file as needed to download the real board through the VME * CPU using the Vision code * *********************************************************************** * Original creation: S.Belforte June 29 1998. * Fully revised for clarity, readibility, etc. from * old code by: Pinizzotto + X.Wu + S.Belforte + T.Speer * Revision history: * ucodams-0.c * ============= * 29-Jun-1998 S.Belforte: 0th version. COPY of ucode-19.c with * full history of changes * ucodams-1.c * ============= * 30-Jun-1998 S.Belforte: first version. Remove past history and start * from scratch. This verions is a bit patched * (cfr. use of kkk and hhh flags to implement * bad usage of states in old code that breakes * "pure Moore FSM"). But .... * VERSION 1 PRODUCES THE SAME EXACT OUTPUT FILE * AS VERSION 19 OF THE OLD CODE !!!!!!!!!!!!!! * i. e. of Version_0 of ucodams. * ucodams-2.c * ============= * 30-Jun-1998 S.Belforte: Move include for AMS_MS_Definitions at beginning * of file for easier maintenance (single instance) * ucodams-3.c * ============= * 1-Jul-1998 S.Belforte: Clean up from patches, will get same flow with * more logical state flow, pure Moore FSM now. * FROM NOW ON OUTPUT FILE CAN NOT BE COMPARED * DIRECTELY WITH OLD ONE ANY MORE, ONLY RESULTS * WHEN RUNNING THE AMS SHOULD BE THE SAME ! * Enable IllegalState catching, remove unneeded * OpCodes, simplify state diagram, and put back * testing for MaxRoad. * ucodams-4.c * ============= * 1-Jul-1998 S.Belforte: Add run-time switches to disable Hold, MaxRoad * introducing the TuneFlow function * ucodams-5.c * ============= * 6-Jul-1998 S.Belforte: Use new AM opcodes as in AMS_MS_Definitions-2.h * Improve msgs to user. Check for illegal inputs. * Fix bug in byte2 calculation for output files. * ucodams-6.c * ============= * 4-Sep-1998 S.Belforte: Fix bugs: Jump to Init2 after EndEvent, and * re-introduce ClearHandshacke (RESET) opcode * before each event in Init3 (no matter what * Fabio says, it is needed !!!). * THIS IS THE FIRST VERSION AFTER -2 THAT WORKS ! * * ucodams-7.c * ============= * 22-Sep-1998 A.Cerri: add a new shift after all the 6/6 roads are output, * to implement the 5/6 case. A new output loop is * also added, after the SHIFT. * *********************************************************************/ #include #include #include "AMS_MS_Definitions-3.h" /* global variables */ int VmeOutput, OpmdOutput, VlogOutput; /* enable flags for output files */ FILE *filede1,*filede2,*filede3; /* OPENMODELER format files */ FILE *filede4,*filede5,*filede6; /* VERILOG format files */ FILE *filede7; /* VME format file */ int IgnoreHold, IgnoreMaxRoad; /* user flags to change FSM flow */ /**************************************************************************/ int main (){ /* function prototypes */ int OpenFiles(); int WriteOutput(int address, int data); int CloseFiles(); int TuneFlow(); int ComputeNextState(int address); int ComputeNextOutput(int NextState); /* local definitions and variables */ int status; int address; int data; int NextOutput; /*****************************************************/ /* executable code */ /* start by deciding which outputs to write and opening files as needed */ status = OpenFiles (); /* allow user to tune the AMS flow with run-time inputs */ /* preset flag values for standard action, so that customisation can be turned off by simply commenting out the TuneFLow call */ IgnoreHold = 0; IgnoreMaxRoad = 0; status = TuneFlow(); /* then loop on all RAM addresses (128k), compute proper data word, (this is the "active" core of the program) and write it out */ for (address = 0; address <= MaxAddress; address++) { NextState = ComputeNextState (address); data = ComputeNextOutput (NextState); status = WriteOutput (address, data); } /* end loop on RAM addresses */ /* finally close output files and exit*/ status = CloseFiles (); return 0; } /* end of main */ /*======================================================================*/ /*======================================================================*/ /********************************************************** *********** F U N C T I O N S ************* ***********************************************************/ int OpenFiles () { int OutFlag; printf (" output choice (binary coded, multiple choices are allowed) : \n"); printf (" 1 VME - 2 OpenModeller - 4 Verilog (e.g. 5 = VME and Verilog) : \n"); scanf ("%d", &OutFlag); VmeOutput = OutFlag & 0x1; OpmdOutput = OutFlag & 0x2; VlogOutput = OutFlag & 0x4; if (!VmeOutput & ! OpmdOutput & ! VlogOutput) printf (" Warning, the program will produce NO output !\n "); else { printf (" The program outptut will be in the following file(s): \n"); printf (" (Warning: preexisting files will be overwritten !) \n\n"); } if (OpmdOutput) { printf (" M1_128K.AM-USEQ, M2_... and M3_... for OpenModeler simulation. \n"); filede1 = fopen ("M1_128K.AM-USEQ","w"); filede2 = fopen ("M2_128K.AM-USEQ","w"); filede3 = fopen ("M3_128K.AM-USEQ","w"); }; if (VlogOutput) { printf (" M1_128K.AM-USEQ_V, M2_... and M3_... for Verilog simulation. \n"); filede4 = fopen ("M1_128K.AM-USEQ_V","w"); filede5 = fopen ("M2_128K.AM-USEQ_V","w"); filede6 = fopen ("M3_128K.AM-USEQ_V","w"); }; if (VmeOutput) { printf (" VME_128K.AM-USEQ for downloading through the VME cpu. \n"); filede7 = fopen ("VME_128K.AM-USEQ","w"); }; printf ("\n"); return 0; } /* end of OpenFiles */ /**************************************************************************/ int CloseFiles() { if (OpmdOutput) { fclose (filede1); fclose (filede2); fclose (filede3); }; if (VlogOutput) { fclose (filede4); fclose (filede5); fclose (filede6); }; if (VmeOutput) { fclose (filede7); }; return 0; } /* end of CloseFiles */ /**************************************************************************/ int WriteOutput(int address, int data) { int byte0, byte1, byte2; /* 3 bytes for the 3 8-bit ram chips */ byte0 = data & 0x0000FF; byte1 = (data & 0x00FF00) >> 8; byte2 = (data & 0xFF0000) >> 16; if (OpmdOutput) { fprintf (filede1, "%05X/%02X;\n", address, byte0); fprintf (filede2, "%05X/%02X;\n", address, byte1); fprintf (filede3, "%05X/%02X;\n", address, byte2); }; if (VlogOutput) { fprintf (filede4, "%02X\n", byte0); fprintf (filede5, "%02X\n", byte1); fprintf (filede6, "%02X\n", byte2); }; if (VmeOutput) { fprintf (filede7, "%06X\n", data); }; return 0; } /* end of WriteOutput */ /**************************************************************************/ int TuneFlow () { printf (" Ignore output HOLD ? (1/0 = Y/N) : "); scanf ("%d", &IgnoreHold); while (IgnoreHold != 0 & IgnoreHold != 1) { printf (" Illegal value, enter 1 or 0 : "); scanf ("%d", &IgnoreHold); } printf (" Ignore Road Limit ? (1/0 = Y/N) : "); scanf ("%d", &IgnoreMaxRoad); while (IgnoreMaxRoad != 0 & IgnoreMaxRoad != 1) { printf (" Illegal value, enter 1 or 0 : "); scanf ("%d", &IgnoreMaxRoad); } return 0; } /* end of TuneFlow */ /**************************************************************************/ int ComputeNextState (int address) { /* first extract the various input signals */ CurrentState = (address >> CurrentStateOffset) & CurrentStateMask; MaxRoad = (address >> MaxRoadOffset) & MaxRoadMask; Hold = (address >> HoldOffset) & HoldMask; DataValid_ = (address >> DataValid_Offset) & DataValidMask; EEin = (address >> EEinOffset) & EEinMask; NewHit = (address >> NewHitOffset) & NewHitMask; /* invert low active signals for uniform logic in the following */ DataValid = ! DataValid_; /* Allow for user's request to ignore some input flags */ if (IgnoreHold) Hold = 0; if (IgnoreMaxRoad) MaxRoad = 0; /* now the state diagram. The following switch block * is f1: it defines the FSM State Diagram * via NextState = f1 (CurrentState, inputs) */ switch (CurrentState) { case Reset: NextState = Init3; break; /* case Init1: NextState = Init2; break; */ case Init2: NextState = Init3; break; case Init3: NextState = WaitForHit; break; case WaitForHit: if (NewHit) NextState = ProcessHit; else if (EEin) NextState = StartCount; else NextState = WaitForHit; break; case ProcessHit: if (NewHit) NextState = ProcessHit; else if (EEin) NextState = StartCount; else NextState = WaitForHit; break; case StartCount: NextState = Count0; break; case Count0: NextState = Count1; break; case Count1: NextState = Count2; break; case Count2: NextState = Count3; break; case Count3: NextState = Count4; break; case Count4: NextState = Count5; break; case Count5: NextState = SyncGlue; break; case SyncGlue: NextState = Wait1; break; case Wait1: NextState = Wait2; break; case Wait2: NextState = Wait3; break; case Wait3: NextState = Wait4; break; case Wait4: NextState = Wait5; break; case Wait5: NextState = Wait6; break; case Wait6: NextState = Wait7; break; case Wait7: NextState = Wait8; break; case Wait8: NextState = Wait9; break; case Wait9: NextState = Wait10; break; case Wait10: NextState = Wait11; break; case Wait11: NextState = Wait12; break; case Wait12: NextState = Wait13; break; case Wait13: NextState = Wait14; break; case Wait14: NextState = Wait15; break; case Wait15: NextState = Wait16; break; case Wait16: NextState = Wait17; break; case Wait17: NextState = Wait18; break; case Wait18: NextState = EndWait; break; case EndWait: if (MaxRoad) NextState = EndOutput; else { if (Hold) NextState = EndWait; else { if (DataValid) NextState = ProcessRoad; else NextState = NoDV_1; } } break; case NoDV_1: if (MaxRoad) NextState = EndOutput; else { if (Hold) NextState = NoDV_1; else { if (DataValid) NextState = ProcessRoad; else NextState = NoDV_2; } } break; case NoDV_2: if (MaxRoad) NextState = EndOutput; else { if (Hold) NextState = NoDV_2; else { if (DataValid) NextState = ProcessRoad; else NextState = EndOutput; } } break; case ProcessRoad: NextState = EndWait; break; case EndOutput: if (Hold) NextState = EndOutput; else NextState = Do_Shift; break; /* after the 6/6 output make a shift and proceed to the 5/6 output */ case Do_Shift: NextState = SyncGlue_s; break; case SyncGlue_s: NextState = Wait1_s; break; case Wait1_s: NextState = Wait2_s; break; case Wait2_s: NextState = Wait3_s; break; case Wait3_s: NextState = Wait4_s; break; case Wait4_s: NextState = Wait5_s; break; case Wait5_s: NextState = Wait6_s; break; case Wait6_s: NextState = Wait7_s; break; case Wait7_s: NextState = Wait8_s; break; case Wait8_s: NextState = Wait9_s; break; case Wait9_s: NextState = Wait10_s; break; case Wait10_s: NextState = Wait11_s; break; case Wait11_s: NextState = Wait12_s; break; case Wait12_s: NextState = Wait13_s; break; case Wait13_s: NextState = Wait14_s; break; case Wait14_s: NextState = Wait15_s; break; case Wait15_s: NextState = Wait16_s; break; case Wait16_s: NextState = Wait17_s; break; case Wait17_s: NextState = Wait18_s; break; case Wait18_s: NextState = EndWait_s; break; case EndWait_s: if (MaxRoad) NextState = EndOutput_s; else { if (Hold) NextState = EndWait_s; else { if (DataValid) NextState = ProcessRoad_s; else NextState = NoDV_1_s; } } break; case NoDV_1_s: if (MaxRoad) NextState = EndOutput_s; else { if (Hold) NextState = NoDV_1_s; else { if (DataValid) NextState = ProcessRoad_s; else NextState = NoDV_2_s; } } break; case NoDV_2_s: if (MaxRoad) NextState = EndOutput_s; else { if (Hold) NextState = NoDV_2_s; else { if (DataValid) NextState = ProcessRoad_s; else NextState = EndOutput_s; } } break; case ProcessRoad_s: NextState = EndWait_s; break; case EndOutput_s: if (Hold) NextState = EndOutput_s; else NextState = WaitParity; break; case WaitParity: NextState = EndEvent; break; case EndEvent: NextState = Init2; break; /* latch illegal transitions by jumping to a fixed state and never exiting */ case IllegalState: NextState = IllegalState; break; default: NextState = IllegalState; } /* end of switch */ return NextState; } /* end of ComputeNextState */ /**************************************************************************/ int ComputeNextOutput (int State) { int DataWord; /* The present function is f2: it formally computes the * FSM outputs as functions of the state, since we pass NextState * to this function, we get NextOutput(NextState) */ /* preset default value for all controls, they are set to "inactive" and will be activated only when needed. Note that Sel_ has to be always 0 with present GLUE3, and that at present we also put EP=1 in each output word, so these two controls are set here to proper value and never changed again. */ OpCode = NOP0; Done_ = 1; Sel_ = 0; Pop = 0; Push = 0; EEout = 0; EPout = 1; EEreset = 0; /* then enable controls as needed in the various states */ switch (State) { case Reset: break; /* case Init1: OpCode = CLRHIT; EEreset = 1; break; */ case Init2: OpCode = CLRHIT; break; case Init3: {OpCode = RESET; Pop = 1; EEreset = 1;} break; case WaitForHit: break; case ProcessHit: OpCode = INPUT; break; case StartCount: OpCode = CLRCNT; break; case Count0: OpCode = COUNT; break; case Count1: OpCode = COUNT; break; case Count2: OpCode = COUNT; break; case Count3: OpCode = COUNT; break; case Count4: OpCode = COUNT; break; case Count5: OpCode = COUNT; break; case SyncGlue: OpCode = NOP0; break; case Wait1: OpCode = OUTPUT; break; case Wait2: OpCode = OUTPUT; break; case Wait3: OpCode = OUTPUT; break; case Wait4: OpCode = OUTPUT; break; case Wait5: OpCode = OUTPUT; break; case Wait6: OpCode = OUTPUT; break; case Wait7: OpCode = OUTPUT; break; case Wait8: OpCode = OUTPUT; break; case Wait9: OpCode = OUTPUT; break; case Wait10: OpCode = OUTPUT; break; case Wait11: OpCode = OUTPUT; break; case Wait12: OpCode = OUTPUT; break; case Wait13: OpCode = OUTPUT; break; case Wait14: OpCode = OUTPUT; break; case Wait15: OpCode = OUTPUT; break; case Wait16: OpCode = OUTPUT; break; case Wait17: OpCode = OUTPUT; break; case Wait18: OpCode = OUTPUT; break; case EndWait: OpCode = OUTPUT; break; case NoDV_1: OpCode = OUTPUT; break; case NoDV_2: OpCode = OUTPUT; break; case ProcessRoad: {OpCode = OUTPUT; Push = 1; Done_ = 0;} break; case EndOutput: break; case Do_Shift: OpCode = SHIFT; break; case SyncGlue_s: OpCode = NOP0; break; case Wait1_s: OpCode = OUTPUT; break; case Wait2_s: OpCode = OUTPUT; break; case Wait3_s: OpCode = OUTPUT; break; case Wait4_s: OpCode = OUTPUT; break; case Wait5_s: OpCode = OUTPUT; break; case Wait6_s: OpCode = OUTPUT; break; case Wait7_s: OpCode = OUTPUT; break; case Wait8_s: OpCode = OUTPUT; break; case Wait9_s: OpCode = OUTPUT; break; case Wait10_s: OpCode = OUTPUT; break; case Wait11_s: OpCode = OUTPUT; break; case Wait12_s: OpCode = OUTPUT; break; case Wait13_s: OpCode = OUTPUT; break; case Wait14_s: OpCode = OUTPUT; break; case Wait15_s: OpCode = OUTPUT; break; case Wait16_s: OpCode = OUTPUT; break; case Wait17_s: OpCode = OUTPUT; break; case Wait18_s: OpCode = OUTPUT; break; case EndWait_s: OpCode = OUTPUT; break; case NoDV_1_s: OpCode = OUTPUT; break; case NoDV_2_s: OpCode = OUTPUT; break; case ProcessRoad_s: {OpCode = OUTPUT; Push = 1; Done_ = 0;} break; case EndOutput_s: break; case WaitParity: break; case EndEvent: EEout = 1; break; } /* end of switch on various State values */ /* build output data word */ DataWord = 0; DataWord |= (State & NextStateMask) << NextStateOffset; DataWord |= (OpCode & OpCodeMask) << OpCodeOffset; DataWord |= (Done_ & Done_Mask) << Done_Offset; DataWord |= (Sel_ & Sel_Mask) << Sel_Offset; DataWord |= (Pop & PopMask) << PopOffset; DataWord |= (Push & PushMask) << PushOffset; DataWord |= (EEout & EEoutMask) << EEoutOffset; DataWord |= (EPout & EPoutMask) << EPoutOffset; DataWord |= (EEreset & EEresetMask) << EEresetOffset; return DataWord; } /* end of ComputeNextOutput */ /**************************************************************************/