libz80 with compilation problems (uses up to much ram)

Revision:
0:b612024f5aee
Child:
1:78a39c3a30f6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/z80.c	Thu Mar 10 20:32:59 2011 +0000
@@ -0,0 +1,786 @@
+/* =========================================================
+ *  libz80 - Z80 emulation library
+ * =========================================================
+ *
+ * (C) Gabriel Gambetta (ggambett@adinet.com.uy) 2000 - 2002
+ *
+ * Version 1.99
+ *
+ * ---------------------------------------------------------
+ *
+ *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "z80.h"
+#include "string.h"
+
+
+#define BR (ctx->R1.br)
+#define WR (ctx->R1.wr)
+
+#define SETFLAG(F) setFlag(ctx, F)
+#define RESFLAG(F) resFlag(ctx, F)
+#define GETFLAG(F) getFlag(ctx, F)
+
+#define VALFLAG(F,V) valFlag(ctx, F, V)
+
+
+/* ---------------------------------------------------------
+ *  Flag tricks
+ * --------------------------------------------------------- 
+ *
+ * To avoid repeating entries in the spec files, many operations that look similar are treated as special cases
+ * of a more general operation.
+ *
+ * For example, ADD and ADC are similar in syntax and operation - the difference is that ADC takes the carry flag
+ * into account.
+ *
+ * So we define a general operation doArithmetic(...) which accepts a boolean parameter specifying wheter to do
+ * a Carry-operation or not. Then, when we parse, we can say
+ *
+ * (ADD|ADC) ....
+ *        doArithmetic(FLAG_FOR_%1)
+ *
+ * and everything works fine.
+ *
+ */
+ 
+/* Flags for doIncDec() */
+static const int ID_INC = 0;
+static const int ID_DEC = 1;
+
+/* Flags for enable / disable interrupts */
+static const int IE_DI = 0;
+static const int IE_EI = 1;
+
+/* Flags for doSetRes() */
+static const int SR_RES = 0;
+static const int SR_SET = 1;
+
+/* Flags for logical / arithmetic operations */
+static const int IA_L = 0;
+static const int IA_A = 1;
+
+/* Flags for doArithmetic() - F1 = withCarry, F2 = isSub */
+static const int F1_ADC = 1;
+static const int F1_SBC = 1;
+static const int F1_ADD = 0;
+static const int F1_SUB = 0;
+
+static const int F2_ADC = 0;
+static const int F2_SBC = 1;
+static const int F2_ADD = 0;
+static const int F2_SUB = 1;
+
+
+/* ---------------------------------------------------------
+ *  The opcode implementations
+ * --------------------------------------------------------- 
+ */
+#include "opcodes_decl.h"
+
+typedef enum
+{
+    OP_NONE,
+    OP_BYTE,
+    OP_OFFSET,
+    OP_WORD    
+} Z80OperandType;
+
+typedef void (*Z80OpcodeFunc) (Z80Context* ctx); 
+
+struct Z80OpcodeEntry
+{
+    Z80OpcodeFunc func;
+    
+    int operand_type;
+    char* format;    
+    
+    struct Z80OpcodeTable* table;
+};
+
+
+struct Z80OpcodeTable
+{
+    int opcode_offset;
+    struct Z80OpcodeEntry entries[256];
+};
+
+
+#include "opcodes_table.h"
+
+
+/* ---------------------------------------------------------
+ *  Data operations
+ * --------------------------------------------------------- 
+ */ 
+static void write8 (Z80Context* ctx, ushort addr, byte val)
+{
+    ctx->memWrite(ctx->memParam, addr, val);    
+}
+
+
+static void write16 (Z80Context* ctx, ushort addr, ushort val)
+{
+    ctx->memWrite(ctx->memParam, addr, (byte)(val & 0xFF));
+    val >>= 8;
+    addr++;
+    ctx->memWrite(ctx->memParam, addr, (byte)(val & 0xFF));
+}
+
+
+static byte read8 (Z80Context* ctx, ushort addr)
+{
+    return ctx->memRead(ctx->memParam, addr);    
+}
+
+
+static ushort read16 (Z80Context* ctx, ushort addr)
+{
+    return (ctx->memRead(ctx->memParam, addr) | (ctx->memRead(ctx->memParam, ++addr) << 8));
+}
+
+
+static byte ioRead (Z80Context* ctx, ushort addr)
+{
+    return ctx->ioRead(ctx->ioParam, addr);    
+}
+
+
+static void ioWrite (Z80Context* ctx, ushort addr, byte val)
+{
+    ctx->ioWrite(ctx->ioParam, addr, val);    
+}
+
+
+/* ---------------------------------------------------------
+ *  Flag operations
+ * --------------------------------------------------------- 
+ */
+ 
+/** Sets a flag */
+static void setFlag(Z80Context* ctx, Z80Flags flag)
+{
+    BR.F |= flag;
+}
+
+/** Resets a flag */
+static void resFlag(Z80Context* ctx, Z80Flags flag)
+{
+    BR.F &= ~flag;
+}
+
+/** Puts a value in a flag */
+static void valFlag(Z80Context* ctx, Z80Flags flag, int val)
+{
+    if (val)
+        SETFLAG(flag);
+    else
+        RESFLAG(flag);
+}
+
+/** Returns a flag */
+static int getFlag(Z80Context* ctx, Z80Flags flag)
+{
+    return (BR.F & flag) != 0;
+}
+
+
+/* ---------------------------------------------------------
+ *  Flag adjustments
+ * --------------------------------------------------------- 
+ */
+
+static int parityBit[256] = { 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 
+    0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
+
+
+static void adjustFlags (Z80Context* ctx, byte val)
+{
+    VALFLAG(F_5, (val & F_5) != 0);
+    VALFLAG(F_3, (val & F_3) != 0);
+}
+
+
+static void adjustFlagSZP (Z80Context* ctx, byte val)
+{
+    VALFLAG(F_S, (val & 0x80) != 0);
+    VALFLAG(F_Z, (val == 0));
+    VALFLAG(F_PV, parityBit[val]);
+}
+
+
+// Adjust flags after AND, OR, XOR
+static void adjustLogicFlag (Z80Context* ctx, int flagH)
+{
+    VALFLAG(F_S, (BR.A & 0x80) != 0);
+    VALFLAG(F_Z, (BR.A == 0));
+    VALFLAG(F_H, flagH);
+    VALFLAG(F_N, 0);
+    VALFLAG(F_C, 0);
+    VALFLAG(F_PV, parityBit[BR.A]);
+
+    adjustFlags(ctx, BR.A);
+}
+
+
+/* ---------------------------------------------------------
+ *  Condition checks
+ * --------------------------------------------------------- 
+ */
+ 
+typedef enum
+{
+    C_,
+    C_Z,
+    C_NZ,
+    C_C,
+    C_NC,
+    C_M,
+    C_P,
+    C_PE,
+    C_PO        
+} Z80Condition;
+
+static int condition(Z80Context* ctx, Z80Condition cond)
+{
+    if (cond == C_)
+        return GETFLAG(F_);
+        
+    if (cond == C_Z)
+        return !GETFLAG(F_Z);
+    
+    if (cond == C_NZ)
+        return GETFLAG(F_Z);
+    
+    if (cond == C_C)
+        return GETFLAG(F_C);
+    
+    if (cond == C_NC)
+        return !GETFLAG(F_C);
+        
+    if (cond == C_M)
+        return GETFLAG(F_S);
+    
+    if (cond == C_P)
+                return !(GETFLAG(F_S) | GETFLAG(F_Z)); 
+    if (cond == C_PE)
+        return !GETFLAG(F_PV);
+        
+/*    if (cond == C_PO)*/
+        return GETFLAG(F_PV);
+}
+
+
+/* ---------------------------------------------------------
+ *  Generic operations
+ * --------------------------------------------------------- 
+ */
+ 
+ 
+static int doComplement(byte v)
+{
+    if ((v & 0x80) == 0)
+        return v;
+
+    v = ~v;
+    v &= 0x7F;
+    v++;
+
+    return -v;
+}
+
+ 
+/** Do an arithmetic operation (ADD, SUB, ADC, SBC y CP) */
+static byte doArithmetic (Z80Context* ctx, byte value, int withCarry, int isSub)
+{
+    ushort res; /* To detect carry */
+
+    if (isSub)
+    {
+        SETFLAG(F_N);
+        VALFLAG(F_H, (((BR.A & 0x0F) - (value & 0x0F)) & 0x10) != 0);
+        res = BR.A - value;
+        if (withCarry && GETFLAG(F_C))
+            res--;
+    }
+    else
+    {
+        RESFLAG(F_N);
+        VALFLAG(F_H, (((BR.A & 0x0F) + (value & 0x0F)) & 0x10) != 0);
+        res = BR.A + value;
+        if (withCarry && GETFLAG(F_C))
+            res++;
+    }
+    VALFLAG(F_S, ((res & 0x80) != 0));
+    VALFLAG(F_C, ((res & 0x100) != 0));
+    VALFLAG(F_Z, (res == 0));
+    VALFLAG(F_PV, (((BR.A & 0x80) == (value & 0x80)) && ((BR.A & 0x80) != (res & 0x80))) != 0);
+
+    adjustFlags(ctx, BR.A);
+
+    return (byte)(res & 0xFF);
+}
+
+
+static void doAND (Z80Context* ctx, byte value)
+{
+    BR.A &= value;
+    adjustLogicFlag(ctx, 1);
+}
+
+
+static void doOR (Z80Context* ctx, byte value)
+{
+    BR.A |= value;
+    adjustLogicFlag(ctx, 0);
+}
+
+
+static void doXOR (Z80Context* ctx, byte value)
+{
+    BR.A ^= value;
+    adjustLogicFlag(ctx, 0);
+}
+
+
+static void doBIT (Z80Context* ctx, int b, byte val)
+{
+    if (val & (1 << b))
+        RESFLAG(F_Z | F_PV);
+    else
+        SETFLAG(F_Z | F_PV);
+
+    SETFLAG(F_H);
+    RESFLAG(F_N);
+
+    RESFLAG(F_S);
+    if ((b == 7) && !GETFLAG(F_Z))
+        SETFLAG(F_S);
+
+    RESFLAG(F_5);
+    if ((b == 5) && !GETFLAG(F_Z))
+        SETFLAG(F_5);
+
+    RESFLAG(F_3);
+    if ((b == 3) && !GETFLAG(F_Z))
+        SETFLAG(F_3);
+}
+
+
+byte doSetRes (Z80Context* ctx, int bit, int pos, byte val)
+{
+    if (bit)
+        val |= (1 << pos);
+    else
+        val &= ~(1 << pos);
+    return val;
+}
+
+
+
+static byte doIncDec (Z80Context* ctx, byte val, int isDec)
+{
+    if (isDec)
+    {
+        VALFLAG(F_PV, (val & 0x80) && !((val - 1) & 0x80));
+        val--;
+        VALFLAG(F_H, !(val & 0x0F));
+    }
+    else
+    {
+        VALFLAG(F_PV, !(val & 0x80) && ((val + 1) & 0x80));
+        val++;
+        VALFLAG(F_H, !(val & 0x0F));
+    }
+
+    VALFLAG(F_S, ((val & 0x80) != 0));
+    VALFLAG(F_Z, (val == 0));
+    VALFLAG(F_N, isDec);
+
+    adjustFlags(ctx, BR.A);
+
+    return val;
+}
+
+
+static byte doRLC (Z80Context* ctx, int adjFlags, byte val)
+{
+    VALFLAG(F_C, (val & 0x80) != 0);
+    val <<= 1;
+    val |= (byte)GETFLAG(F_C);
+
+    adjustFlags(ctx, val);
+    RESFLAG(F_H | F_N);
+
+    if (adjFlags)
+        adjustFlagSZP(ctx, val);
+
+    return val;
+}
+
+
+static byte doRL (Z80Context* ctx, int adjFlags, byte val)
+{
+    int CY = GETFLAG(F_C);
+    VALFLAG(F_C, (val & 0x80) != 0);
+    val <<= 1;
+    val |= (byte)CY;
+
+    adjustFlags(ctx, val);
+    RESFLAG(F_H | F_N);
+
+    if (adjFlags)
+        adjustFlagSZP(ctx, val);
+
+    return val;
+}
+
+
+static byte doRRC (Z80Context* ctx, int adjFlags, byte val)
+{
+    VALFLAG(F_C, (val & 0x01) != 0);
+    val >>= 1;
+    val |= ((byte)GETFLAG(F_C) << 7);
+
+    adjustFlags(ctx, val);
+    RESFLAG(F_H | F_N);
+
+    if (adjFlags)
+        adjustFlagSZP(ctx, val);
+
+    return val;
+}
+
+
+static byte doRR (Z80Context* ctx, int adjFlags, byte val)
+{
+    int CY = GETFLAG(F_C);
+    VALFLAG(F_C, (val & 0x01));
+    val >>= 1;
+    val |= (CY << 7);
+
+    adjustFlags(ctx, val);
+    RESFLAG(F_H | F_N);
+
+    if (adjFlags)
+        adjustFlagSZP(ctx, val);
+
+    return val;
+}
+
+
+static byte doSL (Z80Context* ctx, byte val, int isArith)
+{
+    VALFLAG(F_C, (val & 0x80) != 0);
+    val <<= 1;
+
+    if (!isArith)
+        val |= 1;
+
+    adjustFlags(ctx, val);
+    RESFLAG(F_H | F_N);
+    adjustFlagSZP(ctx, val);
+
+    return val;
+}
+
+
+static byte doSR (Z80Context* ctx, byte val, int isArith)
+{
+    int b = ((val & 0x80) != 0);
+
+    VALFLAG(F_C, (val & 0x01) != 0);
+    val >>= 1;
+
+    if (isArith)
+        val |= (byte)b;
+
+    adjustFlags(ctx, val);
+    RESFLAG(F_H | F_N);
+    adjustFlagSZP(ctx, val);
+
+    return val;
+}
+
+
+static void doPush (Z80Context* ctx, ushort val)
+{
+    WR.SP--;
+    write16(ctx, WR.SP, val);
+    WR.SP--;
+}
+
+
+static ushort doPop (Z80Context* ctx)
+{    
+    ushort val;
+    
+    WR.SP++;
+    val = read16(ctx, WR.SP);
+    WR.SP++;
+
+    return val;
+}
+
+
+/* The DAA opcode
+ * According to the value in A and the flags set, add a value to A
+ *
+ * Flags set   Byte (0..9)(0..9) 
+ * -------------------------------------------- 
+ * (None)   + &00 
+ * Carry:+ &60 
+ * Subtract:+ &00 
+ * Subtract+Carry:+ &A0 
+ * Half-carry:+ &06 
+ * Half-carry+Carry:+ &66 
+ * Half-carry+Subtract:+ &FA 
+ * Half-carry+Subtract+Carry:+ &9A 
+ * 
+ * Flags set   Byte (0..9)(A..F) 
+ * -------------------------------------------- 
+ * (None)   + &06 
+ * Carry:+ &66 
+ * Subtract:+ &00 
+ * Subtract+Carry:+ &a0 
+ * Half-carry:+ &06 
+ * Half-carry+Carry:+ &66 
+ * Half-carry+Subtract:+ &fa 
+ * Half-carry+Subtract+Carry:+ &9A 
+ * 
+ * Flags set   Byte (A..F)(0..9) 
+ * -------------------------------------------- 
+ * (None)   + &60 
+ * Carry:+ &60 
+ * Subtract:+ &00 
+ * Subtract+Carry:+ &A0 
+ * Half-carry:+ &66 
+ * Half-carry+Carry:+ &66 
+ * Half-carry+Subtract:+ &fa 
+ * Half-carry+Subtract+Carry:+ &9A 
+ * 
+ * Flags set   Byte (A..F)(A..F) 
+ * -------------------------------------------- 
+ * (None)   + &66 
+ * Carry:+ &66 
+ * Subtract:+ &00 
+ * Subtract+Carry:+ &a0 
+ * Half-carry:+ &66 
+ * Half-carry+Carry:+ &66 
+ * Half-carry+Subtract:+ &fa 
+ * Half-carry+Subtract+Carry:+ &9A 
+ */    
+
+static int DAA_BYTETYPE[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
+
+static byte DAA_ADJUSTMENT[4][8] = { 
+    { 0x00, 0x60, 0x00, 0xA0, 0x06, 0x66, 0xFA, 0x9A }, 
+    { 0x06, 0x66, 0x00, 0xA0, 0x06, 0x66, 0xFA, 0x9A },
+    { 0x60, 0x60, 0x00, 0xA0, 0x66, 0x66, 0xFA, 0x9A },
+    { 0x66, 0x66, 0x00, 0xA0, 0x66, 0x66, 0xFA, 0x9A } };
+        
+static void doDAA (Z80Context* ctx)
+{
+    /* (0..9)(0..9) = 0 */
+    /* (0..9)(A..F) = 1 */
+    /* (A..F)(0..9) = 2 */
+    /* (A..F)(A..F) = 3 */
+    int byteType = DAA_BYTETYPE[BR.A] | ((DAA_BYTETYPE[BR.A >> 4]) << 1);    
+    
+    int flagMask = 0;
+    if (GETFLAG(F_C))
+        flagMask |= 1;
+    if (GETFLAG(F_S))
+        flagMask |= 2;
+    if (GETFLAG(F_H))
+        flagMask |= 4;
+    
+    BR.A += DAA_ADJUSTMENT[byteType][flagMask];
+    
+    adjustFlags(ctx, BR.A);
+}
+ 
+#include "opcodes_impl.c"
+
+
+/* ---------------------------------------------------------
+ *  The top-level functions
+ * --------------------------------------------------------- 
+ */ 
+void Z80Execute (Z80Context* ctx)
+{
+    struct Z80OpcodeTable* current = &opcodes_main;
+    struct Z80OpcodeEntry* entries = current->entries;
+    Z80OpcodeFunc func;
+    
+    byte opcode;
+    int offset = 0;
+    do
+    {
+        opcode = read8(ctx, ctx->PC + offset);
+        
+        ctx->PC++;
+        func = entries[opcode].func;
+        if (func != NULL)
+        {            
+            ctx->PC -= offset;
+            func(ctx);
+            ctx->PC += offset;
+            break;
+        }
+        else if (entries[opcode].table != NULL)
+        {
+            current = entries[opcode].table;
+            entries = current->entries;
+            offset = current->opcode_offset;
+        }
+
+        else
+        {
+            /* NOP */
+            break;    
+        }
+    } while(1);
+}
+
+
+void Z80Debug (Z80Context* ctx, char* dump, char* decode)
+{
+    char tmp[20];    
+    struct Z80OpcodeTable* current = &opcodes_main;
+    struct Z80OpcodeEntry* entries = current->entries;
+    char* fmt;
+    byte opcode;
+    ushort parm;
+    int offset = 0;
+    int PC = ctx->PC;
+    int size = 0;
+    
+    if (dump)
+        dump[0] = 0;
+        
+    if (decode)
+        decode[0] = 0;
+
+    do
+    {
+        opcode = read8(ctx, PC + offset);
+        size++;
+        
+        PC++;
+        ctx->R++;
+        fmt = entries[opcode].format;
+        if (fmt != NULL)
+        {            
+            PC -= offset;
+            parm = read16(ctx, PC);
+        
+            if (entries[opcode].operand_type == OP_NONE)
+                size++;
+            else
+                size += 2;
+            if (entries[opcode].operand_type != OP_WORD)
+            {
+                parm &= 0xFF;
+                size--;
+            }
+                
+            if (decode)
+                sprintf(decode, fmt, parm);
+            
+            PC += offset;
+            break;
+        }
+        else if (entries[opcode].table != NULL)
+        {
+            current = entries[opcode].table;
+            entries = current->entries;
+            offset = current->opcode_offset;
+        }
+
+        else
+        {
+            if (decode != NULL)
+                strcpy(decode, "NOP (ignored)");
+            break;    
+        }
+    } while(1);    
+    
+    if (dump)
+    {
+        for (offset = 0; offset < size; offset++)
+        {
+            sprintf(tmp, "%02X", read8(ctx, ctx->PC + offset));
+            strcat(dump, tmp);
+        }        
+    }
+}
+
+
+void Z80RESET (Z80Context* ctx)
+{
+    ctx->PC = 0x0000;
+    BR.F = 0;
+    ctx->IM = 0;
+    ctx->IFF1 = ctx->IFF2 = 0;    
+}
+
+
+void Z80INT (Z80Context* ctx, byte value)
+{
+    if (!ctx->IFF1)
+        return;
+
+    if (ctx->IM == 0)
+    {      
+        /* FIXME What to do? */
+/*        opcode = Val;
+        execute();*/
+    }
+    else if (ctx->IM == 1)
+    {
+        doPush(ctx, ctx->PC);
+        ctx->PC = 0x0038;
+    }
+    else if (ctx->IM == 2)
+    {
+        doPush(ctx, ctx->PC);
+        ctx->PC = (ctx->I << 8) | value;
+    }
+}
+
+
+void Z80NMI (Z80Context* ctx)
+{
+    ctx->IFF1 = 0;
+    doPush(ctx, ctx->PC);
+    ctx->PC = 0x0066;    
+}