1+ #include "common.h"
2+ #include "emulator.h"
3+
4+ #include <emscripten.h>
5+
6+ // hooks we wana implement
7+ #define IS_SPEC_emulator_step_after ~,1
8+ #define IS_SPEC_serial_write ~,1
9+
10+ //fallback to default/dummy "implementations"
11+ #define HOOK_SELECT_INNER (...) HOOK_SELECT_GET_3(__VA_ARGS__)
12+ #define HOOK_SELECT_GET_3 (a , b , slot , ...) slot
13+
14+ #define HOOK_VOID_CALL (name , e , f , ...) HOOK_##name(e, f, ##__VA_ARGS__)
15+ #define HOOK_VOID_IGNORE (...) ((void)0)
16+
17+ #define HOOK_BOOL_CALL (name , e , f , ...) HOOK_##name(e, f)
18+ #define HOOK_BOOL_IGNORE (...) (FALSE)
19+ #define HOOK0 (name ) \
20+ HOOK_SELECT_INNER(IS_SPEC_##name, HOOK_VOID_CALL, HOOK_VOID_IGNORE)(name, e, __func__)
21+
22+ #define HOOK (name , ...) \
23+ HOOK_SELECT_INNER(IS_SPEC_##name, HOOK_VOID_CALL, HOOK_VOID_IGNORE)(name, e, __func__, __VA_ARGS__)
24+
25+ #define HOOK0_FALSE (name ) \
26+ HOOK_SELECT_INNER(IS_SPEC_##name, HOOK_BOOL_CALL, HOOK_BOOL_IGNORE)(name, e, __func__)
27+
28+
29+ #ifndef BREAKPOINTS_MAX_BANKS_NUMBER
30+ #define BREAKPOINTS_MAX_BANKS_NUMBER 1
31+ #endif
32+
33+ typedef uint32_t breakpoints_type ;
34+ #define MEMORY_SIZE (64 * 1024)
35+ #define BREAKPOINTS_BIT_SIZE (sizeof(breakpoints_type) * 8)
36+ #define BREAKPOINTS_SIZE ((BREAKPOINTS_MAX_BANKS_NUMBER * MEMORY_SIZE) / BREAKPOINTS_BIT_SIZE)
37+ #define BREAKPOINTS_SHIFT (__builtin_ctz(BREAKPOINTS_BIT_SIZE))
38+ #define BREAKPOINTS_MASK (BREAKPOINTS_BIT_SIZE - 1)
39+ #define BREAKPOINTS_BANK_SHIFT (16 - BREAKPOINTS_SHIFT)
40+
41+ #define EMULATOR_FIELDS_HOOK breakpoints_type breakpoint[BREAKPOINTS_SIZE] __attribute__((aligned(8)));
42+
43+ static void HOOK_emulator_step_after (Emulator * , const char * func_name );
44+ static void HOOK_serial_write (Emulator * , const char * func_name , u8 value );
45+
46+ #include "emulator.c"
47+
48+ static inline uint32_t emulator_get_banked_PC_inline (Emulator * e ) {
49+ #if BREAKPOINTS_MAX_BANKS_NUMBER > 1
50+ uint16_t pc = REG .PC ;
51+ if (pc < 0x4000 ) {
52+ return (MMAP_STATE .rom_base [0 ] << (16 - ROM_BANK_SHIFT )) | pc ;
53+ } else if (pc < 0x8000 ) {
54+ return (MMAP_STATE .rom_base [1 ] << (16 - ROM_BANK_SHIFT )) | pc ;
55+ } else if (pc < 0xA000 ) {
56+ return (e -> state .vram .bank << 16 ) | pc ;
57+ } else if (pc < 0xC000 ) {
58+ return (MMAP_STATE .ext_ram_base << (16 - EXT_RAM_BANK_SHIFT )) | pc ;
59+ } else if (pc < 0xE000 ) {
60+ return (e -> state .wram .bank << 16 ) | pc ;
61+ }
62+ return pc ;
63+ #else
64+ return REG .PC ;
65+ #endif
66+ }
67+
68+ static inline bool is_breakpoint (Emulator * e , uint32_t banked_pc ) {
69+ uint32_t idx = banked_pc >> BREAKPOINTS_SHIFT ;
70+ return (e -> breakpoint [idx ] & ((breakpoints_type )1 << (banked_pc & BREAKPOINTS_MASK )));
71+ }
72+
73+
74+ void HOOK_serial_write (Emulator * e , const char * func_name , u8 value ) {
75+ EM_ASM ({emulator .serialCallback ($0 );}, value );
76+ }
77+
78+ void HOOK_emulator_step_after (Emulator * e , const char * func_name ) {
79+ uint32_t banked_pc = emulator_get_banked_PC_inline (e );
80+ if (is_breakpoint (e , banked_pc )) {
81+ e -> state .event |= EMULATOR_EVENT_BREAKPOINT ;
82+ }
83+ }
84+
85+ EMSCRIPTEN_KEEPALIVE
86+ void emulator_set_breakpoint (Emulator * e , uint32_t addr ) {
87+ uint32_t idx = addr >> BREAKPOINTS_SHIFT ;
88+ e -> breakpoint [idx ] |= ((breakpoints_type )1 << (addr & BREAKPOINTS_MASK ));
89+ }
90+
91+ EMSCRIPTEN_KEEPALIVE
92+ void emulator_clear_breakpoints (Emulator * e ) {
93+ ZERO_MEMORY (e -> breakpoint );
94+ }
95+
96+ EMSCRIPTEN_KEEPALIVE
97+ uint32_t emulator_get_banked_PC (Emulator * e ) {
98+ return emulator_get_banked_PC_inline (e );
99+ }
100+
101+ EMSCRIPTEN_KEEPALIVE
102+ void emulator_render_vram (Emulator * e , u32 * buffer ) {
103+ memset (buffer , 0 , sizeof (u32 ) * 256 * 256 );
104+ for (int ty = 0 ; ty < 24 ; ty ++ ) {
105+ for (int bank = 0 ; bank < 2 ; bank ++ ) {
106+ for (int tx = 0 ; tx < 16 ; tx ++ ) {
107+ for (int row = 0 ; row < 8 ; row ++ ) {
108+ int n = tx * 16 + ty * 16 * 16 + row * 2 + (bank << 13 );
109+ u8 a = VRAM .data [n ];
110+ u8 b = VRAM .data [n + 1 ];
111+ for (int x = 0 ; x < 8 ; x ++ ) {
112+ u32 color = 0xFFC2F0C4 ;
113+ u8 bit = (0x80 >> x );
114+ if ((a & bit ) && (b & bit )) {
115+ color = 0xFF001B2D ;
116+ } else if (a & bit ) {
117+ color = 0xFFA8B95A ;
118+ } else if (b & bit ) {
119+ color = 0xFF6E601E ;
120+ } else if (x == 7 || row == 7 ) {
121+ color = 0xFFB2E0B4 ;
122+ }
123+ buffer [(tx * 8 + x + bank * 128 ) + (ty * 8 + row ) * 256 ] = color ;
124+ }
125+ }
126+ }
127+ }
128+ }
129+ if (IS_CGB ) {
130+ for (int idx = 0 ; idx < 8 ; idx ++ ) {
131+ for (int col = 0 ; col < PALETTE_COLOR_COUNT ; col ++ ) {
132+ for (int x = 0 ; x < 8 ; x ++ ) {
133+ for (int y = 0 ; y < 8 ; y ++ ) {
134+ buffer [x + idx * 8 + (200 + col * 8 + y ) * 256 ] =
135+ PPU .bgcp .palettes [idx ].color [col ];
136+ buffer [x + idx * 8 + (200 + col * 8 + y ) * 256 + 128 ] =
137+ PPU .obcp .palettes [idx ].color [col ];
138+ }
139+ }
140+ }
141+ }
142+ } else {
143+ for (int type = 0 ; type < PALETTE_TYPE_COUNT ; type ++ ) {
144+ for (int col = 0 ; col < PALETTE_COLOR_COUNT ; col ++ ) {
145+ for (int x = 0 ; x < 8 ; x ++ ) {
146+ for (int y = 0 ; y < 8 ; y ++ ) {
147+ buffer [x + type * 8 + (200 + col * 8 + y ) * 256 ] =
148+ e -> pal [type ].color [col ];
149+ }
150+ }
151+ }
152+ }
153+ }
154+ }
155+
156+ EMSCRIPTEN_KEEPALIVE
157+ void emulator_render_background (Emulator * e , u32 * buffer , int type ) {
158+ memset (buffer , 0 , sizeof (u32 ) * 256 * 256 );
159+ int bank = 0 ;
160+ int tile_map = 0x1800 + ((type & 1 ) ? 0x400 : 0 );
161+ for (int ty = 0 ; ty < 32 ; ty ++ ) {
162+ for (int tx = 0 ; tx < 32 ; tx ++ ) {
163+ u8 tile = VRAM .data [tile_map + tx + ty * 32 ];
164+ int offset = 0 ;
165+ if (tile < 128 )
166+ offset = (LCDC .bg_tile_data_select == TILE_DATA_8000_8FFF ) ? 0 : 0x1000 ;
167+ for (int row = 0 ; row < 8 ; row ++ ) {
168+ int n = offset + tile * 16 + row * 2 ;
169+ u8 a = VRAM .data [n ];
170+ u8 b = VRAM .data [n + 1 ];
171+ for (int x = 0 ; x < 8 ; x ++ ) {
172+ u32 color = 0xFFC2F0C4 ;
173+ u8 bit = (0x80 >> x );
174+ if ((a & bit ) && (b & bit )) {
175+ color = 0xFF001B2D ;
176+ } else if (a & bit ) {
177+ color = 0xFFA8B95A ;
178+ } else if (b & bit ) {
179+ color = 0xFF6E601E ;
180+ } else if (x == 7 || row == 7 ) {
181+ color = 0xFFB2E0B4 ;
182+ }
183+ buffer [(tx * 8 + x ) + (ty * 8 + row ) * 256 ] = color ;
184+ }
185+ }
186+ }
187+ }
188+ for (int x = 0 ; x < SCREEN_WIDTH ; x ++ ) {
189+ buffer [((PPU .scx + x ) % 256 ) + (PPU .scy * 256 )] &= 0xFF7F7F7F ;
190+ buffer [((PPU .scx + x ) % 256 ) +
191+ ((PPU .scy + SCREEN_HEIGHT - 1 ) % 256 ) * 256 ] &= 0xFF7F7F7F ;
192+ }
193+ for (int y = 0 ; y < SCREEN_HEIGHT ; y ++ ) {
194+ buffer [PPU .scx + ((PPU .scy + y ) % 256 ) * 256 ] &= 0xFF7F7F7F ;
195+ buffer [((PPU .scx + SCREEN_WIDTH ) % 256 ) + ((PPU .scy + y ) % 256 ) * 256 ] &=
196+ 0xFF7F7F7F ;
197+ }
198+ }
199+
200+ #ifdef GBSTUDIO
201+ EMSCRIPTEN_KEEPALIVE
202+ Bool set_audio_channel_mute (Emulator * e , int channel , Bool muted ) {
203+ EmulatorConfig emu_config = emulator_get_config (e );
204+ emu_config .disable_sound [channel ] = muted ;
205+ emulator_set_config (e , & emu_config );
206+ return emu_config .disable_sound [channel ];
207+ }
208+ #endif
0 commit comments