summaryrefslogtreecommitdiff
path: root/main.h
blob: 397541d4cec56aa3503afd049581ed41aa2709b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/* gameplaySP
 *
 * Copyright (C) 2006 Exophase <exophase@gmail.com>
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef MAIN_H
#define MAIN_H

typedef enum
{
  TIMER_INACTIVE,
  TIMER_PRESCALE,
  TIMER_CASCADE
} timer_status_type;

typedef enum
{
  TIMER_NO_IRQ,
  TIMER_TRIGGER_IRQ
} timer_irq_type;


typedef enum
{
  TIMER_DS_CHANNEL_NONE,
  TIMER_DS_CHANNEL_A,
  TIMER_DS_CHANNEL_B,
  TIMER_DS_CHANNEL_BOTH
} timer_ds_channel_type;

typedef struct
{
  s32 count;
  u32 reload;
  u32 prescale;
  u32 stop_cpu_ticks;
  fixed16_16 frequency_step;
  timer_ds_channel_type direct_sound_channels;
  timer_irq_type irq;
  timer_status_type status;
} timer_type;

typedef enum
{
  auto_frameskip,
  manual_frameskip,
  no_frameskip
} frameskip_type;

extern u32 cpu_ticks;
extern u32 frame_ticks;
extern u32 execute_cycles;
extern frameskip_type current_frameskip_type;
extern u32 frameskip_value;
extern u32 random_skip;
extern u32 global_cycles_per_instruction;
extern u32 synchronize_flag;
extern u32 skip_next_frame;

extern timer_type timer[4];
static u32 prescale_table[] = { 0, 6, 8, 10 };

extern u32 cycle_memory_access;
extern u32 cycle_pc_relative_access;
extern u32 cycle_sp_relative_access;
extern u32 cycle_block_memory_access;
extern u32 cycle_block_memory_sp_access;
extern u32 cycle_block_memory_words;
extern u32 cycle_dma16_words;
extern u32 cycle_dma32_words;
extern u32 flush_ram_count;

extern u64 base_timestamp;

extern u8 main_path[512];

extern u32 update_backup_flag;
extern u32 clock_speed;

u32 update_gba();
void reset_gba();
void synchronize();
void quit();
void delay_us(u32 us_count);
void get_ticks_us(u64 *tick_return);
void game_name_ext(u8 *src, u8 *buffer, u8 *extension);
void main_write_mem_savestate(file_tag_type savestate_file);
void main_read_savestate(file_tag_type savestate_file);


#ifdef PSP_BUILD

u32 file_length(u8 *filename, s32 dummy);

extern u32 real_frame_count;
extern u32 virtual_frame_count;
extern u32 max_frameskip;
extern u32 num_skipped_frames;

#endif


#ifdef GP2X_BUILD

extern u64 frame_count_initial_timestamp;
extern u32 real_frame_count;
extern u32 virtual_frame_count;
extern u32 max_frameskip;
extern u32 num_skipped_frames;

#endif


#ifdef PC_BUILD

u32 file_length(u8 *dummy, FILE *fp);

#endif

#define count_timer(timer_number)                                             \
  timer[timer_number].reload = 0x10000 - value;                               \
  if(timer_number < 2)                                                        \
  {                                                                           \
    u32 timer_reload =                                                        \
     timer[timer_number].reload << timer[timer_number].prescale;              \
    sound_update_frequency_step(timer_number);                                \
  }                                                                           \

#define adjust_sound_buffer(timer_number, channel)                            \
  if(timer[timer_number].direct_sound_channels & (0x01 << channel))           \
  {                                                                           \
    direct_sound_channel[channel].buffer_index =                              \
     (direct_sound_channel[channel].buffer_index + buffer_adjust) %           \
     BUFFER_SIZE;                                                             \
  }                                                                           \

#define trigger_timer(timer_number)                                           \
  if(value & 0x80)                                                            \
  {                                                                           \
    if(timer[timer_number].status == TIMER_INACTIVE)                          \
    {                                                                         \
      u32 prescale = prescale_table[value & 0x03];                            \
      u32 timer_reload = timer[timer_number].reload;                          \
                                                                              \
      if((value >> 2) & 0x01)                                                 \
        timer[timer_number].status = TIMER_CASCADE;                           \
      else                                                                    \
        timer[timer_number].status = TIMER_PRESCALE;                          \
                                                                              \
      timer[timer_number].prescale = prescale;                                \
      timer[timer_number].irq = (value >> 6) & 0x01;                          \
                                                                              \
      address16(io_registers, 0x100 + (timer_number * 4)) =                   \
       -timer_reload;                                                         \
                                                                              \
      timer_reload <<= prescale;                                              \
      timer[timer_number].count = timer_reload;                               \
                                                                              \
      if(timer_reload < execute_cycles)                                       \
        execute_cycles = timer_reload;                                        \
                                                                              \
      if(timer_number < 2)                                                    \
      {                                                                       \
        u32 buffer_adjust =                                                   \
         (u32)(((float)(cpu_ticks - timer[timer_number].stop_cpu_ticks) *     \
         sound_frequency) / 16777216.0) * 2;                                  \
                                                                              \
        sound_update_frequency_step(timer_number);                            \
        adjust_sound_buffer(timer_number, 0);                                 \
        adjust_sound_buffer(timer_number, 1);                                 \
      }                                                                       \
    }                                                                         \
  }                                                                           \
  else                                                                        \
  {                                                                           \
    if(timer[timer_number].status != TIMER_INACTIVE)                          \
    {                                                                         \
      timer[timer_number].status = TIMER_INACTIVE;                            \
      timer[timer_number].stop_cpu_ticks = cpu_ticks;                         \
    }                                                                         \
  }                                                                           \
  address16(io_registers, 0x102 + (timer_number * 4)) = value;                \

void change_ext(u8 *src, u8 *buffer, u8 *extension);

#endif