BBC Basic in Z80 emulation on the mbed, USB serial terminal output only. LOAD and SAVE work on the local file system but there is no error signalling.

Dependencies:   mbed

Revision:
0:806c2f2a7d47
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/z80/edops.h	Wed Jun 29 14:25:56 2011 +0000
@@ -0,0 +1,590 @@
+/* Emulations of the ED operations of the Z80 instruction set.
+ * Copyright (C) 1994 Ian Collier.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define input(var) {  var=in(c);\
+                     f=(f&1)|(var&0xa8)|((!var)<<6)|parity(var);\
+                   }
+#define sbchl(x) {    unsigned short z=(x);\
+                      unsigned long t=(hl-z-cy)&0x1ffff;\
+                      f=((t>>8)&0xa8)|(t>>16)|2|\
+                        (((hl&0xfff)<(z&0xfff)+cy)<<4)|\
+                        (((hl^z)&(hl^t)&0x8000)>>13)|\
+                        ((!(t&0xffff))<<6)|2;\
+                      l=t;\
+                      h=t>>8;\
+                   }
+
+#define adchl(x) {    unsigned short z=(x);\
+                      unsigned long t=hl+z+cy;\
+                      f=((t>>8)&0xa8)|(t>>16)|\
+                        (((hl&0xfff)+(z&0xfff)+cy>0xfff)<<4)|\
+                        (((~hl^z)&(hl^t)&0x8000)>>13)|\
+                        ((!(t&0xffff))<<6)|2;\
+                      l=t;\
+                      h=t>>8;\
+                 }
+
+#define neg (a=-a,\
+            f=(a&0xa8)|((!a)<<6)|(((a&15)>0)<<4)|((a==128)<<2)|2|(a>0))
+
+{
+   unsigned char op=fetch(pc);
+   pc++;
+   
+// IN B,(C)   
+   switch(op){
+instr(0x40,8);
+   input(b);
+endinstr;
+
+// OUT (C),B
+instr(0x41,8);
+   out(c,b);
+endinstr;
+
+// SBC HL,BC
+instr(0x42,11);
+   sbchl(bc);
+endinstr;
+
+// LD (nn),BC
+instr(0x43,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    store2b(addr,b,c);
+   }
+endinstr;
+
+// NEG
+instr(0x44,4);
+   neg;
+endinstr;
+
+// RETN
+instr(0x45,4);
+   iff1=iff2;
+   ret;
+endinstr;
+
+// IM 0
+instr(0x46,4);
+   im=0;
+endinstr;
+
+// LD I,A
+instr(0x47,5);
+   i=a;
+endinstr;
+
+// IN C,(C)
+instr(0x48,8);
+   input(c);
+endinstr;
+
+// OUT (C),C
+instr(0x49,8);
+   out(c,c);
+endinstr;
+
+// ADC HL,BC
+instr(0x4a,11);
+   adchl(bc);
+endinstr;
+
+// LD BC,(nn)
+instr(0x4b,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    c=fetch(addr);
+    b=fetch(addr+1);
+   }
+endinstr;
+
+// ?
+instr(0x4c,4);
+   neg;
+endinstr;
+
+// RETI
+instr(0x4d,4);
+   ret;
+endinstr;
+
+// ?
+instr(0x4e,4);
+   im=1;
+endinstr;
+
+// ?
+instr(0x4f,5);
+   r=a;
+endinstr;
+
+// IN D,(C)
+instr(0x50,8);
+   input(d);
+endinstr;
+
+// OUT (C),D
+instr(0x51,8);
+   out(c,d);
+endinstr;
+
+// SBC HL,DE
+instr(0x52,11);
+   sbchl(de);
+endinstr;
+
+// LD (nn),DE
+instr(0x53,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    store2b(addr,d,e);
+   }
+endinstr;
+
+// ?
+instr(0x54,4);
+   neg;
+endinstr;
+
+// my opcode for replacing the MOS routines
+instr(0x55,4);
+   // printf("@ %04x Illegal opcode ED55 (MOS) \n\r",pc);
+   do_mos(); // 
+   ret;
+endinstr;
+
+// IM 1
+instr(0x56,4);
+   im=1;
+endinstr;
+
+// LD A,I
+instr(0x57,5);
+   a=i;
+   f=(f&1)|(a&0xa8)|((!a)<<6)|(iff2<<2);
+endinstr;
+
+// IN E,(C)
+instr(0x58,8);
+   input(e);
+endinstr;
+
+// OUT (C),E
+instr(0x59,8);
+   out(c,e);
+endinstr;
+
+// ADC HL,DE
+instr(0x5a,11);
+   adchl(de);
+endinstr;
+
+// LD DE,(nn)
+instr(0x5b,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    e=fetch(addr);
+    d=fetch(addr+1);
+   }
+endinstr;
+
+// ?
+instr(0x5c,4);
+   neg;
+endinstr;
+
+// ?
+instr(0x5d,4);
+   ret;
+endinstr;
+
+// IM 2
+instr(0x5e,4);
+   im=2;
+endinstr;
+
+// LDA A,R (unecessary on static memory)
+instr(0x5f,5);
+   a=r;
+   f=(f&1)|(a&0xa8)|((!a)<<6)|(iff2<<2);
+endinstr;
+
+// IN H,(C)
+instr(0x60,8);
+   input(h);
+endinstr;
+
+// OUT (C),H
+instr(0x61,8);
+   out(c,h);
+endinstr;
+
+// SBC HL,HL
+instr(0x62,11);
+   sbchl(hl);
+endinstr;
+
+// ?
+instr(0x63,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    store2b(addr,h,l);
+   }
+endinstr;
+
+// ?
+instr(0x64,4);
+   neg;
+endinstr;
+
+// ? illegal instruction ED65
+instr(0x65,4);
+   ret;
+endinstr;
+
+// ?
+instr(0x66,4);
+   ret; 
+   //  was im=0;
+endinstr;
+
+// RRD
+instr(0x67,14);
+   {unsigned char t=fetch(hl);
+    unsigned char u=(a<<4)|(t>>4);
+    a=(a&0xf0)|(t&0x0f);
+    store(hl,u);
+    f=(f&1)|(a&0xa8)|((!a)<<6)|parity(a);
+   }
+endinstr;
+
+// IN L,(C)
+instr(0x68,8);
+   input(l);
+endinstr;
+
+// OUT (C),L
+instr(0x69,8);
+   out(c,l);
+endinstr;
+
+// ADC HL,HL
+instr(0x6a,11);
+   adchl(hl);
+endinstr;
+
+// ?
+instr(0x6b,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    l=fetch(addr);
+    h=fetch(addr+1);
+   }
+endinstr;
+
+// ?
+instr(0x6c,4);
+   neg;
+endinstr;
+
+// ?
+instr(0x6d,4);
+   ret;
+endinstr;
+
+// ?
+instr(0x6e,4);
+   // im=1;
+   ret;
+endinstr;
+
+// RLD
+instr(0x6f,5);
+   {unsigned char t=fetch(hl);
+    unsigned char u=(a&0x0f)|(t<<4);
+    a=(a&0xf0)|(t>>4);
+    store(hl,u);
+    f=(f&1)|(a&0xa8)|((!a)<<6)|parity(a);
+   }
+endinstr;
+
+// ?
+instr(0x70,8);
+   {unsigned char x;input(x);}
+endinstr;
+
+// ?
+instr(0x71,8);
+   out(c,0);
+endinstr;
+
+// SBC HL,SP
+instr(0x72,11);
+   sbchl(sp);
+endinstr;
+
+// LD (nn),SP
+instr(0x73,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    store2(addr,sp);
+   }
+endinstr;
+
+// ?
+instr(0x74,4);
+   neg;
+endinstr;
+
+// ?
+instr(0x75,4);
+   ret;
+endinstr;
+
+// ?
+instr(0x76,4);
+   im=2;
+endinstr;
+
+// IN A,(C)
+instr(0x78,8);
+   input(a);
+endinstr;
+
+// OUT (C),A
+instr(0x79,8);
+   out(c,a);
+endinstr;
+
+// ADC HL,SP
+instr(0x7a,11);
+   adchl(sp);
+endinstr;
+
+// LD SP,(nn)
+instr(0x7b,16);
+   {unsigned short addr=fetch2(pc);
+    pc+=2;
+    sp=fetch2(addr);
+   }
+endinstr;
+
+// ?
+instr(0x7c,4);
+   neg;
+endinstr;
+
+// ?
+instr(0x7d,4);
+   ret;
+endinstr;
+
+// ?
+instr(0x7e,4);
+   im=3;
+endinstr;
+
+// LDI
+instr(0xa0,12);
+   {unsigned char x=fetch(hl);
+    store(de,x);
+    if(!++l)h++;
+    if(!++e)d++;
+    if(!c--)b--;
+    f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
+   }
+endinstr;
+
+// CPI
+instr(0xa1,12);
+   {unsigned char carry=cy;
+    cpa(fetch(hl));
+    if(!++l)h++;
+    if(!c--)b--;
+    f=(f&0xfa)|carry|(((b|c)>0)<<2);
+   }
+endinstr;
+
+// INI
+instr(0xa2,12);
+   {unsigned char t=in(c);
+    store(hl,t);
+    if(!++l)h++;
+    b--;
+    f=(b&0xa8)|((!b)<<6)|2|((parity(b)^c)&4);
+    }
+endinstr;
+
+// OUTI
+instr(0xa3,12); /* I can't determine the correct flags outcome for the
+                   block OUT instructions.  Spec says that the carry
+                   flag is left unchanged and N is set to 1, but that
+                   doesn't seem to be the case... */
+   {unsigned char x=fetch(hl);
+   // printf("OUTI %02x %02x\n\r",c,x);
+    out(c,x);
+    if(!++l)h++;
+    b--;
+    f=(f&1)|0x12|(b&0xa8)|((!b)<<6);
+   // f=(f & 0xBF)|2|((b==0)<<6);
+   
+   }
+endinstr;
+
+// LDD
+instr(0xa8,12);
+   {unsigned char x=fetch(hl);
+    store(de,x);
+    if(!l--)h--;
+    if(!e--)d--;
+    if(!c--)b--;
+    f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
+   }
+endinstr;
+
+// CPD
+instr(0xa9,12);
+   {unsigned char carry=cy;
+    cpa(fetch(hl));
+    if(!l--)h--;
+    if(!c--)b--;
+    f=(f&0xfa)|carry|(((b|c)>0)<<2);
+   }
+endinstr;
+
+// IND
+instr(0xaa,12);
+   {unsigned char t=in(c);
+    store(hl,t);
+    if(!l--)h--;
+    b--;
+//    f=(f & 0xBF)|2|((!b)<<6);
+
+    f=(b&0xa8)|((b>0)<<6)|2|((parity(b)^c^4)&4);
+   }
+endinstr;
+
+// OUTD
+instr(0xab,12);
+   {unsigned char x=fetch(hl);
+    out(c,x);
+    if(!l--)h--;
+    b--;
+    f=(f&1)|0x12|(b&0xa8)|((!b)<<6);
+   }
+endinstr;
+
+/* Note: the Z80 implements "*R" as "*" followed by JR -2.  No reason
+   to change this... */
+
+// LDIR
+instr(0xb0,12);
+   {unsigned char x=fetch(hl);
+    store(de,x);
+    if(!++l)h++;
+    if(!++e)d++;
+    if(!c--)b--;
+    f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
+    if(b|c)pc-=2;
+   }
+endinstr;
+
+// CPIR
+instr(0xb1,12);
+   {unsigned char carry=cy;
+    cpa(fetch(hl));
+    if(!++l)h++;
+    if(!c--)b--;
+    f=(f&0xfa)|carry|(((b|c)>0)<<2);
+    if((f&0x44)==4)pc-=2;
+   }
+endinstr;
+
+// INIR
+instr(0xb2,12);
+   {unsigned char t=in(c);
+    store(hl,t);
+    if(!++l)h++;
+    b--;
+    f=(b&0xa8)|((!b)<<6)|2|((parity(b)^c)&4);
+   // f=(f & 0xBF)|2|((!b)<<6);
+    if(b)pc-=2;
+   }
+endinstr;
+
+// OTIR
+instr(0xb3,12);
+   {unsigned char x=fetch(hl);
+    out(c,x);
+    if(!++l)h++;
+    b--;
+    f=(f&1)|0x12|(b&0xa8)|((!b)<<6);
+    if(b)pc-=2;
+   }
+endinstr;
+
+// LDDR
+instr(0xb8,12);
+   {unsigned char x=fetch(hl);
+    store(de,x);
+    if(!l--)h--;
+    if(!e--)d--;
+    if(!c--)b--;
+    f=(f&0xc1)|(x&0x28)|(((b|c)>0)<<2);
+    if(b|c)pc-=2;
+   }
+endinstr;
+
+// CPDR
+instr(0xb9,12);
+   {unsigned char carry=cy;
+    cpa(fetch(hl));
+    if(!l--)h--;
+    if(!c--)b--;
+    f=(f&0xfa)|carry|(((b|c)>0)<<2);
+    if((f&0x44)==4)pc-=2;
+   }
+endinstr;
+
+// INDR
+instr(0xba,12);
+   {unsigned char t=in(c);
+    store(hl,t);
+    if(!l--)h--;
+    b--;
+  f=(b&0xa8)|((!b)<<6)|2|((parity(b)^c^4)&4);
+  // f=(f & 0xBF)|2|((!b)<<6);
+
+    if(b)pc-=2;
+   }
+endinstr;
+
+// OTDR
+instr(0xbb,12);
+   {unsigned char x=fetch(hl);
+    out(c,x);
+    if(!l--)h--;
+    b--;
+    f=(f&1)|0x12|(b&0xa8)|((!b)<<6);
+    if(b)pc-=2;
+   }
+endinstr;
+
+}}