| 1 |
4 |
tbourke |
(* $Id: transitionflipper.sml 27 2008-03-28 05:50:05Z tbourke $ *)
|
| 2 |
|
|
|
| 3 |
|
|
(*TODO:
|
| 4 |
|
|
* Check whether duplicate selectids can muck things up.
|
| 5 |
|
|
* Remove unused select ids from final transitions (or initial transitions?).
|
| 6 |
|
|
fun removeEarlierDuplicates l = let (* there can be only one *)
|
| 7 |
|
|
fun p s (s', _) = not (s =:= s')
|
| 8 |
|
|
fun f [] = []
|
| 9 |
|
|
| f ((x as (s, _))::xs) = x :: f (List.filter (p s) xs)
|
| 10 |
|
|
in rev (f (rev l)) end
|
| 11 |
|
|
|
| 12 |
|
|
fun unusedId used (E.BoundId (s, ty, _)) = if s <- used
|
| 13 |
|
|
then SOME (s, ty) else NONE
|
| 14 |
|
|
|
| 15 |
|
|
val sellist = removeEarlierDuplicates
|
| 16 |
|
|
(List.mapPartial (unusedId (!usednames)) presellist)
|
| 17 |
|
|
|
| 18 |
|
|
* What happens if we call negate(negate tr)?
|
| 19 |
|
|
Should this be forbidden by using types?
|
| 20 |
|
|
|
| 21 |
|
|
* Should check whether any actselect indices are used in guard terms in a way
|
| 22 |
|
|
that will create problems (restrict how actions are selected?).
|
| 23 |
|
|
e.g. select i . (i > 4) / a[i]
|
| 24 |
|
|
||negate
|
| 25 |
|
|
\/
|
| 26 |
|
|
select i . (i <= r) / a[i]
|
| 27 |
|
|
But how would this combine with other transitions? Does it work?
|
| 28 |
|
|
This must first be understood properly.
|
| 29 |
|
|
|
| 30 |
|
|
* What about action selectids with non-zero lower bounds?
|
| 31 |
|
|
chan c[6];
|
| 32 |
|
|
select i : int[2,5] . true / c[i]
|
| 33 |
|
|
|
| 34 |
|
|
Either forbid, or the negation set has to include:
|
| 35 |
|
|
select i : int [0,1] . true / c[i]
|
| 36 |
|
|
|
| 37 |
|
|
* Need a mapping back from scalar sets to their typedef-ed names (possibly via
|
| 38 |
|
|
uniqueid lookup?, or don't expand to begin with (would this break anything
|
| 39 |
|
|
else?). See tests/testflip13, the selectid should come from 'S', not
|
| 40 |
|
|
scalar[5].
|
| 41 |
|
|
|
| 42 |
|
|
*)
|
| 43 |
|
|
|
| 44 |
|
|
structure TransitionFlipper :> TRANSITION_FLIPPER = let
|
| 45 |
|
|
structure E = Expression
|
| 46 |
|
|
and Env = Environment
|
| 47 |
|
|
and ECVT = ExpressionCvt
|
| 48 |
|
|
and ATrans = ActionTrans
|
| 49 |
|
|
and ClkE = ClockExpression
|
| 50 |
|
|
and CETrans = ClkExprTrans
|
| 51 |
|
|
in struct
|
| 52 |
|
|
exception FlipFailed of string
|
| 53 |
|
|
|
| 54 |
|
|
(* shortcuts over Atom and AtomSet *)
|
| 55 |
18 |
tbourke |
infix <+ <- ++ <\ \ =:= ; open Symbol
|
| 56 |
4 |
tbourke |
|
| 57 |
|
|
type t = {selectids: E.boundid list,
|
| 58 |
|
|
actionsubs: E.expr list,
|
| 59 |
|
|
guard: E.expr}
|
| 60 |
|
|
|
| 61 |
|
|
fun toString {selectids, actionsubs, guard} = let
|
| 62 |
|
|
fun showActions [] = ""
|
| 63 |
|
|
| showActions (e::es) = "[" ^ ECVT.Expr.toString e ^"]"^ showActions es
|
| 64 |
|
|
|
| 65 |
|
|
fun boundToStr (E.BoundId (s, ty, _)) = Atom.toString s ^
|
| 66 |
|
|
" : " ^ ECVT.Ty.toString ty
|
| 67 |
|
|
val bindingList = (ListFormat.fmt {init="(", sep=", ",
|
| 68 |
|
|
final=")", fmt=boundToStr})
|
| 69 |
|
|
in
|
| 70 |
|
|
"{select " ^ bindingList selectids ^ "\n" ^
|
| 71 |
|
|
" action: " ^ showActions actionsubs ^ "\n " ^
|
| 72 |
|
|
ECVT.Expr.toString guard ^ " }" ^ "\n"
|
| 73 |
|
|
end
|
| 74 |
|
|
|
| 75 |
|
|
fun andexpr env (e1, e2) = let
|
| 76 |
|
|
val (ce1, ce1fa, used) = ClkE.fromExpr (emptyset, env, e1)
|
| 77 |
|
|
val (ce2, ce2fa, used) = ClkE.fromExpr (used, env, e2)
|
| 78 |
27 |
tbourke |
in ClkE.toExpr (ClkE.andexpr (ce1, ce2), ce1fa @ ce2fa) end
|
| 79 |
4 |
tbourke |
|
| 80 |
|
|
fun negateTransitions env (subtypes, trans : t list, invariant) = let
|
| 81 |
|
|
val _ = Util.debugSect (Settings.Outline, fn ()=>"negateTransitions:\n"
|
| 82 |
|
|
::map toString trans)
|
| 83 |
|
|
|
| 84 |
|
|
(* 1. Group like subscripts; rename subSelectIds; make others unique. *)
|
| 85 |
|
|
val atrans = ATrans.ensureConsistency
|
| 86 |
|
|
(map (ATrans.fromTrans subtypes) trans)
|
| 87 |
|
|
val otherATrans = ATrans.coverMissingChannels (subtypes, atrans,
|
| 88 |
|
|
invariant)
|
| 89 |
|
|
val cetrans = map (CETrans.fromATrans env) atrans
|
| 90 |
|
|
|
| 91 |
|
|
val _ = Util.debugSubsect (Settings.Outline,
|
| 92 |
|
|
fn ()=>"cover missing channels:\n"
|
| 93 |
|
|
::map ATrans.toString otherATrans)
|
| 94 |
|
|
|
| 95 |
|
|
(* 2. Paritition remaining transitions. *)
|
| 96 |
|
|
val partitions = Partitions.makeList cetrans
|
| 97 |
|
|
|
| 98 |
|
|
(* 3. Form partition expressions: just over freeSubscripts
|
| 99 |
|
|
Grouping back into a single list of transitions. *)
|
| 100 |
|
|
val cetrans = List.concat (List.map CETrans.formPartitionReps partitions)
|
| 101 |
|
|
|
| 102 |
|
|
val _ = Util.debugSubsect (Settings.Detailed,
|
| 103 |
|
|
fn ()=>"with partition reps:\n"::map CETrans.toString cetrans)
|
| 104 |
|
|
|
| 105 |
|
|
(* 4. Convert the location invariant into a clock expression
|
| 106 |
|
|
* (this piece was hacked in later and could be tightened up. *)
|
| 107 |
|
|
val (cinv, cinv_fall, _) = ClkE.fromExpr (CETrans.unionNames cetrans,
|
| 108 |
|
|
env, invariant)
|
| 109 |
|
|
val cetrans = if null cinv_fall then cetrans
|
| 110 |
|
|
else List.map (CETrans.addDisjointForalls cinv_fall)
|
| 111 |
|
|
cetrans
|
| 112 |
|
|
|
| 113 |
|
|
(* 5. Negate each, concatenating results. *)
|
| 114 |
|
|
val ncetrans = List.concat (List.map (CETrans.negate cinv) cetrans)
|
| 115 |
|
|
|
| 116 |
|
|
val _ = Util.debugSubsect (Settings.Detailed, fn ()=>"after negation:\n"
|
| 117 |
|
|
::map CETrans.toString ncetrans)
|
| 118 |
|
|
|
| 119 |
|
|
in map ATrans.toTrans otherATrans @ map CETrans.toTrans ncetrans end
|
| 120 |
|
|
handle CETrans.SelectIdConflictsWithForAll (sel, forall) => let
|
| 121 |
|
|
fun showSym n = ListFormat.fmt {init=n ^ "(", final=")",
|
| 122 |
|
|
sep=", ", fmt=Atom.toString}
|
| 123 |
|
|
in
|
| 124 |
|
|
raise FlipFailed ("select/forall conflict, " ^
|
| 125 |
|
|
showSym "select" sel ^
|
| 126 |
|
|
showSym "forall" forall )
|
| 127 |
|
|
end
|
| 128 |
|
|
|
| 129 |
|
|
| ClkE.NonClockTerm => raise FlipFailed "bad clock terms in guard"
|
| 130 |
|
|
|
| 131 |
|
|
| ATrans.ActSubWithNonSimpleSelect e => raise FlipFailed (
|
| 132 |
|
|
"channel subscript contains non-simple bound variable (" ^
|
| 133 |
|
|
ExpressionCvt.Expr.toString e ^ ")")
|
| 134 |
|
|
|
| 135 |
|
|
| ATrans.ActSubWithBadType {expr, badty, goodty} => raise FlipFailed
|
| 136 |
|
|
("channel subscript select variable " ^
|
| 137 |
|
|
ExpressionCvt.Expr.toString expr ^ " has type " ^
|
| 138 |
|
|
ExpressionCvt.Ty.toString badty ^ ", not " ^
|
| 139 |
|
|
ExpressionCvt.Ty.toString goodty)
|
| 140 |
|
|
|
| 141 |
|
|
| ATrans.BadSubscriptCount =>
|
| 142 |
|
|
raise FlipFailed ("wrong number of channel subscripts")
|
| 143 |
|
|
|
| 144 |
|
|
| ATrans.MixedSubscriptTypes (e1, e2) => raise FlipFailed
|
| 145 |
|
|
("non-consistent channel subscript dimensions (" ^
|
| 146 |
|
|
ExpressionCvt.Expr.toString e1 ^ ", " ^
|
| 147 |
|
|
ExpressionCvt.Expr.toString e2 ^ ")")
|
| 148 |
|
|
|
| 149 |
|
|
fun chanToSubRanges (env, s) = let
|
| 150 |
|
|
fun arrToList (E.CHANNEL _, r) = SOME r
|
| 151 |
|
|
| arrToList (E.ARRAY (ty, E.Type sub), r) = arrToList (ty, sub::r)
|
| 152 |
|
|
| arrToList _ = NONE
|
| 153 |
|
|
in
|
| 154 |
|
|
Option.composePartial (fn ty=> arrToList (ty, []), Env.findValType env) s
|
| 155 |
|
|
end
|
| 156 |
|
|
|
| 157 |
|
|
end
|
| 158 |
|
|
end
|
| 159 |
|
|
|