(*-------------------------------------------------------------------------*)
(*                                                                         *)
(*  Amiga Oberon Library Module: NoGuru               Date: 02-Nov-92      *)
(*                                                                         *)
(*   © 1991 by Fridtjof Siebert                                            *)
(*                                                                         *)
(*-------------------------------------------------------------------------*)

(*
 * To compile use "Oberon [-dma] SET English NoGuru" to get an english
 * version of this module. Use "Oberon [-d] NoGuru" to get a german one.
 *)

(* $IF NoGuruRq *)
MODULE NoGuruRq;
(* $ELSE *)
MODULE NoGuru;
(* $END *)

IMPORT wb := Workbench,
       e  := Exec,
             Alerts,
             io,
(* $IF GarbageCollector *)
       gc := GarbageCollector,
(* $END *)
(* $IF NoGuruRq *)
       rq := Requests,
(* $END *)
       ol := OberonLib,
       s  := SYSTEM;

(* $StackChk- *)

(*------------------------------------------------------------*)

(* Die Traps haben folgende Bedeutung:

      2   Busfehler
      3   Addressfehler
      4   ill. Befehl
      5   Division durch 0
      6   Chk (Bereichsfehler)
      7   TrapV (Overflow)
      8   Privilegverletzung
      9   Trace-Vektor
      A   Line-A
      B   Line-F

 C - 1F   Guru # x

     20   Trap # 0 (Bereichsfehler)
     21   Trap # 1 (ungültiger Case index)
     22   Trap # 2 (Stack überlauf)
     23   Trap # 3 (Nil-Zeiger dereferenziert)
     24   Trap # 4 (Funktion ohne RETURN beendet)
     25   Trap # 5 (Fehler bei Typüberprüfung festgestellt)
     26   Trap # 6 (falscher Prozessor installiert)
     27   Trap # 7 (Zeiger ist ungerade (Adressfehle))
     28   Trap # 8 (User Break (^C));
     29   Trap # 9 (Out of memory);

22 -255   Guru # x

*)

TYPE
 TrapInfoType = RECORD
                  trap: LONGINT;
                  ssw:  INTEGER;
                  adr:  LONGINT;
                  ir:   INTEGER;
                  sr:   INTEGER;
                  pc:   LONGINT;
                END;
TYPE
  SegTrackProc = PROCEDURE (Address{8}: s.ADDRESS;
                            VAR SegNum{9}: LONGINT;
                            VAR Offset{10}: LONGINT): e.STRPTR;
  SegSemPtr = UNTRACED POINTER TO SegSem;
  SegSem = STRUCT (semaphore: e.SignalSemaphore)
    find: SegTrackProc;
  END;
VAR
  TrapInfo: TrapInfoType;
  A: ARRAY 8 OF LONGINT;
  D: ARRAY 8 OF LONGINT;
  Msg: ARRAY 80 OF CHAR;
  Me: e.TaskPtr;
  Sem: SegSemPtr;
  SegNum, Offset: LONGINT;
  SegName: ARRAY 256 OF CHAR;
  NamePtr: e.STRPTR;

(* $IFNOT NoGuruRq *)
  string:ARRAY 32 OF CHAR;
  i: INTEGER;
(* $END *)


PROCEDURE Assert*(cc: BOOLEAN; msg: ARRAY OF CHAR); (* $CopyArrays- *)

BEGIN
(* $IF NoGuruRq *)
  rq.Assert(cc,msg);
(* $ELSE *)
  IF ~ cc THEN
    io.WriteString(" *** ");
    io.WriteString(msg);
    io.WriteLn;
    HALT(20);
  END;
(* $END *)
END Assert;


