SECTION "CGD"

GET "b.CGheader"
GET "b.FP2Ops"

STATIC {
/* ARM disassembler for BCPL codegenerator.
   version of 08 Jul 87 13:07:27
*/
   dummy = VersionMark;
   version = 1*256+4 };

/*
   1.2	01 Nov 85 11:40:10
     CMP not CMPS, etc, and register definitions at the start,
     so the listing can be assembled if required.
   1.3	06 Feb 86 12:16:21
     Floating point ops incorporated
   1.4	08 Jul 87 13:06:47
     second version of floating point instruction set.
     CMPS etc restored.
*/

STATIC {
   position = 0;
   RealWrch = 0;
   noRegisterUpdate = 0;
   moveType = 0;
   labelsKnown = 0 };

LET InitialiseDisassembler(printLabels) BE {
   RealWrch := Wrch;
   Wrch := CountWrch;
   labelsKnown := printLabels;
   position := 1
/*
   FOR r = r.0 to r.pc DO
      WriteF("%s RN %n*n", RegisterName(r), r);
   NewLine()
*/
}

AND TerminateDisassembler() BE {
   Wrch := RealWrch }

AND CountWrch(ch) BE {
   TEST ch='*N'
      THEN position := 1
      ELSE position := position+1;
   RealWrch(ch) }

AND TabTo(n) BE {
   LET n1 = (n-1)&(-8);   // tab stop before
   LET p1 = (position+7)&(-8);
   IF p1<=n1 THEN {
      RealWrch('*T');
      WHILE p1~=n1 DO {
	 RealWrch('*T');
	 p1 := p1+8 };
      position := n1+1 };
   WHILE position<n DO Wrch('*s') }

AND RegisterName(r) = VALOF SWITCHON r&15 INTO {
   CASE r.0:	  RESULTIS "r0"
   CASE r.a1:	  RESULTIS "a1"
   CASE r.a2:	  RESULTIS "a2"
   CASE r.a3:	  RESULTIS "a3"
   CASE r.a4:	  RESULTIS "a4"
   CASE r.w1:	  RESULTIS "w1"
   CASE r.nilbase:RESULTIS "nilbase"
   CASE r.gb:	  RESULTIS "rgb"
   CASE r.g:	  RESULTIS "rg"
   CASE r.p:	  RESULTIS "rp"
   CASE r.ts:	  RESULTIS "rts"
   CASE r.l:	  RESULTIS "rl"
   CASE r.b:	  RESULTIS "rb"
   CASE r.nil:	  RESULTIS "nil"
   CASE r.14:	  RESULTIS "r14"
   CASE r.pc:	  RESULTIS "pc" }

AND ShiftName(sh) = VALOF SWITCHON sh&#x60 INTO {
   CASE sh.asl: RESULTIS "ASL"
   CASE sh.lsr: RESULTIS "LSR"
   CASE sh.asr: RESULTIS "ASR"
   CASE sh.ror: RESULTIS "ROR" }

AND MaskName(m) = VALOF SWITCHON m&#xf0000000 INTO {
   CASE m.eq:  RESULTIS "EQ"
   CASE m.ne:  RESULTIS "NE"
   CASE m.geu: RESULTIS "CS"
   CASE m.ltu: RESULTIS "CC"
   CASE m.mi:  RESULTIS "MI"
   CASE m.pl:  RESULTIS "PL"
   CASE m.vs:  RESULTIS "VS"
   CASE m.vc:  RESULTIS "VC"
   CASE m.gtu: RESULTIS "HI"
   CASE m.leu: RESULTIS "LS"
   CASE m.ge:  RESULTIS "GE"
   CASE m.lt:  RESULTIS "LT"
   CASE m.gt:  RESULTIS "GT"
   CASE m.le:  RESULTIS "LE"
   CASE m.always:RESULTIS ""
   CASE m.never: RESULTIS "NV" }

