*** empty log message ***
[fw/sdcc] / sim / ucsim / xa.src / inst.cc
index f493dac7ca96bff7d971eea99815d6b7209eefda..1efe594caef32f84459acd439af2e040f2d88e95 100644 (file)
@@ -6,7 +6,7 @@
  * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
  * Other contributors include:
  *   Karl Bongers karl@turbobit.com,
- *   Johan Knol 
+ *   Johan Knol johan.knol@iduna.nl
  *
  */
 
@@ -35,6 +35,44 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "xacl.h"
 #include "regsxa.h"
 
+#define NOTDONE_ASSERT { printf("**********Instr not done at %d!\n", __LINE__); }
+
+void cl_xa::store1(t_addr addr, unsigned char val)
+{
+  if (addr < 0x2000) {
+    set_idata1(addr, val);
+  } else {
+    set_xdata1(addr, val);
+  }
+}
+
+void cl_xa::store2(t_addr addr, unsigned short val)
+{
+  if (addr < 0x2000) {
+    set_idata2(addr, val);
+  } else {
+    set_xdata2(addr, val);
+  }
+}
+
+unsigned char cl_xa::get1(t_addr addr)
+{
+  if (addr < 0x2000) {
+    return get_idata1(addr);
+  } else {
+    return get_xdata1(addr);
+  }
+}
+
+unsigned short cl_xa::get2(t_addr addr)
+{
+  if (addr < 0x2000) {
+    return get_idata2(addr);
+  } else {
+    return get_xdata2(addr);
+  }
+}
+
 int cl_xa::get_reg(int word_flag, unsigned int index)
 {
   int result;
@@ -59,7 +97,6 @@ bool cl_xa::get_bit(int bit) {
   }
   result = get_byte_direct(offset + (bit/8)) & (1 << (bit%8));
   return result;
-  //return mem_direct[offset + (bit/8)] & (1 << (bit%8));
 }
 
 void cl_xa::set_bit(int bit, int value) {
@@ -74,10 +111,8 @@ void cl_xa::set_bit(int bit, int value) {
   i = get_byte_direct(offset + (bit/8));
   if (value) {
     set_byte_direct(offset + (bit/8), i | (1 << (bit%8)) );
-    //mem_direct[offset + (bit/8)] |= (1 << (bit%8));
   } else {
     set_byte_direct(offset + (bit/8), i & ~(1 << (bit%8)) );
-    //mem_direct[offset + (bit/8)] &= ~(1 << (bit%8));
   }
 }
 
@@ -110,6 +145,7 @@ int cl_xa::inst_ADDC(uint code, int operands)
 
 int cl_xa::inst_ADDS(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 
@@ -123,28 +159,150 @@ int cl_xa::inst_AND(uint code, int operands)
   return(resGO);
 }
 
+/* logical AND bit with Carry flag */
 int cl_xa::inst_ANL(uint code, int operands)
 {
+ unsigned char flags;
+ unsigned short bitAddr = (code&0x03 << 8) + fetch();
+ flags = get_psw();
+
+  if (flags & BIT_C) {
+    /* have work to do */
+    switch(operands) {
+      case CY_BIT :
+        if (!get_bit(bitAddr)) {
+          set_psw(flags & ~BIT_C);
+        }
+      break;
+
+      case CY_NOTBIT :
+        if (get_bit(bitAddr)) {
+          set_psw(flags & ~BIT_C);
+        }
+      break;
+    }
+  }
+
   return(resGO);
 }
 
+/* arithmetic shift left */
 int cl_xa::inst_ASL(uint code, int operands)
 {
+  unsigned int dst, cnt;
+  unsigned char flags;
+
+  /* ASL, dest, count
+    while (count != 0)
+      C = dest.80H; dest <<= 1; if sign chg then set V=1
+      this is a confusing one...
+  */
+
+  flags = get_psw();
+  flags &= ~BIT_ALL; /* clear these bits */
+
+  switch(operands) {
+    //{0,0xc150,0xf300,' ',2,ASL, REG_REG         }, //  ASL Rd, Rs                 1 1 0 0 S S 0 1  d d d d s s s s
+    case REG_REG :
+      cnt = reg1(RI_0F) & 0x1f;
+      switch (code & 0xc00) {
+        case 0: // byte
+          dst = reg1(RI_F0);
+          dst <<= cnt;
+          set_reg1(RI_F0,dst);
+          if (dst & 0x100)
+            flags |= BIT_C;
+          if ((dst & 0xff) == 0)
+            flags |= BIT_Z;
+        break;
+        case 1: // word
+          dst = reg2(RI_F0);
+          dst <<= cnt;
+          set_reg2(RI_F0,dst);
+          if (dst & 0x10000)
+            flags |= BIT_C;
+          if ((dst & 0xffff) == 0)
+            flags |= BIT_Z;
+        break;
+        case 3:  // dword
+          //dst = reg4(RI_F0);
+          dst = reg2(RI_F0) | (reg2(RI_F0 + 2) << 16);
+          if ((cnt != 0) && (dst & (0x80000000 >> (cnt-1)))) {
+            flags |= BIT_C;
+          }
+          dst <<= cnt;
+          set_reg2(RI_F0,dst & 0xffff);
+          set_reg2(RI_F0+2, (dst>>16) & 0xffff);
+          if (dst == 0)
+            flags |= BIT_Z;
+        break;
+      }
+    break;
+
+    case REG_DATA4 :
+    case REG_DATA5 :
+      switch (code & 0xc00) {
+        case 0: // byte
+          dst = reg1(RI_F0);
+          cnt = operands & 0x0f;
+          dst <<= cnt;
+          set_reg1(RI_F0,dst);
+          if (dst & 0x100)
+            flags |= BIT_C;
+          if ((dst & 0xff) == 0)
+            flags |= BIT_Z;
+        break;
+        case 1: // word
+          dst = reg2(RI_F0);
+          cnt = operands & 0x0f;
+          dst <<= cnt;
+          set_reg2(RI_F0,dst);
+          if (dst & 0x10000)
+            flags |= BIT_C;
+          if ((dst & 0xffff) == 0)
+            flags |= BIT_Z;
+        break;
+        case 3:  // dword
+          dst = reg1(RI_F0 & 0xe);
+          cnt = operands & 0x1f;
+          if ((cnt != 0) && (dst & (0x80000000 >> (cnt-1)))) {
+            flags |= BIT_C;
+          }
+          dst <<= cnt;
+          set_reg2(RI_F0,dst & 0xffff);
+          set_reg2(RI_F0+2, (dst>>16) & 0xffff);
+          if (dst == 0)
+            flags |= BIT_Z;
+        break;
+      }
+    break;
+  }
+  set_psw(flags);
+
   return(resGO);
 }
 
 int cl_xa::inst_ASR(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 
 int cl_xa::inst_BCC(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  if (!(get_psw() & BIT_C)) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 
 int cl_xa::inst_BCS(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  if (get_psw() & BIT_C) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 
@@ -152,57 +310,114 @@ int cl_xa::inst_BEQ(uint code, int operands)
 {
   short jmpAddr = fetch1()*2;
   if (get_psw() & BIT_Z) {
-    PC=(PC+jmpAddr)&0xfffffffe;
+    PC=(PC+jmpAddr)&0xfffffe;
   }
   return(resGO);
 }
 
 int cl_xa::inst_BG(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  short flags=get_psw();
+  bool Z=flags&BIT_Z, C=flags&BIT_C;
+  if (!(Z|C)) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BGE(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  short flags=get_psw();
+  bool N=flags&BIT_N, V=flags&BIT_V;
+  if (!(N^V)) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BGT(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  short flags=get_psw();
+  bool Z=flags&BIT_Z, N=flags&BIT_N, V=flags&BIT_V;
+  if (!((Z|N)^V)) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BKPT(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_BL(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  short flags=get_psw();
+  bool Z=flags&BIT_Z, C=flags&BIT_C;
+  if (Z|C) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BLE(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  short flags=get_psw();
+  bool Z=flags&BIT_Z, N=flags&BIT_N, V=flags&BIT_V;
+  if ((Z|N)^V) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BLT(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  short flags=get_psw();
+  bool N=flags&BIT_N, V=flags&BIT_V;
+  if (N^V) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BMI(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  if (get_psw()&BIT_N) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BNE(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  if (!(get_psw()&BIT_Z)) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BNV(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  if (!(get_psw()&BIT_V)) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BOV(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  if (get_psw()&BIT_V) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 int cl_xa::inst_BPL(uint code, int operands)
 {
+  short jmpAddr = fetch1()*2;
+  if (!(get_psw()&BIT_N)) {
+    PC=(PC+jmpAddr)&0xfffffe;
+  }
   return(resGO);
 }
 
@@ -315,8 +530,7 @@ int cl_xa::inst_CJNE(uint code, int operands)
 int cl_xa::inst_CLR(uint code, int operands)
 {
   unsigned short bitAddr = (code&0x03 << 8) + fetch();
-  // fixme: implement
-  bitAddr=bitAddr;
+  set_bit (bitAddr, 0);
   return(resGO);
 }
 
@@ -331,14 +545,17 @@ int cl_xa::inst_CMP(uint code, int operands)
 }
 int cl_xa::inst_CPL(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_DA(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_DIV(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 
@@ -388,11 +605,13 @@ int cl_xa::inst_DJNZ(uint code, int operands)
 
 int cl_xa::inst_FCALL(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 
 int cl_xa::inst_FJMP(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 
@@ -407,6 +626,12 @@ int cl_xa::inst_JB(uint code, int operands)
 }
 int cl_xa::inst_JBC(uint code, int operands)
 {
+  short bitAddr=((code&0x3)<<8) + fetch1();
+  short jmpAddr = (fetch1() * 2);
+  if (get_bit(bitAddr)) {
+    PC = (PC+jmpAddr)&0xfffffe;
+  }
+  set_bit(bitAddr,0);
   return(resGO);
 }
 int cl_xa::inst_JNB(uint code, int operands)
@@ -417,7 +642,6 @@ int cl_xa::inst_JNB(uint code, int operands)
     PC = (PC+jmpAddr)&0xfffffe;
   }
   return(resGO);
-  return(resGO);
 }
 int cl_xa::inst_JMP(uint code, int operands)
 {
@@ -458,10 +682,25 @@ int cl_xa::inst_JZ(uint code, int operands)
 }
 int cl_xa::inst_LEA(uint code, int operands)
 {
+  switch (operands) {
+    case REG_REGOFF8:
+      {
+       char offset=fetch1();
+       set_reg2(RI_70, reg2(RI_07)+offset);
+       break;
+      }
+    case REG_REGOFF16:
+      {
+       short offset=fetch2();
+       set_reg2(RI_70, reg2(RI_07)+offset);
+       break;
+      }
+  }
   return(resGO);
 }
 int cl_xa::inst_LSR(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_MOV(uint code, int operands)
@@ -532,26 +771,32 @@ int cl_xa::inst_MOVC(uint code, int operands)
 }
 int cl_xa::inst_MOVS(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_MOVX(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_MUL(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_NEG(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_NOP(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_NORM(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_OR(uint code, int operands)
@@ -566,18 +811,18 @@ int cl_xa::inst_OR(uint code, int operands)
 
 int cl_xa::inst_ORL(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 
 int cl_xa::inst_POP(uint code, int operands)
 {
+  unsigned short sp=get_sp();
   switch(operands) {
     case DIRECT:
     {
-      unsigned short sp;
       unsigned short direct_addr = ((operands & 0x7) << 8) | fetch();
 
-      sp = get_sp();
       if (code & 0x0800) {  /* word op */
         set_word_direct(direct_addr, get2(sp) );
       } else {
@@ -588,9 +833,50 @@ int cl_xa::inst_POP(uint code, int operands)
     break;
 
     case RLIST:
-      // fixme: implement
+    {
       unsigned char rlist = fetch();
-      rlist = rlist; //shutup compiler
+      if (code & 0x0800) { // word op
+       if (code & 0x4000) { // R8-R15
+         if (rlist&0x01) { set_reg2(8, get2(sp)); sp+=2; }
+         if (rlist&0x02) { set_reg2(9, get2(sp)); sp+=2; }
+         if (rlist&0x04) { set_reg2(10, get2(sp)); sp+=2; }
+         if (rlist&0x08) { set_reg2(11, get2(sp)); sp+=2; }
+         if (rlist&0x10) { set_reg2(12, get2(sp)); sp+=2; }
+         if (rlist&0x20) { set_reg2(13, get2(sp)); sp+=2; }
+         if (rlist&0x40) { set_reg2(14, get2(sp)); sp+=2; }
+         if (rlist&0x80) { set_reg2(15, get2(sp)); sp+=2; }
+       } else { // R0-R7
+         if (rlist&0x01) { set_reg2(0, get2(sp)); sp+=2; }
+         if (rlist&0x02) { set_reg2(1, get2(sp)); sp+=2; }
+         if (rlist&0x04) { set_reg2(2, get2(sp)); sp+=2; }
+         if (rlist&0x08) { set_reg2(3, get2(sp)); sp+=2; }
+         if (rlist&0x10) { set_reg2(4, get2(sp)); sp+=2; }
+         if (rlist&0x20) { set_reg2(5, get2(sp)); sp+=2; }
+         if (rlist&0x40) { set_reg2(6, get2(sp)); sp+=2; }
+         if (rlist&0x80) { set_reg2(7, get2(sp)); sp+=2; }
+       }
+      } else { // byte op
+       if (code & 0x4000) { // R4l-R7h
+         if (rlist&0x01) { set_reg1(8, get1(sp)); sp+=2; }
+         if (rlist&0x02) { set_reg1(9, get1(sp)); sp+=2; }
+         if (rlist&0x04) { set_reg1(10, get1(sp)); sp+=2; }
+         if (rlist&0x08) { set_reg1(11, get1(sp)); sp+=2; }
+         if (rlist&0x10) { set_reg1(12, get1(sp)); sp+=2; }
+         if (rlist&0x20) { set_reg1(13, get1(sp)); sp+=2; }
+         if (rlist&0x40) { set_reg1(14, get1(sp)); sp+=2; }
+         if (rlist&0x80) { set_reg1(15, get1(sp)); sp+=2; }
+       } else { // R0l-R3h
+         if (rlist&0x01) { set_reg1(0, get1(sp)); sp+=2; }
+         if (rlist&0x02) { set_reg1(1, get1(sp)); sp+=2; }
+         if (rlist&0x04) { set_reg1(2, get1(sp)); sp+=2; }
+         if (rlist&0x08) { set_reg1(3, get1(sp)); sp+=2; }
+         if (rlist&0x10) { set_reg1(4, get1(sp)); sp+=2; }
+         if (rlist&0x20) { set_reg1(5, get1(sp)); sp+=2; }
+         if (rlist&0x40) { set_reg1(6, get1(sp)); sp+=2; }
+         if (rlist&0x80) { set_reg1(7, get1(sp)); sp+=2; }
+       }
+      }
+    }
     break;
   }
   return(resGO);
@@ -615,16 +901,59 @@ int cl_xa::inst_PUSH(uint code, int operands)
     break;
 
     case RLIST:
-      // fixme: implement
+    {
+      unsigned short sp=get_sp();
       unsigned char rlist = fetch();
-      rlist = rlist; //shutup compiler
+      if (code & 0x0800) { // word op
+       if (code & 0x4000) { // R15-R8
+         if (rlist&0x80) { sp-=2; store2(sp, reg2(15)); }
+         if (rlist&0x40) { sp-=2; store2(sp, reg2(14)); }
+         if (rlist&0x20) { sp-=2; store2(sp, reg2(13)); }
+         if (rlist&0x10) { sp-=2; store2(sp, reg2(12)); }
+         if (rlist&0x08) { sp-=2; store2(sp, reg2(11)); }
+         if (rlist&0x04) { sp-=2; store2(sp, reg2(10)); }
+         if (rlist&0x02) { sp-=2; store2(sp, reg2(9)); }
+         if (rlist&0x01) { sp-=2; store2(sp, reg2(8)); }
+       } else { // R7-R0
+         if (rlist&0x80) { sp-=2; store2(sp, reg2(7)); }
+         if (rlist&0x40) { sp-=2; store2(sp, reg2(6)); }
+         if (rlist&0x20) { sp-=2; store2(sp, reg2(5)); }
+         if (rlist&0x10) { sp-=2; store2(sp, reg2(4)); }
+         if (rlist&0x08) { sp-=2; store2(sp, reg2(3)); }
+         if (rlist&0x04) { sp-=2; store2(sp, reg2(2)); }
+         if (rlist&0x02) { sp-=2; store2(sp, reg2(1)); }
+         if (rlist&0x01) { sp-=2; store2(sp, reg2(0)); }
+       }
+      } else { // byte op
+       if (code & 0x4000) { // R7h-R4l
+         if (rlist&0x80) { sp-=2; store2(sp, reg1(15)); }
+         if (rlist&0x40) { sp-=2; store2(sp, reg1(14)); }
+         if (rlist&0x20) { sp-=2; store2(sp, reg1(13)); }
+         if (rlist&0x10) { sp-=2; store2(sp, reg1(12)); }
+         if (rlist&0x08) { sp-=2; store2(sp, reg1(11)); }
+         if (rlist&0x04) { sp-=2; store2(sp, reg1(10)); }
+         if (rlist&0x02) { sp-=2; store2(sp, reg1(9)); }
+         if (rlist&0x01) { sp-=2; store2(sp, reg1(8)); }
+       } else { // R3h-R0l
+         if (rlist&0x80) { sp-=2; store2(sp, reg1(7)); }
+         if (rlist&0x40) { sp-=2; store2(sp, reg1(6)); }
+         if (rlist&0x20) { sp-=2; store2(sp, reg1(5)); }
+         if (rlist&0x10) { sp-=2; store2(sp, reg1(4)); }
+         if (rlist&0x08) { sp-=2; store2(sp, reg1(3)); }
+         if (rlist&0x04) { sp-=2; store2(sp, reg1(2)); }
+         if (rlist&0x02) { sp-=2; store2(sp, reg1(1)); }
+         if (rlist&0x01) { sp-=2; store2(sp, reg1(0)); }
+       }
+      }
+      set_sp(sp);
+    }
     break;
   }
-  
   return(resGO);
 }
 int cl_xa::inst_RESET(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_RET(uint code, int operands)
@@ -664,30 +993,39 @@ int cl_xa::inst_RETI(uint code, int operands)
 }
 int cl_xa::inst_RL(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_RLC(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_RR(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_RRC(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_SETB(uint code, int operands)
 {
   unsigned short bitAddr = (code&0x03 << 8) + fetch();
-  // fixme: implement
-  bitAddr=bitAddr;
+  set_bit (bitAddr, 1);
   return(resGO);
 }
 
 int cl_xa::inst_SEXT(uint code, int operands)
 {
+  bool neg=get_psw()&BIT_N;
+  if (code & 0x0800) { // word op
+    set_reg2(RI_F0, neg ? 0xffff : 0);
+  } else {
+    set_reg1(RI_F0, neg ? 0xff : 0);
+  }
   return(resGO);
 }
 
@@ -710,12 +1048,29 @@ int cl_xa::inst_SUBB(uint code, int operands)
 #include "inst_gen.cc"
   return(resGO);
 }
+
 int cl_xa::inst_TRAP(uint code, int operands)
 {
+  // steal a few opcodes for simulator only putchar() and exit()
+  // functions.  Used in SDCC regression testing.
+  switch (code & 0x0f) {
+    case 0xe:
+      // implement a simulator putchar() routine
+      //printf("PUTCHAR-----> %xH\n", reg1(0));
+      putchar(reg1(0));
+      fflush(stdout);
+    break;
+
+    case 0xf:
+      ::exit(0);
+    break;
+  }
   return(resGO);
 }
+
 int cl_xa::inst_XCH(uint code, int operands)
 {
+  NOTDONE_ASSERT;
   return(resGO);
 }
 int cl_xa::inst_XOR(uint code, int operands)