z80, fix sms interrupt handling in cz80
authorkub <derkub@gmail.com>
Wed, 6 Oct 2021 17:45:37 +0000 (19:45 +0200)
committerkub <derkub@gmail.com>
Wed, 6 Oct 2021 17:46:39 +0000 (19:46 +0200)
cpu/cz80/cz80.c
cpu/cz80/cz80.h
cpu/cz80/cz80_op.c
cpu/cz80/cz80_opED.c
cpu/cz80/cz80macro.h

index 82de13f..41d5819 100644 (file)
@@ -199,7 +199,6 @@ void Cz80_Init(cz80_struc *CPU)
        CPU->pzR16[3] = pzAF;\r
 \r
        zIX = zIY = 0xffff;\r
-       zF = ZF;\r
 \r
        CPU->Interrupt_Callback = Cz80_Interrupt_Callback;\r
 }\r
@@ -245,7 +244,6 @@ INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles)
        UINT32 adr = 0;\r
        UINT32 res;\r
        UINT32 val;\r
-       int afterEI = 0;\r
        union16 *data;\r
 \r
        PC = CPU->PC;\r
@@ -255,33 +253,36 @@ INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles)
        CPU->ICount = cycles - CPU->ExtraCycles;\r
        CPU->ExtraCycles = 0;\r
 \r
-       if (!CPU->HaltState)\r
-       {\r
 Cz80_Exec:\r
-               if (CPU->ICount > 0)\r
+       if (CPU->Status)\r
+       {\r
+               if (CPU->Status & CZ80_HAS_NMI)\r
                {\r
+                       zIFF1 = 0;\r
+                       CPU->Status &= ~(CZ80_HALTED | CZ80_HAS_NMI);\r
+                       CPU->ExtraCycles += 11;\r
+                       PUSH_16(zRealPC);\r
+                       SET_PC(0x66);\r
+               } else if (CPU->Status & CZ80_HAS_INT)\r
+               {\r
+                       CHECK_INT\r
+               } else if (CPU->Status & CZ80_HALTED)\r
+               {\r
+                       goto Cz80_Exec_End;\r
+               }\r
+               CPU->ICount -= CPU->ExtraCycles;\r
+               CPU->ExtraCycles = 0;\r
+       }\r
+\r
+       if (CPU->ICount > 0)\r
+       {\r
 Cz80_Exec_nocheck:\r
-                       data = pzHL;\r
-                       Opcode = READ_OP();\r
+               data = pzHL;\r
+               Opcode = READ_OP();\r
 #if CZ80_EMULATE_R_EXACTLY\r
-                       zR++;\r
+               zR++;\r
 #endif\r
-                       #include "cz80_op.c"\r
-               }\r
-\r
-               if (afterEI)\r
-               {\r
-                       afterEI = 0;\r
-Cz80_Check_Interrupt:\r
-                       if (CPU->IRQState != CLEAR_LINE)\r
-                       {\r
-                               CHECK_INT\r
-                       }\r
-                       CPU->ICount -= CPU->ExtraCycles;\r
-                       CPU->ExtraCycles = 0;\r
-                       if (!CPU->HaltState)\r
-                               goto Cz80_Exec;\r
-               }\r
+               #include "cz80_op.c"\r
        }\r
 \r
 Cz80_Exec_End:\r
@@ -289,7 +290,7 @@ Cz80_Exec_End:
 #if CZ80_ENCRYPTED_ROM\r
        CPU->OPBase = OPBase;\r
 #endif\r
-       if (!(CPU->HaltState && CPU->ICount > 0))\r
+       if (!((CPU->Status & CZ80_HALTED) && CPU->ICount > 0))\r
                cycles -= CPU->ICount;\r
        CPU->ICount = 0;\r
 #if !CZ80_EMULATE_R_EXACTLY\r