AND OpCodeName(op) = VALOF {
   noRegisterUpdate := FALSE;
   moveType := FALSE;
   SWITCHON (op&#x1e00000)>>21 INTO {
      CASE f.add>>21:  RESULTIS "ADD"
      CASE f.sub>>21:  RESULTIS "SUB"
      CASE f.rsb>>21:  RESULTIS "RSB"
      CASE f.adc>>21:  RESULTIS "ADC"
      CASE f.sbc>>21:  RESULTIS "SBC"
      CASE f.rsc>>21:  RESULTIS "RSC"
      CASE f.cmp>>21:  noRegisterUpdate := TRUE;
		       RESULTIS "CMP"
      CASE f.cmn>>21:  noRegisterUpdate := TRUE;
		       RESULTIS "CMN"
      CASE f.and>>21:  RESULTIS "AND"
      CASE f.eor>>21:  RESULTIS "EOR"
      CASE f.orr>>21:  RESULTIS "ORR"
      CASE f.bic>>21:  RESULTIS "BIC"
      CASE f.tst>>21:  noRegisterUpdate := TRUE;
		       RESULTIS "TST"
      CASE f.teq>>21:  noRegisterUpdate := TRUE;
		       RESULTIS "TEQ"
      CASE f.mov>>21:  moveType := TRUE;
		       RESULTIS "MOV"
      CASE f.mvn>>21:  moveType := TRUE;
		       RESULTIS "MVN" } }

