FSM.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Barth, July 17, 1987 5:42:41 pm PDT
Last Edited by: Don Curry January 13, 1988 9:27:39 am PST
DIRECTORY Core, CoreClasses, IO, Sisyph, SymTab;
FSM: CEDAR DEFINITIONS = BEGIN
Theory
This interface defines some routines for creating finite state machines and their corresponding cellTypes from either code or schematics. The cellTypes can be created with or without a register for the outputs. When a cellType without a register is created, all outputs have the prefix 'Nxt' to distinguish the signal names from inputs which where outputs from the previous cycle. The cellTypes have a high level Rosemary eval proc and will recast into a variety of cell types depending on the parameter exprImplKey. See FSMImpl.mesa for the latest catalogue of implementation choices for exprImplKey.
Public Types - (for direct contruction of FSMData)
FSMData:   TYPE = REF FSMDataRec;
FSMDataRec:  TYPE = RECORD [
name:    IO.ROPE    ← NIL,
states:    States     ← NIL,
initialState:  State     ← NIL,
outInAll:   BOOL     ← TRUE, -- TRUE => all outputs avail as inputs
outIns:   LIST OF IO.ROPE  ← NIL, -- If ~outInAll then list of outs avail as inputs
register:   RegisterType   ← edgeTriggered,
mach:    Expression   ← NIL, -- private
assert:    Expression   ← NIL, -- any guaranteed conditions
publics:   LIST OF IO.ROPE  ← NIL, -- private
srcCellType:  Core.CellType  ← NIL ]; -- private
States:  TYPE = LIST OF State;
State:  TYPE = REF StateRec;
StateRec: TYPE = RECORD [
name:   IO.ROPE    ← NIL,
outputs:  LIST OF IO.ROPE  ← NIL, -- Moore state and outs, Mealy state
outputsInv: LIST OF IO.ROPE  ← NIL,  -- explicit control of state encodings
outTrans:  Transitions   ← NIL,
inTrans:  Transitions   ← NIL, -- private
srcCellInst: CellInstance   ← NIL ]; -- private
Transitions: TYPE = LIST OF Transition;
Transition: TYPE = REF TransitionRec;
TransitionRec: TYPE = RECORD [
enable:  Expression   ← NIL,
outputs:  LIST OF IO.ROPE  ← NIL,  -- Mealy outs
target:   State     ← NIL,
srcCellInst: CellInstance   ← NIL ]; -- private
Expression:  TYPE = REF;
CellInstance:  TYPE = CoreClasses.CellInstance;
RegisterType: TYPE = {edgeTriggered, twoPhase, none};
Private Types - (used during indirect contruction of FSMData)
Context:  TYPE = REF ContextRec;
ContextRec: TYPE = RECORD[
fsm:   FSMData,
logic:   LIST OF CurrentLogic,
data:   LIST OF CurrentData,
state:   IO.ROPE,
declares:  LIST OF Declaration, -- Used during declarations
signals:  Signals,     -- Used after all declarations
invTab:  SymTab.Ref,
stateTab:  SymTab.Ref ];
CurrentLogic: TYPE = LIST OF FieldValMask ← NIL;
CurrentData:  TYPE = LIST OF FieldValMask ← NIL;
FieldValMask: TYPE = RECORD[f,v,m: NAT ← default];
Signals:   TYPE = REF SignalSeqRec;
SignalSeqRec: TYPE = RECORD [SEQUENCE size: NAT OF Declaration];
Declaration:  TYPE = RECORD [name: IO.ROPE, io: InOut, size: NAT, index: NAT];
InOut:   TYPE = {in, out, outIn}; -- outIn = clocked state variables, prev val input
default:   NAT = LAST[NAT];
Creation of FSM CellTypes from FSMData or Schematics
CodeMachine: PROC [fsm: FSMData, exprImplKey: ATOM ← $SC] RETURNS [ct: Core.CellType];
fsm.publics, fsm.mach and all inTrans fields are initialized to NIL.
SchStateCell:   PROC RETURNS [ct: Core.CellType]; -- Target Source
SchTransitionCell: PROC RETURNS [ct: Core.CellType]; -- Source Target
SchMachine: PROC [
cx:    Sisyph.Context,
name:   IO.ROPE  ← NIL,
register:  RegisterType ← edgeTriggered,
exprImplKey: ATOM   ← $SC    ]
RETURNS [ct: Core.CellType];
Sch cell name: ".fsm" is concatenated to name if supplied or the current object name if not.
Sisyph is invoked to extract the schematic state machine.
A state labelled Init must exist.
Every state has an implicit transition to Init when Reset is asserted.
The names used in the public of the cellType will be:
"Vdd", "Gnd", "Reset",
all input names,
all output names (including automatically assigned xtra state bit names),
SELECT registerType FROM
edgeTriggered => "Clock"
twoPhase    => "PhA", "PhB"
ENDCASE   => 'Nxt' prepended to all outputs which are also inputs,
Generating FSMData
The following procs are useful for writing FSM Generators.
You create a context: ctx ← Create[]
Declare names:   id: NAT ← ctx.Declare[name, in/out/outIn, size]
Specify the transition: ctx.IfState["state1"]; ctx.AddOut[id, val]; ctx.JmpState["state2"]; ...
or maybe state outs: ctx.IfState[NIL];  ctx.AddOut[id, val]; ctx.SetState["state"]; ...
And finish:    fsm ← ctx.Finish[]
IfState, and If push the context down one level.
JmpState pops the context up one level.
Only IfState can be used at the top level.
Only If can be used at lower levels.
And is used to extend a condition started by IfState or If.
Transition Definition Construct: (outputs associated with transistions)
IfState[state1], And[...], AddOut[...], JmpState[state2] provides a means of defining outputs for a transition between states. Logical conditions applied to the context using And are ANDed with state1 to enable the transition to state2.
State Definition Construct: (outputs associated with states)
IfState[NIL], AddOut[...], JmpState[state] provides an means of defining the outputs for a state (rather than a transition). Any logical conditions applied to the context using And between the IfState and JmpState trigger an ERROR in JmpState.
Branch-contexts can be explored using the If call.
Contexts and branch-contexts are terminated by JmpState
JmpState[NIL] can be used to just pop the context.
The state "Init" must be declared.
The input "Reset" is always implicit and causes a transition from anywhere to "Init".
Outputs of "Init" may be defined using the State Definition Construct
Outputs which also appear as inputs (after one clock delay) can be declared as outIn (rather than just out). Making more outputs available as inputs tends to decrease the number of xtra bits the FSM contructor needs to add in order to disambiguate states. It also tends to decrease the term sizes.
Example: Dragon SmallCache SCPmCodeFSMImpl.mesa
Create: PROC[name: IO.ROPE] RETURNS[ctx: Context];
Declare: PROC[ctx: Context, name: IO.ROPE, io: InOut, size: NAT ← 1] RETURNS[ix: NAT];
IfState:  PROC[ctx: Context, s: IO.ROPE];
If:    PROC[ctx: Context, f, v: NAT, m: NAT ← default];
And:   PROC[ctx: Context, f, v: NAT, m: NAT ← default];
AddOut:  PROC[ctx: Context, f, v: NAT, m: NAT ← default];
JmpState: PROC[ctx: Context, s: IO.ROPE];
Finish:  PROC[ctx: Context] RETURNS[mach: FSMData];
Complete state assignments and convert to an Expression
EncodeStates: PROC[fsm: FSMData];           -- multiple calls ok
ConvertToExp: PROC[fsm: FSMData] RETURNS[machine: LIST OF REF]; -- calls EncodeStates
Build Standard Cells
ImplementExprFile: PROC[file: IO.ROPE, register: RegisterType, exprImplKey: ATOM]
RETURNS[Core.CellType];
ImplementExpr: PROC[mach: Expression, register: RegisterType, exprImplKey: ATOM]
RETURNS[Core.CellType];
BuildSCMachine: PROC[mach: Expression] RETURNS [Core.CellType];
BuildSCGates:  PROC[mach: Expression] RETURNS [Core.CellType];
BuildSCRegister: PROC[mach: Expression] RETURNS [Core.CellType];
END.