OSDN Git Service

[General] Convert sourcecode's CRLF format: DOS(WINDOWS) to Unix, to apply patches...
[csp-qt/common_source_project-fm7.git] / source / src / vm / mame / emu / cpu / h6280 / h6280.c
index 92f4fd8..14467da 100644 (file)
-/*****************************************************************************\r
-\r
-    h6280.c - Portable HuC6280 emulator\r
-\r
-    Copyright Bryan McPhail, mish@tendril.co.uk\r
-\r
-    This source code is based (with permission!) on the 6502 emulator by\r
-    Juergen Buchmueller.  It is released as part of the Mame emulator project.\r
-    Let me know if you intend to use this code in any other project.\r
-\r
-\r
-    NOTICE:\r
-\r
-    This code is around 99% complete!  Several things are unimplemented,\r
-    some due to lack of time, some due to lack of documentation, mainly\r
-    due to lack of programs using these features.\r
-\r
-    csh, csl opcodes are not supported.\r
-\r
-    I am unsure if flag B is set upon execution of rti.\r
-\r
-    Cycle counts should be quite accurate.\r
-\r
-\r
-    Changelog, version 1.02:\r
-        JMP + indirect X (0x7c) opcode fixed.\r
-        SMB + RMB opcodes fixed in disassembler.\r
-        change_pc function calls removed.\r
-        TSB & TRB now set flags properly.\r
-        BIT opcode altered.\r
-\r
-    Changelog, version 1.03:\r
-        Swapped IRQ mask for IRQ1 & IRQ2 (thanks Yasuhiro)\r
-\r
-    Changelog, version 1.04, 28/9/99-22/10/99:\r
-        Adjusted RTI (thanks Karl)\r
-        TST opcodes fixed in disassembler (missing break statements in a case!).\r
-        TST behaviour fixed.\r
-        SMB/RMB/BBS/BBR fixed in disassembler.\r
-\r
-    Changelog, version 1.05, 8/12/99-16/12/99:\r
-        Added CAB's timer implementation (note: irq ack & timer reload are changed).\r
-        Fixed STA IDX.\r
-        Fixed B flag setting on BRK.\r
-        Assumed CSH & CSL to take 2 cycles each.\r
-\r
-        Todo:  Performance could be improved by precalculating timer fire position.\r
-\r
-    Changelog, version 1.06, 4/5/00 - last opcode bug found?\r
-        JMP indirect was doing a EAL++; instead of EAD++; - Obviously causing\r
-        a corrupt read when L = 0xff!  This fixes Bloody Wolf and Trio The Punch!\r
-\r
-    Changelog, version 1.07, 3/9/00:\r
-        Changed timer to be single shot - fixes Crude Buster music in level 1.\r
-\r
-    Changelog, version 1.08, 8/11/05: (Charles MacDonald)\r
-\r
-        Changed timer implementation, no longer single shot and reading the\r
-        timer registers returns the count only. Fixes the following:\r
-        - Mesopotamia: Music tempo & in-game timer\r
-        - Dragon Saber: DDA effects\r
-        - Magical Chase: Music tempo and speed regulation\r
-        - Cadash: Allows the first level to start\r
-        - Turrican: Allows the game to start\r
-\r
-        Changed PLX and PLY to set NZ flags. Fixes:\r
-        - Afterburner: Graphics unpacking\r
-        - Aoi Blink: Collision detection with background\r
-\r
-        Fixed the decimal version of ADC/SBC to *not* update the V flag,\r
-        only the binary ones do.\r
-\r
-        Fixed B flag handling so it is always set outside of an interrupt;\r
-        even after being set by PLP and RTI.\r
-\r
-        Fixed P state after reset to set I and B, leaving T, D cleared and\r
-        NVZC randomized (cleared in this case).\r
-\r
-        Fixed interrupt processing order (Timer has highest priority followed\r
-        by IRQ1 and finally IRQ2).\r
-\r
-    Changelog, version 1.09, 1/07/06: (Rob Bohms)\r
-\r
-        Added emulation of the T flag, fixes PCE Ankuku Densetsu title screen\r
-\r
-    Changelog, version 1.10, 5/09/07: (Wilbert Pol)\r
-\r
-        - Taking of interrupts is delayed to respect a pending instruction already\r
-          in the instruction pipeline; fixes After Burner.\r
-        - Added 1 cycle for decimal mode ADC and SBC instructions.\r
-        - Changed cycle counts for CSH and CSL instructions to 3.\r
-        - Added T flag support to the SBC instruction.\r
-        - Fixed ADC T flag to set the Z flag based on the value read.\r
-        - Added 3 cycle penalty to ADC, AND, EOR, ORA, and SBC instructions\r
-          when the T flag is set.\r
-        - Fixed cycle count and support for 65536 byte blocks for the TAI, TDD,\r
-          TIA, TII, and TIN instructions.\r
-        - Fixed RDWORD macro in the disassembler.\r
-        - Fixed setting of N and V flags in the TST instructions.\r
-        - Removed unneeded debug_mmr code.\r
-        - Fixed TSB and TRB instructions.\r
-        - Added 1 delay when accessing the VDC or VCE areas.\r
-        - Implemented low and high speed cpu modes.\r
-\r
-    Changelog, version 1.11, 18/09/07: (Wilbert Pol)\r
-\r
-        - Improvements to the handling of taking of delayed interrupts.\r
-\r
-******************************************************************************/\r
-\r
-//#include "emu.h"\r
-//#include "debugger.h"\r
-#include "h6280.h"\r
-\r
-static void set_irq_line(h6280_Regs* cpustate, int irqline, int state);\r
-\r
-/* include the macros */\r
-#include "h6280ops.h"\r
-\r
-/* include the opcode macros, functions and function pointer tables */\r
-#include "tblh6280.c"\r
-\r
-/*****************************************************************************/\r
-static CPU_INIT( h6280 )\r
-{\r
-       h6280_Regs *cpustate = (h6280_Regs *)calloc(1, sizeof(h6280_Regs));\r
-\r
-       return cpustate;\r
-}\r
-\r
-static CPU_RESET( h6280 )\r
-{\r
-       int i;\r
-\r
-       /* wipe out the h6280 structure */\r
-       DEVICE *save_program = cpustate->program;\r
-       DEVICE *save_io = cpustate->io;\r
-       memset(cpustate, 0, sizeof(h6280_Regs));\r
-       cpustate->program = save_program;\r
-       cpustate->io = save_io;\r
-\r
-       /* set I and B flags */\r
-       P = _fI | _fB;\r
-\r
-    /* stack starts at 0x01ff */\r
-       cpustate->sp.d = 0x1ff;\r
-\r
-    /* read the reset vector into PC */\r
-       PCL = RDMEM(cpustate, H6280_RESET_VEC);\r
-       PCH = RDMEM(cpustate, (H6280_RESET_VEC+1));\r
-\r
-       /* CPU starts in low speed mode */\r
-    cpustate->clocks_per_cycle = 4;\r
-\r
-       /* timer off by default */\r
-       cpustate->timer_status=0;\r
-       cpustate->timer_load = 128 * 1024;\r
-\r
-    /* clear pending interrupts */\r
-       for (i = 0; i < 3; i++)\r
-               cpustate->irq_state[i] = CLEAR_LINE;\r
-       cpustate->nmi_state = CLEAR_LINE;\r
-\r
-       cpustate->irq_pending = 0;\r
-}\r
-\r
-static CPU_EXECUTE( h6280 )\r
-{\r
-       int in;\r
-\r
-       if (ICount == -1) {\r
-               cpustate->ICount = 1;\r
-       } else {\r
-               cpustate->ICount += ICount;\r
-       }\r
-       int Base_ICount = cpustate->ICount;\r
-\r
-       if ( cpustate->irq_pending == 2 ) {\r
-               cpustate->irq_pending--;\r
-       }\r
-\r
-       /* Execute instructions */\r
-       do\r
-    {\r
-               cpustate->ppc = cpustate->pc;\r
-\r
-               /* Execute 1 instruction */\r
-               in=RDOP();\r
-               PCW++;\r
-               insnh6280[in](cpustate);\r
-\r
-               if ( cpustate->irq_pending ) {\r
-                       if ( cpustate->irq_pending == 1 ) {\r
-                               if ( !(P & _fI) ) {\r
-                                       cpustate->irq_pending--;\r
-                                       CHECK_AND_TAKE_IRQ_LINES;\r
-                               }\r
-                       } else {\r
-                               cpustate->irq_pending--;\r
-                       }\r
-               }\r
-\r
-               /* Check internal timer */\r
-               if(cpustate->timer_status)\r
-               {\r
-                       if(cpustate->timer_value<=0)\r
-                       {\r
-                               if ( ! cpustate->irq_pending )\r
-                                       cpustate->irq_pending = 1;\r
-                               while( cpustate->timer_value <= 0 )\r
-                                       cpustate->timer_value += cpustate->timer_load;\r
-                               set_irq_line(cpustate, 2,ASSERT_LINE);\r
-                       }\r
-               }\r
-       } while (cpustate->ICount > 0);\r
-\r
-       return Base_ICount - cpustate->ICount;\r
-}\r
-\r
-/*****************************************************************************/\r
-\r
-static void set_irq_line(h6280_Regs* cpustate, int irqline, int state)\r
-{\r
-       if (irqline == INPUT_LINE_NMI)\r
-       {\r
-               if ( state != ASSERT_LINE ) return;\r
-               cpustate->nmi_state = state;\r
-               CHECK_IRQ_LINES;\r
-       }\r
-       else if (irqline < 3)\r
-       {\r
-               /* If the state has not changed, just return */\r
-               if ( cpustate->irq_state[irqline] == state )\r
-                       return;\r
-\r
-           cpustate->irq_state[irqline] = state;\r
-\r
-               CHECK_IRQ_LINES;\r
-       }\r
-}\r
-\r
-\r
-\r
-/*****************************************************************************/\r
-\r
-READ8_HANDLER( h6280_irq_status_r )\r
-{\r
-       int status;\r
-\r
-       switch (offset&3)\r
-       {\r
-       default: return 0;\r
-       case 3:\r
-               {\r
-                       status=0;\r
-                       if(cpustate->irq_state[1]!=CLEAR_LINE) status|=1; /* IRQ 2 */\r
-                       if(cpustate->irq_state[0]!=CLEAR_LINE) status|=2; /* IRQ 1 */\r
-                       if(cpustate->irq_state[2]!=CLEAR_LINE) status|=4; /* TIMER */\r
-                       return status;\r
-               }\r
-       case 2: return cpustate->irq_mask;\r
-       }\r
-}\r
-\r
-WRITE8_HANDLER( h6280_irq_status_w )\r
-{\r
-       switch (offset&3)\r
-       {\r
-               case 2: /* Write irq mask */\r
-                       cpustate->irq_mask=data&0x7;\r
-                       CHECK_IRQ_LINES;\r
-                       break;\r
-\r
-               case 3: /* Timer irq ack */\r
-                       set_irq_line(cpustate, 2, CLEAR_LINE);\r
-                       break;\r
-       }\r
-}\r
-\r
-READ8_HANDLER( h6280_timer_r )\r
-{\r
-       /* only returns countdown */\r
-       return ((cpustate->timer_value >> 10)&0x7F);\r
-}\r
-\r
-WRITE8_HANDLER( h6280_timer_w )\r
-{\r
-       switch (offset & 1) {\r
-               case 0: /* Counter preload */\r
-                       cpustate->timer_load=cpustate->timer_value=((data&127)+1)*1024;\r
-                       return;\r
-\r
-               case 1: /* Counter enable */\r
-                       if(data&1)\r
-                       {       /* stop -> start causes reload */\r
-                               if(cpustate->timer_status==0) cpustate->timer_value=cpustate->timer_load;\r
-                       }\r
-                       cpustate->timer_status=data&1;\r
-                       return;\r
-       }\r
-}\r
-\r
-/*****************************************************************************/\r
-\r
+/*****************************************************************************
+
+    h6280.c - Portable HuC6280 emulator
+
+    Copyright Bryan McPhail, mish@tendril.co.uk
+
+    This source code is based (with permission!) on the 6502 emulator by
+    Juergen Buchmueller.  It is released as part of the Mame emulator project.
+    Let me know if you intend to use this code in any other project.
+
+
+    NOTICE:
+
+    This code is around 99% complete!  Several things are unimplemented,
+    some due to lack of time, some due to lack of documentation, mainly
+    due to lack of programs using these features.
+
+    csh, csl opcodes are not supported.
+
+    I am unsure if flag B is set upon execution of rti.
+
+    Cycle counts should be quite accurate.
+
+
+    Changelog, version 1.02:
+        JMP + indirect X (0x7c) opcode fixed.
+        SMB + RMB opcodes fixed in disassembler.
+        change_pc function calls removed.
+        TSB & TRB now set flags properly.
+        BIT opcode altered.
+
+    Changelog, version 1.03:
+        Swapped IRQ mask for IRQ1 & IRQ2 (thanks Yasuhiro)
+
+    Changelog, version 1.04, 28/9/99-22/10/99:
+        Adjusted RTI (thanks Karl)
+        TST opcodes fixed in disassembler (missing break statements in a case!).
+        TST behaviour fixed.
+        SMB/RMB/BBS/BBR fixed in disassembler.
+
+    Changelog, version 1.05, 8/12/99-16/12/99:
+        Added CAB's timer implementation (note: irq ack & timer reload are changed).
+        Fixed STA IDX.
+        Fixed B flag setting on BRK.
+        Assumed CSH & CSL to take 2 cycles each.
+
+        Todo:  Performance could be improved by precalculating timer fire position.
+
+    Changelog, version 1.06, 4/5/00 - last opcode bug found?
+        JMP indirect was doing a EAL++; instead of EAD++; - Obviously causing
+        a corrupt read when L = 0xff!  This fixes Bloody Wolf and Trio The Punch!
+
+    Changelog, version 1.07, 3/9/00:
+        Changed timer to be single shot - fixes Crude Buster music in level 1.
+
+    Changelog, version 1.08, 8/11/05: (Charles MacDonald)
+
+        Changed timer implementation, no longer single shot and reading the
+        timer registers returns the count only. Fixes the following:
+        - Mesopotamia: Music tempo & in-game timer
+        - Dragon Saber: DDA effects
+        - Magical Chase: Music tempo and speed regulation
+        - Cadash: Allows the first level to start
+        - Turrican: Allows the game to start
+
+        Changed PLX and PLY to set NZ flags. Fixes:
+        - Afterburner: Graphics unpacking
+        - Aoi Blink: Collision detection with background
+
+        Fixed the decimal version of ADC/SBC to *not* update the V flag,
+        only the binary ones do.
+
+        Fixed B flag handling so it is always set outside of an interrupt;
+        even after being set by PLP and RTI.
+
+        Fixed P state after reset to set I and B, leaving T, D cleared and
+        NVZC randomized (cleared in this case).
+
+        Fixed interrupt processing order (Timer has highest priority followed
+        by IRQ1 and finally IRQ2).
+
+    Changelog, version 1.09, 1/07/06: (Rob Bohms)
+
+        Added emulation of the T flag, fixes PCE Ankuku Densetsu title screen
+
+    Changelog, version 1.10, 5/09/07: (Wilbert Pol)
+
+        - Taking of interrupts is delayed to respect a pending instruction already
+          in the instruction pipeline; fixes After Burner.
+        - Added 1 cycle for decimal mode ADC and SBC instructions.
+        - Changed cycle counts for CSH and CSL instructions to 3.
+        - Added T flag support to the SBC instruction.
+        - Fixed ADC T flag to set the Z flag based on the value read.
+        - Added 3 cycle penalty to ADC, AND, EOR, ORA, and SBC instructions
+          when the T flag is set.
+        - Fixed cycle count and support for 65536 byte blocks for the TAI, TDD,
+          TIA, TII, and TIN instructions.
+        - Fixed RDWORD macro in the disassembler.
+        - Fixed setting of N and V flags in the TST instructions.
+        - Removed unneeded debug_mmr code.
+        - Fixed TSB and TRB instructions.
+        - Added 1 delay when accessing the VDC or VCE areas.
+        - Implemented low and high speed cpu modes.
+
+    Changelog, version 1.11, 18/09/07: (Wilbert Pol)
+
+        - Improvements to the handling of taking of delayed interrupts.
+
+******************************************************************************/
+
+//#include "emu.h"
+//#include "debugger.h"
+#include "h6280.h"
+
+static void set_irq_line(h6280_Regs* cpustate, int irqline, int state);
+
+/* include the macros */
+#include "h6280ops.h"
+
+/* include the opcode macros, functions and function pointer tables */
+#include "tblh6280.c"
+
+/*****************************************************************************/
+static CPU_INIT( h6280 )
+{
+       h6280_Regs *cpustate = (h6280_Regs *)calloc(1, sizeof(h6280_Regs));
+
+       return cpustate;
+}
+
+static CPU_RESET( h6280 )
+{
+       int i;
+
+       /* wipe out the h6280 structure */
+       DEVICE *save_program = cpustate->program;
+       DEVICE *save_io = cpustate->io;
+       memset(cpustate, 0, sizeof(h6280_Regs));
+       cpustate->program = save_program;
+       cpustate->io = save_io;
+
+       /* set I and B flags */
+       P = _fI | _fB;
+
+    /* stack starts at 0x01ff */
+       cpustate->sp.d = 0x1ff;
+
+    /* read the reset vector into PC */
+       PCL = RDMEM(cpustate, H6280_RESET_VEC);
+       PCH = RDMEM(cpustate, (H6280_RESET_VEC+1));
+
+       /* CPU starts in low speed mode */
+    cpustate->clocks_per_cycle = 4;
+
+       /* timer off by default */
+       cpustate->timer_status=0;
+       cpustate->timer_load = 128 * 1024;
+
+    /* clear pending interrupts */
+       for (i = 0; i < 3; i++)
+               cpustate->irq_state[i] = CLEAR_LINE;
+       cpustate->nmi_state = CLEAR_LINE;
+
+       cpustate->irq_pending = 0;
+}
+
+static CPU_EXECUTE( h6280 )
+{
+       int in;
+
+       if (ICount == -1) {
+               cpustate->ICount = 1;
+       } else {
+               cpustate->ICount += ICount;
+       }
+       int Base_ICount = cpustate->ICount;
+
+       if ( cpustate->irq_pending == 2 ) {
+               cpustate->irq_pending--;
+       }
+
+       /* Execute instructions */
+       do
+    {
+               cpustate->ppc = cpustate->pc;
+
+               /* Execute 1 instruction */
+               in=RDOP();
+               PCW++;
+               insnh6280[in](cpustate);
+
+               if ( cpustate->irq_pending ) {
+                       if ( cpustate->irq_pending == 1 ) {
+                               if ( !(P & _fI) ) {
+                                       cpustate->irq_pending--;
+                                       CHECK_AND_TAKE_IRQ_LINES;
+                               }
+                       } else {
+                               cpustate->irq_pending--;
+                       }
+               }
+
+               /* Check internal timer */
+               if(cpustate->timer_status)
+               {
+                       if(cpustate->timer_value<=0)
+                       {
+                               if ( ! cpustate->irq_pending )
+                                       cpustate->irq_pending = 1;
+                               while( cpustate->timer_value <= 0 )
+                                       cpustate->timer_value += cpustate->timer_load;
+                               set_irq_line(cpustate, 2,ASSERT_LINE);
+                       }
+               }
+       } while (cpustate->ICount > 0);
+
+       return Base_ICount - cpustate->ICount;
+}
+
+/*****************************************************************************/
+
+static void set_irq_line(h6280_Regs* cpustate, int irqline, int state)
+{
+       if (irqline == INPUT_LINE_NMI)
+       {
+               if ( state != ASSERT_LINE ) return;
+               cpustate->nmi_state = state;
+               CHECK_IRQ_LINES;
+       }
+       else if (irqline < 3)
+       {
+               /* If the state has not changed, just return */
+               if ( cpustate->irq_state[irqline] == state )
+                       return;
+
+           cpustate->irq_state[irqline] = state;
+
+               CHECK_IRQ_LINES;
+       }
+}
+
+
+
+/*****************************************************************************/
+
+READ8_HANDLER( h6280_irq_status_r )
+{
+       int status;
+
+       switch (offset&3)
+       {
+       default: return 0;
+       case 3:
+               {
+                       status=0;
+                       if(cpustate->irq_state[1]!=CLEAR_LINE) status|=1; /* IRQ 2 */
+                       if(cpustate->irq_state[0]!=CLEAR_LINE) status|=2; /* IRQ 1 */
+                       if(cpustate->irq_state[2]!=CLEAR_LINE) status|=4; /* TIMER */
+                       return status;
+               }
+       case 2: return cpustate->irq_mask;
+       }
+}
+
+WRITE8_HANDLER( h6280_irq_status_w )
+{
+       switch (offset&3)
+       {
+               case 2: /* Write irq mask */
+                       cpustate->irq_mask=data&0x7;
+                       CHECK_IRQ_LINES;
+                       break;
+
+               case 3: /* Timer irq ack */
+                       set_irq_line(cpustate, 2, CLEAR_LINE);
+                       break;
+       }
+}
+
+READ8_HANDLER( h6280_timer_r )
+{
+       /* only returns countdown */
+       return ((cpustate->timer_value >> 10)&0x7F);
+}
+
+WRITE8_HANDLER( h6280_timer_w )
+{
+       switch (offset & 1) {
+               case 0: /* Counter preload */
+                       cpustate->timer_load=cpustate->timer_value=((data&127)+1)*1024;
+                       return;
+
+               case 1: /* Counter enable */
+                       if(data&1)
+                       {       /* stop -> start causes reload */
+                               if(cpustate->timer_status==0) cpustate->timer_value=cpustate->timer_load;
+                       }
+                       cpustate->timer_status=data&1;
+                       return;
+       }
+}
+
+/*****************************************************************************/
+