AND F4Type(a) = VALOF SWITCHON (a>>23)&3 INTO {
   CASE #x1800000>>23: RESULTIS "IB"
   CASE #x1000000>>23: RESULTIS "DB"
   CASE #x0800000>>23: RESULTIS "IA"
   CASE #x0000000>>23: RESULTIS "DA" }

AND PrintRegisterAndShift(b) BE {
   WriteS(RegisterName(b));
   IF (b&#xff0)~=0 THEN {
      WriteF(", %s ", ShiftName(b));
      TEST (b&#x10)~=0 THEN
	 WriteS(RegisterName(b>>8))
      ELSE
	 PrintNumber([b>>7]&#x1f, -1) } }

AND RotateRight(n, shift) = VALOF {
   WHILE shift>0 DO {
      LET bottombit = n&1;
      n := (n>>1);
      IF bottombit~=0 THEN n := n+#x80000000;
      shift := shift-1 };
   RESULTIS n }

AND PrintNumber(offset, shift) BE {
   IF shift>0 THEN offset := RotateRight(offset, 2*shift);
   WriteF((-4097<offset<4097 -> "#%n", "#&%x8"),
	  offset) }

AND StartComment() BE {
   TabTo(33);
   WriteS("; ") }

AND PrintF2Start(a, t) BE {
   WriteF(" %sR%s", ((a&#x100000)~=0 -> "LD", "ST"),
		    MaskName(a));
   IF (a&#x400000)~=0 THEN Wrch('B');
   IF t THEN WrCh('T');
   TabTo(9);
   WriteF("%s, [%s", RegisterName(a>>12),
		     RegisterName(a>>16)) }

AND PrintInstruction(loc, a) BE {
   LET type = a&#xf000000;
   LET updown = a&#x800000;   // for the benfit of DT instructions
   LET n = a&#xfff;	      // ditto
   SWITCHON type>>24 INTO {
      CASE #x0:
	 IF (a&#xfc00000)=0 & (a&#xf0)=#x90 THEN {
	    LET mla = (a&#x200000)~=0;
	    WriteF(" %s%s", (mla -> "MLA", "MUL"), MaskName(a));
	    IF (a&#x100000)~=0 THEN Wrch('S');
	    TabTo(9);
	    WriteF("%s, %s, %s", RegisterName(a>>16), RegisterName(a), RegisterName(a>>8));
	    IF mla THEN WriteF(", %s", RegisterName(a>>12));
	    ENDCASE }

      CASE #x1:
      CASE #x2:
      CASE #x3:
	 WriteF(" %s%s", OpCodeName(a), MaskName(a));
	 IF (a&#x100000)~=0 THEN Wrch('S');
	 TabTo(9);
	 IF ~noRegisterUpdate
	    THEN WriteF("%s, ", RegisterName(a>>12));
	 IF ~moveType
	    THEN WriteF("%s, ", RegisterName(a>>16));
	 TEST (type&#x2000000)=0
	    THEN PrintRegisterAndShift(a)
	    ELSE PrintNumber(a&255, (a>>8)&15);
	 ENDCASE

      CASE #x8:
      CASE #x9:
	 WriteF(" %sM%s%s", ((a&#x100000)~=0 -> "LD", "ST"),
			    MaskName(a), F4Type(a));
	 TabTo(9);
	 WriteS(RegisterName(a>>16));
	 IF (a&f.wb)~=0 THEN Wrch('!');
	 WriteS(", {");
	 {  LET b = a&#xffff;
	    TEST b=0 THEN
	       Wrch('0')
	    ELSE FOR r = 0 TO 15 DO {
	       IF (b&1)~=0 THEN {
		  WriteS(RegisterName(r));
		  IF b=1 THEN BREAK;
		  WriteS(", ") };
	       b := b>>1 } };
	 Wrch('}');
	 IF (a&f.pc)~=0 THEN Wrch('^');
	 ENDCASE

      CASE #xa:
      CASE #xb:
	 WriteF(" %s%s", ((a&#x1000000)~=0 -> "BL", "B"),
			 MaskName(a));
	 TabTo(9);
	 {  LET i = loc+8+(a<<8)/64;
	    LET lab = ?;
	    TEST labelsKnown THEN {
	       lab := LabelWithValue(i, 1);
	       TEST lab<0 THEN {
		  lab := RelocationForLoc(loc);
		  TEST lab~=Null THEN {
		     WriteF("|%s|", SymbolOfReloc(lab));
		     TabTo(18);
		     WriteF("; &%x4", i) }
		  ELSE {
		     Wrch('.'); TabTo(18);
		     WriteF("; &%x4 **unknown label", i) } }
	       ELSE {
		  WriteF("L%n", lab); TabTo(18);
		  WriteF("; &%x4", i) } }
	    ELSE
	       WriteF("&%x6", i) };
	 ENDCASE

      CASE #xf:
	 WriteF(" SWI%s", MaskName(a));
	 TabTo(9);
	 PrintNumber(a&#xffffff, -1);
	 ENDCASE

      CASE #x4:
	 PrintF2Start(a, a&f.wb)
	 WriteS("], ");
	 PrintNumber((UpDown=0 -> -n, n), -1);
	 ENDCASE

      CASE #x5:
	 PrintF2Start(a, 0)
	 WriteS(", ");
	 PrintNumber((UpDown=0 -> -n, n), -1);
	 Wrch(']');
	 IF (a&f.wb)~=0 THEN Wrch('!');
	 ENDCASE

      CASE #x6:
	 PrintF2Start(a, a&f.wb)
	 WriteS("], ");
	 IF UpDown=0 THEN Wrch('-');
	 PrintRegisterAndShift(a);
	 ENDCASE

      CASE #x7:
	 PrintF2Start(a, 0)
	 WriteS(", ");
	 IF UpDown=0 THEN Wrch('-');
	 PrintRegisterAndShift(a);
	 Wrch(']');
	 IF (a&f.wb)~=0 THEN Wrch('!');
	 ENDCASE

      CASE #xc:
	 PrintCPDTStart(a, a&f.wb);
	 n := (a&#xff)*4;
	 WriteF("], #%n", (UpDown=0 -> -n, n));
	 ENDCASE

      CASE #xd:
	 PrintCPDTStart(a, 0);
	 n := (a&#xff)*4;
	 WriteF(", #%n]", (UpDown=0 -> -n, n));
	 IF (a&f.wb)~=0 THEN Wrch('!');
	 ENDCASE

      CASE #xe:
	 TEST (a&#x30)=#x10 THEN {
	    WriteF(" %s%s", CPRTFop(a), maskname(a));
	    TEST (a&#xe00000)=ff.fixflt THEN {
	       WriteDestAndRounding(a);
	       TabTo(9);
	       TEST (a&ff.toarm)~=0 THEN
		  WriteF("%s, %s", RegisterName(a>>12), FPRegName(a))
	       ELSE
		  WriteF("%s, %s", FPRegName(a>>16), RegisterName(a>>12)) }
	    ELSE TEST (a&#xf00000)>=ff.cmf THEN {
	       TabTo(9);
	       WriteF("%s, ", FPRegName(a>>16));
	       TEST (a&ff.const)=0 THEN
		  WriteF("%s", FPRegName(a))
	       ELSE
		  WriteF("#%s", FConst(a&7)) }
	    ELSE {
	       TabTo(9);
	       WriteS(RegisterName(a>>12)) } }
	 ELSE {
	    WriteF(" %s%s", CPDOFop(a),
			    MaskName(a));
	    WriteDestAndRounding(a);
	    TabTo(9);
	    IF ~noRegisterUpdate THEN WriteF("%s, ", FPRegName(a>>12));
	    IF ~moveType THEN WriteF("%s, ", FPRegName(a>>16));
	    TEST (a&ff.const)=0 THEN
	       WriteF("%s", FPRegName(a))
	    ELSE
	       WriteF("#%s", FConst(a&7)) } };
   StartComment();
   WriteF("%x4 %x8*n", loc, a) }

AND FConst(n) = VALOF SWITCHON n INTO {
   CASE 0: RESULTIS "0"
   CASE 1: RESULTIS "1"
   CASE 2: RESULTIS "2"
   CASE 3: RESULTIS "3"
   CASE 4: RESULTIS "4"
   CASE 5: RESULTIS "5"
   CASE 6: RESULTIS "0.5"
   CASE 7: RESULTIS "10" }

AND PrintCPDTStart(a, t) BE {
   LET storeFormat = VALOF SWITCHON a&fcpdt.size INTO {
      CASE fcpdt.s: RESULTIS 'S'
      CASE fcpdt.d: RESULTIS 'D'
      CASE fcpdt.e: RESULTIS 'E'
      CASE fcpdt.p: RESULTIS 'P' };
   WriteF(" %sF%s%c", ((a&#x100000)~=0 -> "LD", "ST"),
		      MaskName(a),
		      storeFormat);
   IF t THEN WrCh('T');
   TabTo(9);
   WriteF("%s, [%s", FPRegName(a>>12), RegisterName(a>>16)) }

AND FPRegName(n) = VALOF SWITCHON n&7 INTO {
   CASE fr.0: RESULTIS "f0"
   CASE fr.1: RESULTIS "f1"
   CASE fr.2: RESULTIS "f2"
   CASE fr.3: RESULTIS "f3"
   CASE fr.4: RESULTIS "f4"
   CASE fr.5: RESULTIS "f5"
   CASE fr.6: RESULTIS "f6"
   CASE fr.7: RESULTIS "f7" }

AND CPRTFop(n) = VALOF SWITCHON n&#xf00000 INTO {
   CASE ff.fix: RESULTIS "FIX"
   CASE ff.flt: RESULTIS "FLT"
   CASE ff.wfs: RESULTIS "WFS"
   CASE ff.rfs: RESULTIS "RFS"
   CASE ff.wfc: RESULTIS "WFC"
   CASE ff.rfc: RESULTIS "RFC"
   CASE ff.cmf: RESULTIS "CMF"
   CASE ff.cnf: RESULTIS "CNF"

   DEFAULT: RESULTIS "???" }

AND CPDOFop(n) = VALOF {
   noRegisterUpdate := FALSE;
   moveType := FALSE;
   SWITCHON (n&#xf08000) INTO {
      CASE ff.adf: RESULTIS "ADF"
      CASE ff.sbf: RESULTIS "SBF"
      CASE ff.rsf: RESULTIS "RSF"
      CASE ff.mlf: RESULTIS "MLF"
      CASE ff.dvf: RESULTIS "DVF"
      CASE ff.rdf: RESULTIS "RDF"
      CASE ff.pow: RESULTIS "POW"
      CASE ff.rpw: RESULTIS "RPW"
      CASE ff.rmf: RESULTIS "RMF"
      CASE ff.fml: RESULTIS "FML"
      CASE ff.fdv: RESULTIS "FDV"
      CASE ff.frd: RESULTIS "FRD"
      CASE ff.pol: RESULTIS "POL"

      CASE ff.abs: moveType := TRUE;
		   RESULTIS "ABS"
      CASE ff.sqt: moveType := TRUE;
		   RESULTIS "SQT"
      CASE ff.mvf: moveType := TRUE;
		   RESULTIS "MVF"
      CASE ff.mnf: moveType := TRUE;
		   RESULTIS "MNF"
      CASE ff.rnd: moveType := TRUE;
		   RESULTIS "RND"
      CASE ff.log: moveType := TRUE;
		   RESULTIS "LOG"
      CASE ff.lgn: moveType := TRUE;
		   RESULTIS "LGN"
      CASE ff.exp: moveType := TRUE;
		   RESULTIS "EXP"
      CASE ff.sin: moveType := TRUE;
		   RESULTIS "SIN"
      CASE ff.cos: moveType := TRUE;
		   RESULTIS "COS"
      CASE ff.tan: moveType := TRUE;
		   RESULTIS "TAN"
      CASE ff.asn: moveType := TRUE;
		   RESULTIS "ASN"
      CASE ff.acs: moveType := TRUE;
		   RESULTIS "ACS"
      CASE ff.atn: moveType := TRUE;
		   RESULTIS "ATN"
      DEFAULT:	   RESULTIS "???" } }

AND WriteDestAndRounding(a) BE {
   SWITCHON a&fcpdo.size INTO {
      CASE fcpdo.s: WrCh('S'); ENDCASE
      CASE fcpdo.d: WrCh('D'); ENDCASE
      CASE fcpdo.e: WrCh('E') };
   SWITCHON a&fr.field INTO {
      CASE fr.rtopi: WrCh('P'); ENDCASE
      CASE fr.rtomi: WrCh('M'); ENDCASE
      CASE fr.rtoz:  WrCh('Z')
      CASE fr.rton: } }