@@ -308,36 +309,23 @@ void Cz80_Set_IRQ(cz80_struc *CPU, INT32 line, INT32 state)
 {\r
        if (line == IRQ_LINE_NMI)\r
        {\r
-               zIFF1 = 0;\r
-               CPU->ExtraCycles += 11;\r
-               CPU->HaltState = 0;\r
-               PUSH_16(CPU->PC - CPU->BasePC)\r
-               Cz80_Set_Reg(CPU, CZ80_PC, 0x66);\r
-       }\r
-       else\r
+               if (state)\r
+                       CPU->Status |= CZ80_HAS_NMI;\r
+               else\r
+                       CPU->Status &= ~CZ80_HAS_NMI;\r
+       } else\r
        {\r
+               CPU->IRQLine = line;\r
                CPU->IRQState = state;\r
-\r
-               if (state != CLEAR_LINE)\r
+               if (state)\r
                {\r
-                       FPTR PC = CPU->PC;\r
-#if CZ80_ENCRYPTED_ROM\r
-                       FPTR OPBase = CPU->OPBase;\r
-#endif\r
-\r
-                       CPU->IRQLine = line;\r
-                       CHECK_INT\r
-                       CPU->PC = PC;\r
-#if CZ80_ENCRYPTED_ROM\r
-                       CPU->OPBase = OPBase;\r
-#endif\r
+                       if (zIFF1)\r
+                               CPU->Status |= CZ80_HAS_INT;\r
+               } else\r
+               {\r
+                       CPU->Status &= ~CZ80_HAS_INT;\r
                }\r
        }\r
-       if (CPU->ICount > 0)\r
-       {\r
-               CPU->ICount -= CPU->ExtraCycles;\r
-               CPU->ExtraCycles  = 0;\r
-       }\r
 }\r
 \r
 \r
@@ -366,7 +354,7 @@ UINT32 Cz80_Get_Reg(cz80_struc *CPU, INT32 regnum)
        case CZ80_IM:   return zIM;\r
        case CZ80_IFF1: return zIFF1;\r
        case CZ80_IFF2: return zIFF2;\r
-       case CZ80_HALT: return CPU->HaltState;\r
+       case CZ80_HALT: return CPU->Status & CZ80_HALTED;\r
        case CZ80_IRQ:  return CPU->IRQState;\r
        default: return 0;\r
        }\r
@@ -405,7 +393,7 @@ void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 val)
        case CZ80_IM:   zIM = val; break;\r
        case CZ80_IFF1: zIFF1 = val ? (1 << 2) : 0; break;\r
        case CZ80_IFF2: zIFF2 = val ? (1 << 2) : 0; break;\r
-       case CZ80_HALT: CPU->HaltState = val; break;\r
+       case CZ80_HALT: CPU->Status = !!val * CZ80_HALTED; break;\r
        case CZ80_IRQ:  CPU->IRQState = val; break;\r
        default: break;\r
        }\r
index 21be4ee..a49d1f1 100644 (file)
@@ -170,6 +170,10 @@ extern "C" {
 #define CZ80_IFF_SFT   CZ80_PF_SFT\r
 #define CZ80_IFF               CZ80_PF\r
 \r
+#define        CZ80_HAS_INT    0x1\r
+#define        CZ80_HAS_NMI    0x2\r
+#define        CZ80_HALTED     0x4\r
+\r
 #ifndef IRQ_LINE_STATE\r
 #define IRQ_LINE_STATE\r
 #define CLEAR_LINE             0               /* clear (a fired, held or pulsed) line */\r
@@ -247,7 +251,7 @@ typedef struct cz80_t
 \r
        UINT8 I;\r
        UINT8 IM;\r
-       UINT8 HaltState;\r
+       UINT8 Status;\r
        UINT8 dummy;\r
 \r
        INT32 IRQLine;\r
index 60810f1..a46210e 100644 (file)
@@ -686,8 +686,8 @@ OP_CCF:
 \r
        OP(0x76):   // HALT\r
 OP_HALT:\r
-               CPU->HaltState = 1;\r
-               goto Cz80_Check_Interrupt;\r
+               CPU->Status |= CZ80_HALTED;\r
+               RET(4)\r
 \r
        OP(0xf3):   // DI\r
 OP_DI:\r
@@ -709,9 +709,12 @@ OP_EI:
                                zR++;\r
 #endif\r
                        }\r
-                       afterEI = 1;\r
-                       CPU->ExtraCycles += 1 - CPU->ICount;\r
-                       CPU->ICount = 1;\r
+                       if (CPU->IRQState)\r
+                       {\r
+                               CPU->Status |= CZ80_HAS_INT;\r
+                               CPU->ExtraCycles -= CPU->ICount;\r
+                               CPU->ICount = 0;\r
+                       }\r
                }\r
                else zIFF2 = (1 << 2);\r
                goto Cz80_Exec_nocheck;\r
