-
Notifications
You must be signed in to change notification settings - Fork 1
/
gb.cpp
154 lines (133 loc) · 3.51 KB
/
gb.cpp
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
/* GameBoy emu control */
#include "pch.h"
int skip_introm = 0;
unsigned benchmark_sound, benchmark_gfx;
int sound_enabled = 1;
/* run on emu start */
void gb_init()
{
// log_init("gbemu.log");
mem_init();
sm83_init();
pad_init();
ppu_init();
apu_init(44100);
if (skip_introm) {
R_INTROM = 1;
R_PC = 0x100;
}
__log("init OK.");
}
/* run on emu shutdown */
void gb_shutdown()
{
mem_shutdown();
pad_shutdown();
apu_shutdown();
ppu_shutdown();
log_shutdown();
}
// **********************************************************************
uint32_t gb_clk;
uint32_t gb_eventclk; // timer before next possible interrupt/LCD mode change
uint32_t gb_timerclk; // time before next timer interrupt
unsigned lcd_int_on;
const char stat2LCDflg[8]={0x08,0x10,0x20,0x00, 0x48,0x50,0x60,0x40};
void check4LCDint(unsigned mode) { // Also called from mem.c!!
//unsigned lcd_int_on_new=; // LYC is not processed here
if(R_STAT&stat2LCDflg[mode]/* !lcd_int_on && */) {// check if interrupt is requested already
R_IF|=INT_LCDSTAT;
sm83_check4int(); // do int if possible
}
//lcd_int_on = lcd_int_on_new;
}
void check4LYC(void) { // Also called from mem.c!!
register unsigned stnew = R_STAT&~4;
if(R_LYC == R_LY) {
stnew|=4;
if(R_STAT < stnew)
if(stnew&0x40) {// check if interrupt allowed
R_IF|=INT_LCDSTAT;
sm83_check4int(); // do int if possible
}
}
R_STAT=stnew;
}
#define STAT_MODE(n) \
R_STAT = (R_STAT&0xFC)|n; \
check4LCDint(n);
// **********************************************************************
uint32_t gb_divbase;
uint32_t gb_timbase;
/* these variables are added to current gb clock to obtain
timer counter values in lower byte of result */
uint8_t gb_timshift; // input clock shift 1048576/(4,16,64,256)
void gb_reload_tima(unsigned data) { // will only contain byte value
gb_timbase = data-(int32_t)(gb_clk >> gb_timshift)-256;
gb_timerclk = ((gb_clk>>gb_timshift)-gb_timbase)<<gb_timshift;
}
static void execute(uint32_t n) {
gb_eventclk+=n; // timerclk = MAXULONG means that timer interrupt is off
/*while(gb_eventclk>gb_timerclk) {
sm83_execute_until(gb_timerclk);
gb_reload_tima(R_TMA);
R_IF|=INT_TIMER; // request timer interrupt
sm83_check4int();
}*/
sm83_execute_until(gb_eventclk);
}
// **********************************************************************
/* begin emulation */
void start()
{
unsigned i,gb_old;
//uint8_t lcd_status_prev,lcd_status:
//lcd_status_prev=lcd_status=0;
lcd_int_on=0;
gb_eventclk = gb_clk = gb_divbase = 0;
gb_timerclk = 0x7FFFFFFF;
while(1) {
gb_old = gb_clk;
R_LY=0;
for(i=144;i!=0;i--) {
check4LYC();
/* LCD during OAM-search (scan sprites) */
/* LCD during H-Blank */
//STAT_MODE(0);
//gb_eventclk+=204;
//sm83_execute_until(gb_eventclk);
STAT_MODE(2);
ppu_enumsprites();
execute(20);
/* LCD during data transfer (draw line) */
STAT_MODE(3); /* no interrupt here !! */
ppu_refreshline();
execute(43);
/* LCD during H-Blank */
STAT_MODE(0);
execute(51);
R_LY++;
}
//R_LY = 143;
/* LCD during V-Blank (10 "empty" lines) */
//if(R_STAT & 0x10) // questionable
R_IF|=INT_VBLANK; // Queue V-blank int
sm83_check4int();
STAT_MODE(1);
ppu_vsync();
for(i=10;i!=0;i--) {
check4LYC();
execute(114);
R_LY++;
}
// smallest of all- eventclk
if(gb_eventclk > (4<<28)) { // wrap _ALL_ counters
gb_clk -=(3<<28);
gb_eventclk -=(3<<28);
apu_clk_inner[1] -=(3<<28);
apu_clk_nextchange-=(3<<28);
if(gb_timerclk<MAXULONG) gb_timerclk-=(3<<28);
}
apu_mix();
}
}