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

z80/edops.h

Committer:
gertk
Date:
2011-06-29
Revision:
0:806c2f2a7d47

File content as of revision 0:806c2f2a7d47:

/* 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;

}}