index 875eae6..eb9f6ee 100644 (file)
@@ -421,8 +421,7 @@ OP_SBC16:
                        zIFF1 = (1 << 2);\r
                        if (CPU->IRQState)\r
                        {\r
-                               USE_CYCLES(10)\r
-                               goto Cz80_Check_Interrupt;\r
+                               CPU->Status |= CZ80_HAS_INT;\r
                        }\r
                }\r
                else zIFF1 = zIFF2;\r
@@ -492,23 +491,27 @@ OP_LDX:
 -----------------------------------------*/\r
 \r
        OPED(0xb0): // LDIR\r
+               if (zBC != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = READ_MEM8(zHL++);\r
                        WRITE_MEM8(zDE++, val);\r
                        zBC--;\r
-                       USE_CYCLES(17)\r
-               } while (zBC && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zBC > 1 && (CPU->ICount > 0) && !CPU->Status);\r
                goto OP_LDXR;\r
 \r
        OPED(0xb8): // LDDR\r
+               if (zBC != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = READ_MEM8(zHL--);\r
                        WRITE_MEM8(zDE--, val);\r
                        zBC--;\r
-                       USE_CYCLES(17)\r
-               } while (zBC && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zBC > 1 && (CPU->ICount > 0) && !CPU->Status);\r
 \r
 OP_LDXR:\r
                F = zF & (SF | ZF | CF);\r
@@ -517,14 +520,14 @@ OP_LDXR:
                if (zBC)\r
                {\r
                        zF = F | VF;\r
-                       PC -= 2;\r
 #if CZ80_EMULATE_R_EXACTLY\r
                        zR--;\r
 #endif\r
-                       goto Cz80_Exec_End;\r
+                       ADD_CYCLES(4)\r
+                       goto Cz80_Exec;\r
                }\r
                zF = F;\r
-               ADD_CYCLES(5)\r
+               ADD_CYCLES(4+5)\r
                goto Cz80_Exec;\r
 \r
 /*-----------------------------------------\r
@@ -553,6 +556,8 @@ OP_CPX:
 -----------------------------------------*/\r
 \r
        OPED(0xb1): // CPIR\r
+               if (zBC != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = READ_MEM8(zHL++);\r
@@ -564,11 +569,13 @@ OP_CPX:
                        if (res & 0x08) F |= XF;\r
                        if (zBC) F |= VF;\r
                        zF = F;\r
-                       USE_CYCLES(17)\r
-               } while (zBC && !(F & ZF) && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zBC > 1 && !(F & ZF) && (CPU->ICount > 0) && !CPU->Status);\r
                goto OP_CPXR;\r
 \r
        OPED(0xb9): // CPDR\r
+               if (zBC != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = READ_MEM8(zHL--);\r
@@ -580,19 +587,19 @@ OP_CPX:
                        if (res & 0x08) F |= XF;\r
                        if (zBC) F |= VF;\r
                        zF = F;\r
-                       USE_CYCLES(17)\r
-               } while (zBC && !(F & ZF) && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zBC > 1 && !(F & ZF) && (CPU->ICount > 0) && !CPU->Status);\r
 \r
 OP_CPXR:\r
                if (zBC && !(F & ZF))\r
                {\r
-                       PC -= 2;\r
 #if CZ80_EMULATE_R_EXACTLY\r
                        zR--;\r
 #endif\r
-                       goto Cz80_Exec_End;\r
+                       ADD_CYCLES(4)\r
+                       goto Cz80_Exec;\r
                }\r
-               ADD_CYCLES(5)\r
+               ADD_CYCLES(4+5)\r
                goto Cz80_Exec;\r
 \r
 /*-----------------------------------------\r
@@ -614,7 +621,7 @@ OP_INX:
                F = SZ[zB];\r
                res = ((UINT32)(zC - 1) & 0xff) + (UINT32)val;\r
                if (val & SF) F |= NF;\r
-               if (res & 0x100) F |= HF | CF;\r
+               if (res < val) F |= HF | CF;\r
                F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;\r
                zF = F;\r
                RET(12)\r
@@ -624,40 +631,44 @@ OP_INX:
 -----------------------------------------*/\r
 \r
        OPED(0xb2): // INIR\r
