--- /dev/null
+/***** spin: dstep.c *****/
+
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */
+/* All Rights Reserved. This software is for educational purposes only. */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code. Permission is given to distribute this code provided that */
+/* this introductory message is not removed and no monies are exchanged. */
+/* Software written by Gerard J. Holzmann. For tool documentation see: */
+/* http://spinroot.com/ */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com */
+
+#include "spin.h"
+#include "y.tab.h"
+
+#define MAXDSTEP 1024 /* was 512 */
+
+char *NextLab[64];
+int Level=0, GenCode=0, IsGuard=0, TestOnly=0;
+
+static int Tj=0, Jt=0, LastGoto=0;
+static int Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP];
+static void putCode(FILE *, Element *, Element *, Element *, int);
+
+extern int Pid, claimnr, separate, OkBreak;
+
+static void
+Sourced(int n, int special)
+{ int i;
+ for (i = 0; i < Tj; i++)
+ if (Tojump[i] == n)
+ return;
+ if (Tj >= MAXDSTEP)
+ fatal("d_step sequence too long", (char *)0);
+ Special[Tj] = special;
+ Tojump[Tj++] = n;
+}
+
+static void
+Dested(int n)
+{ int i;
+ for (i = 0; i < Tj; i++)
+ if (Tojump[i] == n)
+ return;
+ for (i = 0; i < Jt; i++)
+ if (Jumpto[i] == n)
+ return;
+ if (Jt >= MAXDSTEP)
+ fatal("d_step sequence too long", (char *)0);
+ Jumpto[Jt++] = n;
+ LastGoto = 1;
+}
+
+static void
+Mopup(FILE *fd)
+{ int i, j;
+
+ for (i = 0; i < Jt; i++)
+ { for (j = 0; j < Tj; j++)
+ if (Tojump[j] == Jumpto[i])
+ break;
+ if (j == Tj)
+ { char buf[16];
+ if (Jumpto[i] == OkBreak)
+ { if (!LastGoto)
+ fprintf(fd, "S_%.3d_0: /* break-dest */\n",
+ OkBreak);
+ } else {
+ sprintf(buf, "S_%.3d_0", Jumpto[i]);
+ non_fatal("goto %s breaks from d_step seq", buf);
+ } } }
+ for (j = 0; j < Tj; j++)
+ { for (i = 0; i < Jt; i++)
+ if (Tojump[j] == Jumpto[i])
+ break;
+#ifdef DEBUG
+ if (i == Jt && !Special[i])
+ fprintf(fd, "\t\t/* no goto's to S_%.3d_0 */\n",
+ Tojump[j]);
+#endif
+ }
+ for (j = i = 0; j < Tj; j++)
+ if (Special[j])
+ { Tojump[i] = Tojump[j];
+ Special[i] = 2;
+ if (i >= MAXDSTEP)
+ fatal("cannot happen (dstep.c)", (char *)0);
+ i++;
+ }
+ Tj = i; /* keep only the global exit-labels */
+ Jt = 0;
+}
+
+static int
+FirstTime(int n)
+{ int i;
+ for (i = 0; i < Tj; i++)
+ if (Tojump[i] == n)
+ return (Special[i] <= 1);
+ return 1;
+}
+
+static void
+illegal(Element *e, char *str)
+{
+ printf("illegal operator in 'd_step:' '");
+ comment(stdout, e->n, 0);
+ printf("'\n");
+ fatal("'%s'", str);
+}
+
+static void
+filterbad(Element *e)
+{
+ switch (e->n->ntyp) {
+ case ASSERT:
+ case PRINT:
+ case 'c':
+ /* run cannot be completely undone
+ * with sv_save-sv_restor
+ */
+ if (any_oper(e->n->lft, RUN))
+ illegal(e, "run operator in d_step");
+
+ /* remote refs inside d_step sequences
+ * would be okay, but they cannot always
+ * be interpreted by the simulator the
+ * same as by the verifier (e.g., for an
+ * error trail)
+ */
+ if (any_oper(e->n->lft, 'p'))
+ illegal(e, "remote reference in d_step");
+ break;
+ case '@':
+ illegal(e, "process termination");
+ break;
+ case D_STEP:
+ illegal(e, "nested d_step sequence");
+ break;
+ case ATOMIC:
+ illegal(e, "nested atomic sequence");
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+CollectGuards(FILE *fd, Element *e, int inh)
+{ SeqList *h; Element *ee;
+
+ for (h = e->sub; h; h = h->nxt)
+ { ee = huntstart(h->this->frst);
+ filterbad(ee);
+ switch (ee->n->ntyp) {
+ case NON_ATOMIC:
+ inh += CollectGuards(fd, ee->n->sl->this->frst, inh);
+ break;
+ case IF:
+ inh += CollectGuards(fd, ee, inh);
+ break;
+ case '.':
+ if (ee->nxt->n->ntyp == DO)
+ inh += CollectGuards(fd, ee->nxt, inh);
+ break;
+ case ELSE:
+ if (inh++ > 0) fprintf(fd, " || ");
+/* 4.2.5 */ if (Pid != claimnr)
+ fprintf(fd, "(boq == -1 /* else */)");
+ else
+ fprintf(fd, "(1 /* else */)");
+ break;
+ case 'R':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+ putstmnt(fd, ee->n, ee->seqno);
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ case 'r':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+ putstmnt(fd, ee->n, ee->seqno);
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ case 's':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq == -1) && ");
+ putstmnt(fd, ee->n, ee->seqno);
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ case 'c':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+ if (Pid != claimnr)
+ fprintf(fd, "(boq == -1 && ");
+ putstmnt(fd, ee->n->lft, e->seqno);
+ if (Pid != claimnr)
+ fprintf(fd, ")");
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ } }
+ return inh;
+}
+
+int
+putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
+{ int isg=0; char buf[64];
+
+ NextLab[0] = "continue";
+ filterbad(s->frst);
+
+ switch (s->frst->n->ntyp) {
+ case UNLESS:
+ non_fatal("'unless' inside d_step - ignored", (char *) 0);
+ return putcode(fd, s->frst->n->sl->this, nxt, 0, ln, seqno);
+ case NON_ATOMIC:
+ (void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln, seqno);
+ break;
+ case IF:
+ fprintf(fd, "if (!(");
+ if (!CollectGuards(fd, s->frst, 0)) /* what about boq? */
+ fprintf(fd, "1");
+ fprintf(fd, "))\n\t\t\tcontinue;");
+ isg = 1;
+ break;
+ case '.':
+ if (s->frst->nxt->n->ntyp == DO)
+ { fprintf(fd, "if (!(");
+ if (!CollectGuards(fd, s->frst->nxt, 0))
+ fprintf(fd, "1");
+ fprintf(fd, "))\n\t\t\tcontinue;");
+ isg = 1;
+ }
+ break;
+ case 'R': /* <- can't really happen (it's part of a 'c') */
+ fprintf(fd, "if (!("); TestOnly=1;
+ putstmnt(fd, s->frst->n, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case 'r':
+ fprintf(fd, "if (!("); TestOnly=1;
+ putstmnt(fd, s->frst->n, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case 's':
+ fprintf(fd, "if (");
+#if 1
+/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq != -1) || ");
+#endif
+ fprintf(fd, "!("); TestOnly=1;
+ putstmnt(fd, s->frst->n, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case 'c':
+ fprintf(fd, "if (!(");
+ if (Pid != claimnr) fprintf(fd, "boq == -1 && ");
+ TestOnly=1;
+ putstmnt(fd, s->frst->n->lft, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case ELSE:
+ fprintf(fd, "if (boq != -1 || (");
+ if (separate != 2) fprintf(fd, "trpt->");
+ fprintf(fd, "o_pm&1))\n\t\t\tcontinue;");
+ break;
+ case ASGN: /* new 3.0.8 */
+ fprintf(fd, "IfNotBlocked");
+ break;
+ }
+ if (justguards) return 0;
+
+ fprintf(fd, "\n\t\tsv_save();\n\t\t");
+#if 1
+ fprintf(fd, "reached[%d][%d] = 1;\n\t\t", Pid, seqno);
+ fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* true next state */
+ fprintf(fd, "reached[%d][tt] = 1;\n", Pid); /* true current state */
+#endif
+ sprintf(buf, "Uerror(\"block in d_step seq, line %d\")", ln);
+ NextLab[0] = buf;
+ putCode(fd, s->frst, s->extent, nxt, isg);
+
+ if (nxt)
+ { extern Symbol *Fname;
+ extern int lineno;
+
+ if (FirstTime(nxt->Seqno)
+ && (!(nxt->status & DONE2) || !(nxt->status & D_ATOM)))
+ { fprintf(fd, "S_%.3d_0: /* 1 */\n", nxt->Seqno);
+ nxt->status |= DONE2;
+ LastGoto = 0;
+ }
+ Sourced(nxt->Seqno, 1);
+ lineno = ln;
+ Fname = nxt->n->fn;
+ Mopup(fd);
+ }
+ unskip(s->frst->seqno);
+ return LastGoto;
+}
+
+static void
+putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard)
+{ Element *e, *N;
+ SeqList *h; int i;
+ char NextOpt[64];
+ static int bno = 0;
+
+ for (e = f; e; e = e->nxt)
+ { if (e->status & DONE2)
+ continue;
+ e->status |= DONE2;
+
+ if (!(e->status & D_ATOM))
+ { if (!LastGoto)
+ { fprintf(fd, "\t\tgoto S_%.3d_0;\n",
+ e->Seqno);
+ Dested(e->Seqno);
+ }
+ break;
+ }
+ fprintf(fd, "S_%.3d_0: /* 2 */\n", e->Seqno);
+ LastGoto = 0;
+ Sourced(e->Seqno, 0);
+
+ if (!e->sub)
+ { filterbad(e);
+ switch (e->n->ntyp) {
+ case NON_ATOMIC:
+ h = e->n->sl;
+ putCode(fd, h->this->frst,
+ h->this->extent, e->nxt, 0);
+ break;
+ case BREAK:
+ if (LastGoto) break;
+ if (e->nxt)
+ { i = target( huntele(e->nxt,
+ e->status, -1))->Seqno;
+ fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
+ fprintf(fd, "/* 'break' */\n");
+ Dested(i);
+ } else
+ { if (next)
+ { fprintf(fd, "\t\tgoto S_%.3d_0;",
+ next->Seqno);
+ fprintf(fd, " /* NEXT */\n");
+ Dested(next->Seqno);
+ } else
+ fatal("cannot interpret d_step", 0);
+ }
+ break;
+ case GOTO:
+ if (LastGoto) break;
+ i = huntele( get_lab(e->n,1),
+ e->status, -1)->Seqno;
+ fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
+ fprintf(fd, "/* 'goto' */\n");
+ Dested(i);
+ break;
+ case '.':
+ if (LastGoto) break;
+ if (e->nxt && (e->nxt->status & DONE2))
+ { i = e->nxt?e->nxt->Seqno:0;
+ fprintf(fd, "\t\tgoto S_%.3d_0;", i);
+ fprintf(fd, " /* '.' */\n");
+ Dested(i);
+ }
+ break;
+ default:
+ putskip(e->seqno);
+ GenCode = 1; IsGuard = isguard;
+ fprintf(fd, "\t\t");
+ putstmnt(fd, e->n, e->seqno);
+ fprintf(fd, ";\n");
+ GenCode = IsGuard = isguard = LastGoto = 0;
+ break;
+ }
+ i = e->nxt?e->nxt->Seqno:0;
+ if (e->nxt && e->nxt->status & DONE2 && !LastGoto)
+ { fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
+ fprintf(fd, "/* ';' */\n");
+ Dested(i);
+ break;
+ }
+ } else
+ { for (h = e->sub, i=1; h; h = h->nxt, i++)
+ { sprintf(NextOpt, "goto S_%.3d_%d",
+ e->Seqno, i);
+ NextLab[++Level] = NextOpt;
+ N = (e->n && e->n->ntyp == DO) ? e : e->nxt;
+ putCode(fd, h->this->frst,
+ h->this->extent, N, 1);
+ Level--;
+ fprintf(fd, "%s: /* 3 */\n", &NextOpt[5]);
+ LastGoto = 0;
+ }
+ if (!LastGoto)
+ { fprintf(fd, "\t\tUerror(\"blocking sel ");
+ fprintf(fd, "in d_step (nr.%d, near line %d)\");\n",
+ bno++, (e->n)?e->n->ln:0);
+ LastGoto = 0;
+ }
+ }
+ if (e == last)
+ { if (!LastGoto && next)
+ { fprintf(fd, "\t\tgoto S_%.3d_0;\n",
+ next->Seqno);
+ Dested(next->Seqno);
+ }
+ break;
+ } }
+}