PROCEDURE TrapHandler;
BEGIN
  IF Sem # NIL THEN
    e.Forbid;
    NamePtr := Sem.find (TrapInfo.pc, SegNum, Offset);
    IF NamePtr # NIL THEN
      (* $OddChk- *)
      COPY (NamePtr^, SegName);
      (* $OddChk= *)
    END;
    e.Permit;
  ELSE
    NamePtr := NIL;
  END;

  IF e.exec.thisTask#Me THEN
    IF NamePtr = NIL THEN
      IF Alerts.Alert("Task %s (Task=%lx) failed:\nGuru = %lx\nPC   = %lx\n"
                      "  ---  press button to continue  ---",
                      e.exec.thisTask.node.name,
                      e.exec.thisTask,
                      TrapInfo.trap,
                      TrapInfo.pc) THEN END;
    ELSE
      IF Alerts.Alert("Task %s (Task=%lx) failed:\nGuru = %lx\nPC   = %lx\n"
                      "SegTracker: %s : Hunk %ld, Offset $%08lx\n"
                      "  ---  press button to continue  ---",
                      e.exec.thisTask.node.name,
                      e.exec.thisTask,
                      TrapInfo.trap,
                      TrapInfo.pc,
                      s.ADR (SegName),
                      SegNum,
                      Offset) THEN END;
    END;
    HALT(20);
  END;
  A[7] := s.REG(15);

(* $IF GarbageCollector *)
  gc.mutator.locals := NIL;
(* $END *)

  s.SETREG(15,ol.OldSP);

(* $IF English THEN *)

  CASE TrapInfo.trap OF
  02H: Msg := "Buserror" |
  03H: Msg := "Addresserror" |
  04H: Msg := "Illegal instruction" |
  05H: Msg := "Division by 0" |
  06H: Msg := "Rangecheck error (CHK)" |
  07H: Msg := "Overflow (TRAPV)" |
  08H: Msg := "Privilege violation" |
  09H: Msg := "Trace-Vector" |
  0AH: Msg := "Line-A" |
  0BH: Msg := "Line-F" |
  20H: Msg := "Trap # 0 (Rangecheck error)" |
  21H: Msg := "Trap # 1 (illegal CASE-index)" |
  22H: Msg := "Trap # 2 (Stack overflow)" |
  23H: Msg := "Trap # 3 (NIL-Pointer dereferenced)" |
  24H: Msg := "Trap # 4 (Missing RETURN-statement)" |
  25H: Msg := "Trap # 5 (Typ-check error)" |
  26H: Msg := "Trap # 6 (need faster processor)" |
  27H: Msg := "Trap # 7 (uneven pointer used)" |
  28H: Msg := "Trap # 8 (User Break, ^C)" |
  29H: Msg := "Trap # 8 (Speichermangel)" |
  ELSE Msg := " Guru # 00H";
       INC(Msg[8],SHORT(SHORT(TrapInfo.trap DIV 16))); IF Msg[8]>"0" THEN INC(Msg[8],7) END;
       INC(Msg[9],SHORT(SHORT(TrapInfo.trap MOD 16))); IF Msg[9]>"0" THEN INC(Msg[9],7) END;
  END;

(* $ELSE *)

  CASE TrapInfo.trap OF
  02H: Msg := "Busfehler" |
  03H: Msg := "Addressfehler" |
  04H: Msg := "Illegaler Befehl" |
  05H: Msg := "Division durch 0" |
  06H: Msg := "Chk (Bereichsfehler)" |
  07H: Msg := "TrapV (Überlauf)" |
  08H: Msg := "Privilegverletzung" |
  09H: Msg := "Trace-Vektor" |
  0AH: Msg := "Line-A" |
  0BH: Msg := "Line-F" |
  20H: Msg := "Trap # 0 (Bereichsfehler)" |
  21H: Msg := "Trap # 1 (ungültiger Case index)" |
  22H: Msg := "Trap # 2 (Stack überlauf)" |
  23H: Msg := "Trap # 3 (Nil-Zeiger dereferenziert)" |
  24H: Msg := "Trap # 4 (Funktion ohne RETURN beendet)" |
  25H: Msg := "Trap # 5 (Typ-Check Fehler)" |
  26H: Msg := "Trap # 6 (falscher Prozessor installiert)" |
  27H: Msg := "Trap # 6 (ungerader Zeiger dereferenziert (Adressfehler))" |
  28H: Msg := "Trap # 8 (User Break)" |
  29H: Msg := "Trap # 8 (Ouf of memory)" |
  ELSE Msg := " ??? "
  END;

