mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
-Changed name of cheat config file to cheats.cfg. File is now read in on startup and written out on exit. -Changed cheat config file format to the following: {Some Game's CRC} name=Some Game [Cheat Name 1] enabled=1 XXXXXXXX YYYY <-- cheat code (address, new value) XXXXXXXX YYYY XXXXXXXX YYYY [Cheat Name 2] enabled=0 XXXXXXXX YYYY XXXXXXXX YYYY XXXXXXXX YYYY {Another Game's CRC} name=Another Game ... Here's the cheats.cfg I used for testing: {635a2bff 8b022326} name=SUPER MARIO 64 [Super Mega Jumps] enabled=1 8133b176 0008 [Jesus Mode Mario] enabled=1 81381764 0800 81381766 0024 81000090 3c04 81000092 8034 81000094 8484 81000096 b1e6 81000098 4484 8100009a 3000 810000a0 4680 810000a2 3120 810000a4 4604 810000a6 903c 810000ac 4500 810000ae 0002 810000b4 4600 810000b6 2486 810000b8 080e 810000ba 05db 810000bc e712
567 lines
13 KiB
C
567 lines
13 KiB
C
/**
|
|
* Mupen64 - interupt.c
|
|
* Copyright (C) 2002 Hacktarux
|
|
*
|
|
* Mupen64 homepage: http://mupen64.emulation64.com
|
|
* email address: hacktarux@yahoo.fr
|
|
*
|
|
* If you want to contribute to the project please contact
|
|
* me first (maybe someone is already making what you are
|
|
* planning to do).
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/
|
|
* or modify it under the terms of the GNU General Public Li-
|
|
* cence as published by the Free Software Foundation; either
|
|
* version 2 of the Licence, or any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be use-
|
|
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
|
|
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public Licence for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* Licence along with this program; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
|
* USA.
|
|
*
|
|
**/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#ifndef __WIN32__
|
|
#include <SDL.h>
|
|
#include "../main/winlnxdefs.h"
|
|
#else
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "interupt.h"
|
|
#include "../memory/memory.h"
|
|
#include "r4300.h"
|
|
#include "macros.h"
|
|
#include "exception.h"
|
|
#include "../main/main.h"
|
|
#include "../main/plugin.h"
|
|
#include "../main/savestates.h"
|
|
#include "../main/vcr.h"
|
|
#include "../main/cheat.h"
|
|
#ifdef WITH_LIRC
|
|
#include "../main/lirc.h"
|
|
#endif //WITH_LIRC
|
|
|
|
unsigned int next_vi;
|
|
int vi_field=0;
|
|
int vi_counter=0;
|
|
typedef struct _interupt_queue
|
|
{
|
|
int type;
|
|
unsigned int count;
|
|
struct _interupt_queue *next;
|
|
} interupt_queue;
|
|
|
|
static interupt_queue *q = NULL;
|
|
|
|
void clear_queue()
|
|
{
|
|
while(q != NULL)
|
|
{
|
|
interupt_queue *aux = q->next;
|
|
free(q);
|
|
q = aux;
|
|
}
|
|
}
|
|
|
|
void print_queue()
|
|
{
|
|
interupt_queue *aux;
|
|
//if (Count < 0x7000000) return;
|
|
printf("------------------ %x\n", (unsigned int)Count);
|
|
aux = q;
|
|
while (aux != NULL)
|
|
{
|
|
printf("Count:%x, %x\n", (unsigned int)aux->count, aux->type);
|
|
aux = aux->next;
|
|
}
|
|
printf("------------------\n");
|
|
//getchar();
|
|
}
|
|
|
|
static int SPECIAL_done = 0;
|
|
|
|
int before_event(unsigned int evt1, unsigned int evt2, int type2)
|
|
{
|
|
if(evt1 - Count < 0x80000000)
|
|
{
|
|
if(evt2 - Count < 0x80000000)
|
|
{
|
|
if((evt1 - Count) < (evt2 - Count)) return 1;
|
|
else return 0;
|
|
}
|
|
else
|
|
{
|
|
if((Count - evt2) < 0x10000000)
|
|
{
|
|
switch(type2)
|
|
{
|
|
case SPECIAL_INT:
|
|
if(SPECIAL_done) return 1;
|
|
else return 0;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
else return 1;
|
|
}
|
|
}
|
|
else return 0;
|
|
}
|
|
|
|
void add_interupt_event(int type, unsigned int delay)
|
|
{
|
|
unsigned int count = Count + delay/**2*/;
|
|
int special = 0;
|
|
|
|
if(type == SPECIAL_INT /*|| type == COMPARE_INT*/) special = 1;
|
|
if(Count > 0x80000000) SPECIAL_done = 0;
|
|
|
|
if (get_event(type)) {
|
|
printf("two events of type %x in queue\n", type);
|
|
}
|
|
interupt_queue *aux = q;
|
|
|
|
//if (type == PI_INT)
|
|
//{
|
|
//delay = 0;
|
|
//count = Count + delay/**2*/;
|
|
//}
|
|
|
|
if (q == NULL)
|
|
{
|
|
q = malloc(sizeof(interupt_queue));
|
|
q->next = NULL;
|
|
q->count = count;
|
|
q->type = type;
|
|
next_interupt = q->count;
|
|
//print_queue();
|
|
return;
|
|
}
|
|
|
|
if(before_event(count, q->count, q->type) && !special)
|
|
{
|
|
q = malloc(sizeof(interupt_queue));
|
|
q->next = aux;
|
|
q->count = count;
|
|
q->type = type;
|
|
next_interupt = q->count;
|
|
//print_queue();
|
|
return;
|
|
}
|
|
|
|
while (aux->next != NULL && (!before_event(count, aux->next->count, aux->next->type)
|
|
|| special))
|
|
aux = aux->next;
|
|
|
|
if (aux->next == NULL)
|
|
{
|
|
aux->next = malloc(sizeof(interupt_queue));
|
|
aux = aux->next;
|
|
aux->next = NULL;
|
|
aux->count = count;
|
|
aux->type = type;
|
|
}
|
|
else
|
|
{
|
|
interupt_queue *aux2;
|
|
if (type != SPECIAL_INT)
|
|
while(aux->next != NULL && aux->next->count == count)
|
|
aux = aux->next;
|
|
aux2 = aux->next;
|
|
aux->next = malloc(sizeof(interupt_queue));
|
|
aux = aux->next;
|
|
aux->next = aux2;
|
|
aux->count = count;
|
|
aux->type = type;
|
|
}
|
|
/*if (q->count > Count || (Count - q->count) < 0x80000000)
|
|
next_interupt = q->count;
|
|
else
|
|
next_interupt = 0;*/
|
|
//print_queue();
|
|
}
|
|
|
|
void add_interupt_event_count(int type, unsigned int count)
|
|
{
|
|
add_interupt_event(type, (count - Count)/*/2*/);
|
|
}
|
|
|
|
void remove_interupt_event()
|
|
{
|
|
interupt_queue *aux = q->next;
|
|
if(q->type == SPECIAL_INT) SPECIAL_done = 1;
|
|
free(q);
|
|
q = aux;
|
|
if (q != NULL && (q->count > Count || (Count - q->count) < 0x80000000))
|
|
next_interupt = q->count;
|
|
else
|
|
next_interupt = 0;
|
|
}
|
|
|
|
unsigned int get_event(int type)
|
|
{
|
|
interupt_queue *aux = q;
|
|
if (q == NULL) return 0;
|
|
if (q->type == type)
|
|
return q->count;
|
|
while (aux->next != NULL && aux->next->type != type)
|
|
aux = aux->next;
|
|
if (aux->next != NULL)
|
|
return aux->next->count;
|
|
return 0;
|
|
}
|
|
|
|
void remove_event(int type)
|
|
{
|
|
interupt_queue *aux = q;
|
|
if (q == NULL) return;
|
|
if (q->type == type)
|
|
{
|
|
aux = aux->next;
|
|
free(q);
|
|
q = aux;
|
|
return;
|
|
}
|
|
while (aux->next != NULL && aux->next->type != type)
|
|
aux = aux->next;
|
|
if (aux->next != NULL) // it's a type int
|
|
{
|
|
interupt_queue *aux2 = aux->next->next;
|
|
free(aux->next);
|
|
aux->next = aux2;
|
|
}
|
|
}
|
|
|
|
void translate_event_queue(unsigned int base)
|
|
{
|
|
interupt_queue *aux;
|
|
remove_event(COMPARE_INT);
|
|
remove_event(SPECIAL_INT);
|
|
aux=q;
|
|
while (aux != NULL)
|
|
{
|
|
aux->count = (aux->count - Count)+base;
|
|
aux = aux->next;
|
|
}
|
|
add_interupt_event_count(COMPARE_INT, Compare);
|
|
add_interupt_event_count(SPECIAL_INT, 0);
|
|
}
|
|
|
|
int save_eventqueue_infos(char *buf)
|
|
{
|
|
int len = 0;
|
|
interupt_queue *aux = q;
|
|
if (q == NULL)
|
|
{
|
|
*((unsigned int*)&buf[0]) = 0xFFFFFFFF;
|
|
return 4;
|
|
}
|
|
while (aux != NULL)
|
|
{
|
|
memcpy(buf+len , &aux->type , 4);
|
|
memcpy(buf+len+4, &aux->count, 4);
|
|
len += 8;
|
|
aux = aux->next;
|
|
}
|
|
*((unsigned int*)&buf[len]) = 0xFFFFFFFF;
|
|
return len+4;
|
|
}
|
|
|
|
void load_eventqueue_infos(char *buf)
|
|
{
|
|
int len = 0;
|
|
clear_queue();
|
|
while (*((unsigned int*)&buf[len]) != 0xFFFFFFFF)
|
|
{
|
|
int type = *((unsigned int*)&buf[len]);
|
|
unsigned int count = *((unsigned int*)&buf[len+4]);
|
|
add_interupt_event_count(type, count);
|
|
len += 8;
|
|
}
|
|
}
|
|
|
|
void init_interupt()
|
|
{
|
|
SPECIAL_done = 1;
|
|
next_vi = next_interupt = 5000;
|
|
vi_register.vi_delay = next_vi;
|
|
vi_field = 0;
|
|
clear_queue();
|
|
add_interupt_event_count(VI_INT, next_vi);
|
|
add_interupt_event_count(SPECIAL_INT, 0);
|
|
}
|
|
|
|
void check_interupt()
|
|
{
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
Cause &= ~0x400;
|
|
if ((Status & 7) != 1) return;
|
|
if (Status & Cause & 0xFF00)
|
|
{
|
|
if(q == NULL)
|
|
{
|
|
q = malloc(sizeof(interupt_queue));
|
|
q->next = NULL;
|
|
q->count = Count;
|
|
q->type = CHECK_INT;
|
|
}
|
|
else
|
|
{
|
|
interupt_queue* aux = malloc(sizeof(interupt_queue));
|
|
aux->next = q;
|
|
aux->count = Count;
|
|
aux->type = CHECK_INT;
|
|
q = aux;
|
|
}
|
|
next_interupt = Count;
|
|
}
|
|
}
|
|
|
|
void gen_interupt()
|
|
{
|
|
//if (!skip_jump)
|
|
//printf("interrupt:%x (%x)\n", q->type, Count);
|
|
|
|
// if paused, poll for input events
|
|
while(rompause)
|
|
{
|
|
struct timespec ts;
|
|
ts.tv_sec = 0;
|
|
ts.tv_nsec = 10000000;
|
|
nanosleep(&ts, NULL); // sleep for 10 milliseconds
|
|
SDL_PumpEvents();
|
|
#ifdef WITH_LIRC
|
|
lircCheckInput();
|
|
#endif //WITH_LIRC
|
|
}
|
|
|
|
if (stop == 1) {
|
|
vi_counter = 0; // debug
|
|
dyna_stop();
|
|
}
|
|
if (savestates_job & LOADSTATE)
|
|
{
|
|
savestates_load();
|
|
savestates_job &= ~LOADSTATE;
|
|
return;
|
|
}
|
|
|
|
if (skip_jump /*&& !dynacore*/)
|
|
{
|
|
if (q->count > Count || (Count - q->count) < 0x80000000)
|
|
next_interupt = q->count;
|
|
else
|
|
next_interupt = 0;
|
|
if (interpcore)
|
|
{
|
|
/*if ((Cause & (2 << 2)) && (Cause & 0x80000000))
|
|
interp_addr = skip_jump+4;
|
|
else*/
|
|
interp_addr = skip_jump;
|
|
last_addr = interp_addr;
|
|
}
|
|
else
|
|
{
|
|
/*if ((Cause & (2 << 2)) && (Cause & 0x80000000))
|
|
jump_to(skip_jump+4);
|
|
else*/
|
|
unsigned int dest = skip_jump;
|
|
skip_jump=0;
|
|
jump_to(dest);
|
|
last_addr = PC->addr;
|
|
}
|
|
skip_jump=0;
|
|
return;
|
|
}
|
|
|
|
switch(q->type)
|
|
{
|
|
case SPECIAL_INT:
|
|
if (Count > 0x10000000) return;
|
|
remove_interupt_event();
|
|
add_interupt_event_count(SPECIAL_INT, 0);
|
|
return;
|
|
break;
|
|
|
|
case VI_INT:
|
|
if(vi_counter < 60) {
|
|
if (vi_counter == 0)
|
|
{
|
|
cheat_apply_cheats(ENTRY_BOOT);
|
|
}
|
|
vi_counter++;
|
|
}
|
|
else {
|
|
cheat_apply_cheats(ENTRY_VI);
|
|
}
|
|
#ifdef VCR_SUPPORT
|
|
VCR_updateScreen();
|
|
#else
|
|
updateScreen();
|
|
#endif
|
|
#ifdef WITH_LIRC
|
|
lircCheckInput();
|
|
#endif //WITH_LIRC
|
|
|
|
#ifndef __WIN32__
|
|
SDL_PumpEvents();
|
|
refresh_stat();
|
|
#endif
|
|
new_vi();
|
|
if (vi_register.vi_v_sync == 0) vi_register.vi_delay = 500000;
|
|
else vi_register.vi_delay = ((vi_register.vi_v_sync + 1)*1500);
|
|
next_vi += vi_register.vi_delay;
|
|
if (vi_register.vi_status&0x40) vi_field=1-vi_field;
|
|
else vi_field=0;
|
|
|
|
remove_interupt_event();
|
|
add_interupt_event_count(VI_INT, next_vi);
|
|
|
|
MI_register.mi_intr_reg |= 0x08;
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
return;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
break;
|
|
|
|
case COMPARE_INT:
|
|
remove_interupt_event();
|
|
Count+=2;
|
|
add_interupt_event_count(COMPARE_INT, Compare);
|
|
Count-=2;
|
|
|
|
Cause = (Cause | 0x8000) & 0xFFFFFF83;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
break;
|
|
|
|
case CHECK_INT:
|
|
remove_interupt_event();
|
|
break;
|
|
|
|
case SI_INT:
|
|
#ifdef WITH_LIRC
|
|
lircCheckInput();
|
|
#endif //WITH_LIRC
|
|
|
|
#ifndef __WIN32__
|
|
SDL_PumpEvents();
|
|
#endif
|
|
PIF_RAMb[0x3F] = 0x0;
|
|
remove_interupt_event();
|
|
MI_register.mi_intr_reg |= 0x02;
|
|
si_register.si_stat |= 0x1000;
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
return;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
break;
|
|
|
|
case PI_INT:
|
|
remove_interupt_event();
|
|
MI_register.mi_intr_reg |= 0x10;
|
|
pi_register.read_pi_status_reg &= ~3;
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
return;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
break;
|
|
|
|
case AI_INT:
|
|
if (ai_register.ai_status & 0x80000000) // full
|
|
{
|
|
unsigned int ai_event = get_event(AI_INT);
|
|
remove_interupt_event();
|
|
ai_register.ai_status &= ~0x80000000;
|
|
ai_register.current_delay = ai_register.next_delay;
|
|
ai_register.current_len = ai_register.next_len;
|
|
//add_interupt_event(AI_INT, ai_register.next_delay/**2*/);
|
|
add_interupt_event_count(AI_INT, ai_event+ai_register.next_delay);
|
|
|
|
MI_register.mi_intr_reg |= 0x04;
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
return;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
}
|
|
else
|
|
{
|
|
remove_interupt_event();
|
|
ai_register.ai_status &= ~0x40000000;
|
|
|
|
//-------
|
|
MI_register.mi_intr_reg |= 0x04;
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
return;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
//return;
|
|
}
|
|
break;
|
|
|
|
case SP_INT:
|
|
remove_interupt_event();
|
|
sp_register.sp_status_reg |= 0x303;
|
|
//sp_register.signal1 = 1;
|
|
sp_register.signal2 = 1;
|
|
sp_register.broke = 1;
|
|
sp_register.halt = 1;
|
|
|
|
if (!sp_register.intr_break) return;
|
|
MI_register.mi_intr_reg |= 0x01;
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
return;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
break;
|
|
|
|
case DP_INT:
|
|
remove_interupt_event();
|
|
dpc_register.dpc_status &= ~2;
|
|
dpc_register.dpc_status |= 0x81;
|
|
MI_register.mi_intr_reg |= 0x20;
|
|
if (MI_register.mi_intr_reg & MI_register.mi_intr_mask_reg)
|
|
Cause = (Cause | 0x400) & 0xFFFFFF83;
|
|
else
|
|
return;
|
|
if ((Status & 7) != 1) return;
|
|
if (!(Status & Cause & 0xFF00)) return;
|
|
break;
|
|
|
|
default:
|
|
remove_interupt_event();
|
|
break;
|
|
}
|
|
exception_general();
|
|
if (savestates_job & SAVESTATE)
|
|
{
|
|
savestates_save();
|
|
savestates_job &= ~SAVESTATE;
|
|
}
|
|
}
|