diff --git a/HISTORY.txt b/HISTORY.txt index 58fd91c..9ba4ef9 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -7,7 +7,7 @@ Genesis Plus GX 1.3.2 (??/??/????) (Eke-Eke) * optimized SN76489 core * modified SN76489 cut-off frequency (thanks to Steve Snake) -* added SN76489 linear interpolation using Blip Buffer (thanks to Blargg) +* added SN76489 linear synthesis using Blip Buffer (thanks to Blargg) * added an option to boost SN76489 Noise Channel * removed now outdated Gens YM2612 core * improved YM2612 emulation accuracy (SSG-EG, CSM mode...) (thanks to Nemesis for his tests on real hardware) diff --git a/source/cart_hw/cart_hw.c b/source/cart_hw/cart_hw.c index 90f998c..8ef5fed 100644 --- a/source/cart_hw/cart_hw.c +++ b/source/cart_hw/cart_hw.c @@ -26,10 +26,11 @@ ***************************************************************************/ #include "shared.h" -#include "m68kcpu.h" #define CART_CNT 26 +extern int emulate_address_error; + /* Global Variables */ T_CART_HW cart_hw; uint8 j_cart; diff --git a/source/gen_input.c b/source/gen_input.c index 59e65df..d39e5f5 100644 --- a/source/gen_input.c +++ b/source/gen_input.c @@ -78,7 +78,7 @@ static inline void lightgun_update(int num) if (io_reg[5] & 0x80) { /* External Interrupt ? */ - if (reg[11] & 0x08) {irq_status &= 0xff; irq_status |= 0x12;} + if (reg[11] & 0x08) irq_status = (irq_status & ~0x40) | 0x12; /* HVC Latch: 1) some games does not set HVC latch but instead use bigger X offset diff --git a/source/m68k/m68kconf.h b/source/m68k/m68kconf.h index a64de89..068c634 100644 --- a/source/m68k/m68kconf.h +++ b/source/m68k/m68kconf.h @@ -157,7 +157,7 @@ * access a word or longword at an odd address. * NOTE: This is only emulated properly for 68000 mode. */ -#define M68K_EMULATE_ADDRESS_ERROR OPT_OFF +#define M68K_EMULATE_ADDRESS_ERROR OPT_ON /* Turn ON to enable logging of illegal instruction calls. diff --git a/source/m68k/m68kcpu.c b/source/m68k/m68kcpu.c index d2101af..bcafade 100644 --- a/source/m68k/m68kcpu.c +++ b/source/m68k/m68kcpu.c @@ -75,7 +75,9 @@ const char *const m68ki_cpu_names[] = m68ki_cpu_core m68ki_cpu = {0}; #if M68K_EMULATE_ADDRESS_ERROR +#include jmp_buf m68ki_aerr_trap; +int emulate_address_error = 0; #endif /* M68K_EMULATE_ADDRESS_ERROR */ uint m68ki_aerr_address; @@ -505,13 +507,6 @@ static void default_instr_hook_callback(unsigned int pc) } -#if M68K_EMULATE_ADDRESS_ERROR - #include - jmp_buf m68ki_aerr_trap; - int emulate_address_error = 0; -#endif /* M68K_EMULATE_ADDRESS_ERROR */ - - /* ======================================================================== */ /* ================================= API ================================== */ /* ======================================================================== */ @@ -781,64 +776,42 @@ void m68k_set_cpu_type(unsigned int cpu_type) } } -/* Execute some instructions until we use up num_cycles clock cycles */ -/* ASG: removed per-instruction interrupt checks */ -INLINE int m68k_execute(int num_cycles) +/* Execute a single instruction */ +INLINE int m68k_execute(void) { - /* Make sure we're not stopped */ - if(!CPU_STOPPED) - { /* Set our pool of clock cycles available */ - SET_CYCLES(num_cycles); - m68ki_initial_cycles = num_cycles; + SET_CYCLES(0); + + /* Set tracing accodring to T1. (T0 is done inside instruction) */ + m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ + + /* Set the address space for reads */ + m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */ + + /* Call external hook to peek at CPU */ + m68ki_instr_hook(REG_PC); /* auto-disable (see m68kcpu.h) */ + + /* Record previous program counter */ + REG_PPC = REG_PC; + + /* Read an instruction and call its handler */ + REG_IR = m68ki_read_imm_16(); + m68ki_instruction_jump_table[REG_IR](); + USE_CYCLES(CYC_INSTRUCTION[REG_IR]); + + /* Trace m68k_exception, if necessary */ + m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */ /* ASG: update cycles */ USE_CYCLES(CPU_INT_CYCLES); CPU_INT_CYCLES = 0; - /* Return point if we had an address error */ - m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ - - /* Main loop. Keep going until we run out of clock cycles */ - do - { - /* Set tracing accodring to T1. (T0 is done inside instruction) */ - m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ - - /* Set the address space for reads */ - m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */ - - /* Call external hook to peek at CPU */ - m68ki_instr_hook(REG_PC); /* auto-disable (see m68kcpu.h) */ - - /* Record previous program counter */ - REG_PPC = REG_PC; - - /* Read an instruction and call its handler */ - REG_IR = m68ki_read_imm_16(); - m68ki_instruction_jump_table[REG_IR](); - USE_CYCLES(CYC_INSTRUCTION[REG_IR]); - - /* Trace m68k_exception, if necessary */ - m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */ - } while(GET_CYCLES() > 0); - /* set previous PC to current PC for the next entry into the loop */ REG_PPC = REG_PC; - /* ASG: update cycles */ - USE_CYCLES(CPU_INT_CYCLES); - CPU_INT_CYCLES = 0; - /* return how many clocks we used */ - return m68ki_initial_cycles - GET_CYCLES(); - } + return - GET_CYCLES(); - /* We get here if the CPU is stopped or halted */ - SET_CYCLES(0); - CPU_INT_CYCLES = 0; - - return num_cycles; } /* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */ @@ -858,12 +831,23 @@ INLINE void m68k_set_irq(unsigned int int_level) m68ki_check_interrupts(); /* Level triggered (IRQ) */ } -extern uint16 irq_status; +extern uint8 irq_status; extern uint32 count_m68k; void m68k_run (int cyc) { + /* Make sure we're not stopped */ + if(CPU_STOPPED) + { + count_m68k = cyc; + return; + } + int temp; + + /* Return point if we had an address error */ + m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ + while (count_m68k < cyc) { /* check interrupt updates */ @@ -871,18 +855,23 @@ void m68k_run (int cyc) { irq_status &= ~0x10; + temp = irq_status & 6; + /* hardware latency */ - temp = irq_status >> 8; - if (temp) count_m68k += m68k_execute(temp); + if (irq_status & 0x40) + count_m68k += m68k_execute(); /* interrupt level */ - temp = irq_status & 6; if (temp == 6) irq_status |= 0x20; m68k_set_irq(temp); + + /* ASG: update cycles */ + count_m68k += CPU_INT_CYCLES; + CPU_INT_CYCLES = 0; } /* execute a single instruction */ - count_m68k += m68k_execute(1); + count_m68k += m68k_execute(); } } diff --git a/source/m68k/m68kcpu.h b/source/m68k/m68kcpu.h index 569bc64..c72da37 100644 --- a/source/m68k/m68kcpu.h +++ b/source/m68k/m68kcpu.h @@ -554,7 +554,7 @@ #if M68K_EMULATE_ADDRESS_ERROR #include extern jmp_buf m68ki_aerr_trap; - extern int emulate_address_error; + extern int emulate_address_error; #define m68ki_set_address_error_trap() \ if(setjmp(m68ki_aerr_trap) != 0) \ @@ -564,7 +564,6 @@ { \ SET_CYCLES(0); \ CPU_INT_CYCLES = 0; \ - return m68ki_initial_cycles; \ } \ } @@ -1063,13 +1062,13 @@ INLINE uint m68ki_read_imm_16(void) if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) { CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); - CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); + CPU_PREF_DATA = m68k_read_immediate_32(CPU_PREF_ADDR); } REG_PC += 2; return MASK_OUT_ABOVE_16(CPU_PREF_DATA >> ((2-((REG_PC-2)&2))<<3)); #else REG_PC += 2; - return m68k_read_immediate_16(ADDRESS_68K(REG_PC-2)); + return m68k_read_immediate_16(REG_PC-2); #endif /* M68K_EMULATE_PREFETCH */ } INLINE uint m68ki_read_imm_32(void) @@ -1082,14 +1081,14 @@ INLINE uint m68ki_read_imm_32(void) if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) { CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); - CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); + CPU_PREF_DATA = m68k_read_immediate_32(CPU_PREF_ADDR); } temp_val = CPU_PREF_DATA; REG_PC += 2; if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) { CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); - CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); + CPU_PREF_DATA = m68k_read_immediate_32(CPU_PREF_ADDR); temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | (CPU_PREF_DATA >> 16)); } REG_PC += 2; @@ -1099,7 +1098,7 @@ INLINE uint m68ki_read_imm_32(void) m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ REG_PC += 4; - return m68k_read_immediate_32(ADDRESS_68K(REG_PC-4)); + return m68k_read_immediate_32(REG_PC-4); #endif /* M68K_EMULATE_PREFETCH */ } @@ -1119,7 +1118,7 @@ INLINE uint m68ki_read_8_fc(uint address, uint fc) _m68k_memory_map *temp = &m68k_memory_map[((address)>>16)&0xff]; - if (temp->read8) return (*temp->read8)(address); + if (temp->read8) return (*temp->read8)(ADDRESS_68K(address)); else return READ_BYTE(temp->base, (address) & 0xffff); } INLINE uint m68ki_read_16_fc(uint address, uint fc) @@ -1128,7 +1127,7 @@ INLINE uint m68ki_read_16_fc(uint address, uint fc) m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */ _m68k_memory_map *temp = &m68k_memory_map[((address)>>16)&0xff]; - if (temp->read16) return (*temp->read16)(address); + if (temp->read16) return (*temp->read16)(ADDRESS_68K(address)); else return *(uint16 *)(temp->base + ((address) & 0xffff)); } INLINE uint m68ki_read_32_fc(uint address, uint fc) @@ -1137,7 +1136,7 @@ INLINE uint m68ki_read_32_fc(uint address, uint fc) m68ki_check_address_error_010_less(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */ _m68k_memory_map *temp = &m68k_memory_map[((address)>>16)&0xff]; - if (temp->read16) return ((*temp->read16)(address) << 16) | ((*temp->read16)(address + 2)); + if (temp->read16) return ((*temp->read16)(ADDRESS_68K(address)) << 16) | ((*temp->read16)(ADDRESS_68K(address + 2))); else return m68k_read_immediate_32(address); } @@ -1145,7 +1144,7 @@ INLINE void m68ki_write_8_fc(uint address, uint fc, uint value) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ _m68k_memory_map *temp = &m68k_memory_map[((address)>>16)&0xff]; - if (temp->write8) (*temp->write8)(address,value); + if (temp->write8) (*temp->write8)(ADDRESS_68K(address),value); else WRITE_BYTE(temp->base, (address) & 0xffff, value); } INLINE void m68ki_write_16_fc(uint address, uint fc, uint value) @@ -1153,7 +1152,7 @@ INLINE void m68ki_write_16_fc(uint address, uint fc, uint value) m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error_010_less(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ _m68k_memory_map *temp = &m68k_memory_map[((address)>>16)&0xff]; - if (temp->write16) (*temp->write16)(address,value); + if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value); else *(uint16 *)(temp->base + ((address) & 0xffff)) = value; } INLINE void m68ki_write_32_fc(uint address, uint fc, uint value) @@ -1163,8 +1162,8 @@ INLINE void m68ki_write_32_fc(uint address, uint fc, uint value) _m68k_memory_map *temp = &m68k_memory_map[((address)>>16)&0xff]; if (temp->write16) { - (*temp->write16)(address,value>>16); - (*temp->write16)(address+2,value&0xffff); + (*temp->write16)(ADDRESS_68K(address),value>>16); + (*temp->write16)(ADDRESS_68K(address+2),value&0xffff); } else { @@ -1958,7 +1957,6 @@ INLINE void m68ki_exception_address_error(void) */ if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET) { - m68k_read_memory_8(0x00ffff01); CPU_STOPPED = STOP_LEVEL_HALT; return; } @@ -1975,7 +1973,7 @@ INLINE void m68ki_exception_address_error(void) /* Service an interrupt request and start exception processing */ -void m68ki_exception_interrupt(uint int_level) +INLINE void m68ki_exception_interrupt(uint int_level) { uint vector; uint sr; diff --git a/source/macros.h b/source/macros.h index 7224500..c40f065 100644 --- a/source/macros.h +++ b/source/macros.h @@ -7,20 +7,20 @@ #define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | (BASE)[(ADDR)+1]) -#define READ_WORD_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) | \ - ((BASE)[(ADDR)+1]<<16) | \ - ((BASE)[(ADDR)+2]<<8) | \ - (BASE)[(ADDR)+3]) +#define READ_WORD_LONG(BASE, ADDR) (((BASE)[(ADDR)+1]<<24) | \ + ((BASE)[(ADDR)]<<16) | \ + ((BASE)[(ADDR)+3]<<8) | \ + (BASE)[(ADDR)+1]) #define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[(ADDR)^1] = (VAL)&0xff #define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff; \ (BASE)[(ADDR)+1] = (VAL)&0xff -#define WRITE_WORD_LONG(BASE, ADDR, VAL) (BASE)[(ADDR] = ((VAL)>>24) & 0xff; \ - (BASE)[(ADDR)+1] = ((VAL)>>16)&0xff; \ - (BASE)[(ADDR)+2] = ((VAL)>>8)&0xff; \ - (BASE)[(ADDR)+3] = (VAL)&0xff +#define WRITE_WORD_LONG(BASE, ADDR, VAL) (BASE)[(ADDR+1)] = ((VAL)>>24) & 0xff; \ + (BASE)[(ADDR)] = ((VAL)>>16)&0xff; \ + (BASE)[(ADDR+3)] = ((VAL)>>8)&0xff; \ + (BASE)[(ADDR+2)] = (VAL)&0xff #else diff --git a/source/system.c b/source/system.c index 18b432a..62c943c 100644 --- a/source/system.c +++ b/source/system.c @@ -388,7 +388,7 @@ int system_frame (int do_skip) { h_counter = reg[10]; hint_pending = 1; - if (reg[0] & 0x10) irq_status = (irq_status & 0xff) | 0x14; + if (reg[0] & 0x10) irq_status = (irq_status & ~0x40) | 0x14; /* adjust timings to take further decrement in account (see below) */ if ((line != 0) || (h_counter == 0)) aim_m68k += 36; @@ -430,10 +430,11 @@ int system_frame (int do_skip) /* V Interrupt */ status |= 0x80; - vint_pending = 1; /* 36 cycles latency after VINT occurence flag (Ex-Mutants, Tyrant) */ - if (reg[1] & 0x20) irq_status = (irq_status & 0xff) | 0x2416; + m68k_run(line_m68k + 113); + vint_pending = 1; + if (reg[1] & 0x20) irq_status = (irq_status & ~0x40) | 0x16; } else if (!do_skip) { diff --git a/source/vdp.c b/source/vdp.c index 84712ed..0dca374 100644 --- a/source/vdp.c +++ b/source/vdp.c @@ -50,7 +50,7 @@ uint16 status; /* VDP status flags */ uint8 dmafill; /* next VDP Write is DMA Fill */ uint8 hint_pending; /* 0= Line interrupt is pending */ uint8 vint_pending; /* 1= Frame interrupt is pending */ -uint16 irq_status; /* Interrupt lines updated */ +uint8 irq_status; /* Interrupt lines updated */ /* Global variables */ uint16 ntab; /* Name table A base address */ @@ -651,7 +651,7 @@ static inline void reg_w(unsigned int r, unsigned int d) { /* update IRQ status */ irq_status &= 0x20; - irq_status |= 0x10; + irq_status |= 0x50; if (vint_pending && (reg[1] & 0x20)) irq_status |= 6; else if (d & 0x10) irq_status |= 4; } @@ -677,7 +677,7 @@ static inline void reg_w(unsigned int r, unsigned int d) { /* update IRQ status */ irq_status &= 0x20; - irq_status |= 0x110; + irq_status |= 0x50; if (d & 0x20) irq_status |= 6; else if (hint_pending && (reg[0] & 0x10)) irq_status |= 4; } @@ -697,7 +697,7 @@ static inline void reg_w(unsigned int r, unsigned int d) } /* Display activated/blanked during Horizontal Blanking */ - if (((d&0x40) != (reg[1]&0x40)) && (v_counter < bitmap.viewport.h)) + if (((d&0x40) != (reg[1]&0x40)) && !(status & 8)) { if (count_m68k <= (hint_m68k + 120)) { @@ -748,7 +748,7 @@ static inline void reg_w(unsigned int r, unsigned int d) color_update(0x00, *(uint16 *)&cram[(border << 1)]); /* background color modified during Horizontal Blanking */ - if ((v_counter < bitmap.viewport.h) && (count_m68k <= (line_m68k + 84))) + if (!(status & 8) && (count_m68k <= (line_m68k + 84))) { /* remap current line (see Road Rash I,II,III) */ reg[7] = d; diff --git a/source/vdp.h b/source/vdp.h index 9d1af5a..f1b4f7c 100644 --- a/source/vdp.h +++ b/source/vdp.h @@ -38,7 +38,7 @@ extern uint16 status; extern uint8 dmafill; extern uint8 hint_pending; extern uint8 vint_pending; -extern uint16 irq_status; +extern uint8 irq_status; /* Global variables */ extern uint16 ntab;