(* $END *)

(* $IF NoGuruRq *)

  rq.Fail(Msg);

(* $ELSE *)

  io.WriteString("Guru #"); io.WriteHex(TrapInfo.trap,4);
  io.WriteString(": \[1;33m");
  io.WriteString(Msg);
  io.WriteString("\[m\nDx ");
  i := 0;
  REPEAT
    io.WriteHex(D[i],8); io.Write(" "); IF i=3 THEN io.Write(" ") END;
    INC(i);
  UNTIL i=8;
  io.WriteString("\nAx ");
  i := 0;
  REPEAT
    io.WriteHex(A[i],8); io.Write(" "); IF i=3 THEN io.Write(" ") END;
    INC(i);
  UNTIL i=8;
  IF TrapInfo.trap<=3 THEN
    io.WriteString("\nssw   "); io.WriteHex(TrapInfo.ssw,4);
    io.WriteString("\nadr   "); io.WriteHex(TrapInfo.adr,8);
    io.WriteString("\nir    "); io.WriteHex(TrapInfo.ir ,4);
  END;
  IF NamePtr # NIL THEN
    io.WriteString("\nsegment "); io.WriteString(SegName);
    io.WriteString("\nhunk    "); io.WriteInt(SegNum,4);
    io.WriteString("\noffset  "); io.WriteHex(Offset,8);
  END;
  io.WriteString("\nsr "); io.WriteHex(TrapInfo.sr,4);
  io.WriteString("\npc "); io.WriteHex(TrapInfo.pc,8);
  io.WriteString("\n<RETURN>"); io.ReadString(string);
  HALT(20);

(* $END *)

END TrapHandler;


PROCEDURE TrapProc; (* $NilChk- *)

BEGIN
(* $IFNOT SmallData *)
  s.INLINE(0588FH);       (*    ADDQ.L  #4,A7         *)
(* $END *)
  s.INLINE(048E7H,0FEH);  (*    MOVEM.L A0-A6,-(A7)   *)
  ol.SetA5;
  s.SETREG(8,TrapHandler);
  s.SETREG(9,s.ADR(TrapInfo.trap));
  s.SETREG(11,s.ADR(D));
  s.SETREG(12,s.ADR(A));
  s.INLINE(
    048D3H,000FFH,        (*    MOVEM.L D0-D7,(A3)    *)
    04CDFH,0007FH,        (*    MOVEM.L (A7)+,D0-D6   *)
    048D4H,0007FH,        (*    MOVEM.L D0-D6,(A4)    *)
    0201FH,               (*    move.l  (A7)+,D0      *)
    02280H,               (*    move.l  D0,(A1)       *)
    0B07CH,00003H,        (*    cmp     #3,D0         *)
    06208H,               (*    bhi.s   l             *)
    0235FH,00004H,        (*    move.l  (a7)+, 4(a1)  *)
    0235FH,00008H,        (*    move.l  (a7)+, 8(a1)  *)
    03357H,0000CH,        (* l: move.w  (a7) ,12(a1)  *)
    0236FH,00002H,0000EH, (*    move.l  2(a7),14(a1)  *)
    02F48H,00002H,        (*    move.l  A0,    2(A7)  *)
    04E73H);              (*    rte                   *)

END TrapProc;


BEGIN
  Sem := e.FindSemaphore ("SegTracker");
  Me          := s.VAL(e.TaskPtr,ol.Me);
  Me.trapCode := TrapProc;
(* $IF NoGuruRq *)
END NoGuruRq.
(* $ELSE *)
END NoGuru.
(* $END *)