+               if (zB != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = IN(zBC);\r
                        zB--;\r
                        WRITE_MEM8(zHL++, val);\r
-                       USE_CYCLES(17)\r
-               } while (zB && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status);\r
                goto OP_INXR;\r
 \r
        OPED(0xba): // INDR\r
+               if (zB != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = IN(zBC);\r
                        zB--;\r
                        WRITE_MEM8(zHL--, val);\r
-                       USE_CYCLES(17)\r
-               } while (zB && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status);\r
 \r
 OP_INXR:\r
                F = SZ[zB];\r
                res = ((UINT32)(zC - 1) & 0xff) + (UINT32)val;\r
                if (val & SF) F |= NF;\r
-               if (res & 0x100) F |= HF | CF;\r
+               if (res < val) F |= HF | CF;\r
                F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;\r
                zF = F;\r
                if (zB)\r
                {\r
-                       PC -= 2;\r
 #if CZ80_EMULATE_R_EXACTLY\r
                        zR--;\r
 #endif\r
-                       goto Cz80_Exec_End;\r
+                       ADD_CYCLES(4)\r
+                       goto Cz80_Exec;\r
                }\r
-               ADD_CYCLES(5);\r
+               ADD_CYCLES(4+5);\r
                goto Cz80_Exec;\r
 \r
 /*-----------------------------------------\r
@@ -679,7 +690,7 @@ OP_OUTX:
                F = SZ[zB];\r
                res = (UINT32)zL + (UINT32)val;\r
                if (val & SF) F |= NF;\r
-               if (res & 0x100) F |= HF | CF;\r
+               if (res < val) F |= HF | CF;\r
                F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;\r
                zF = F;\r
                RET(12)\r
@@ -689,40 +700,44 @@ OP_OUTX:
 -----------------------------------------*/\r
 \r
        OPED(0xb3): // OTIR\r
+               if (zB != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = READ_MEM8(zHL++);\r
                        zB--;\r
                        OUT(zBC, val);\r
-                       USE_CYCLES(17)\r
-               } while (zB && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status);\r
                goto OP_OTXR;\r
 \r
        OPED(0xbb): // OTDR\r
+               if (zB != 1)\r
+                       PC -= 2;\r
                do\r
                {\r
                        val = READ_MEM8(zHL--);\r
                        zB--;\r
                        OUT(zBC, val);\r
-                       USE_CYCLES(17)\r
-               } while (zB && (CPU->ICount > 0));\r
+                       USE_CYCLES(21)\r
+               } while (zB > 1 && (CPU->ICount > 0) && !CPU->Status);\r
 \r
 OP_OTXR:\r
                F = SZ[zB];\r
                res = (UINT32)zL + (UINT32)val;\r
                if (val & SF) F |= NF;\r
-               if (res & 0x100) F |= HF | CF;\r
+               if (res < val) F |= HF | CF;\r
                F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;\r
                zF = F;\r
                if (zB)\r
                {\r
-                       PC -= 2;\r
 #if CZ80_EMULATE_R_EXACTLY\r
                        zR--;\r
 #endif\r
-                       goto Cz80_Exec_End;\r
+                       ADD_CYCLES(4)\r
+                       goto Cz80_Exec;\r
                }\r
-               ADD_CYCLES(5)\r
+               ADD_CYCLES(4+5)\r
                goto Cz80_Exec;\r
        }\r
 \r
index 5cabba3..edd6d9d 100644 (file)
@@ -90,7 +90,7 @@
                if (CPU->IRQState == HOLD_LINE)                         \\r
                        CPU->IRQState = CLEAR_LINE;                     \\r
                                                                        \\r
-               CPU->HaltState = 0;                                     \\r
+               CPU->Status &= ~(CZ80_HALTED|CZ80_HAS_INT);             \\r
                zIFF1 = zIFF2 = 0;                                      \\r
                IntVect = CPU->Interrupt_Callback(CPU->IRQLine);        \\r
                                                                        \\r