Mercurial > repos > blastem
comparison jaguar.c @ 1080:382614130914
Some initial work on Atari Jaguar emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 04 Oct 2016 18:30:49 -0700 |
parents | |
children | f6e998227300 |
comparison
equal
deleted
inserted
replaced
1079:329ff62ea391 | 1080:382614130914 |
---|---|
1 #include <stdint.h> | |
2 #include <stdio.h> | |
3 #include <stddef.h> | |
4 #include <stdlib.h> | |
5 #include "m68k_core.h" | |
6 #include "jaguar.h" | |
7 #include "util.h" | |
8 | |
9 //BIOS Area Memory map | |
10 // 10 00 00 - 10 04 00 : Video mode/ Memory control registers | |
11 // 10 04 00 - 10 08 00 : CLUT | |
12 // 10 08 00 - 10 10 00 : Line buffer A | |
13 // 10 10 00 - 10 18 00 : Line buffer B | |
14 // 10 18 00 - 10 20 00 : Write Line buffer | |
15 // 10 21 00 - 10 30 00 : GPU/blitter registers | |
16 // 10 30 00 - 10 40 00 : GPU Local RAM (mirrored every 1K?) | |
17 // 11 00 00 - 11 00 40 : Timer/Clock registers | |
18 // 11 40 00 - 11 40 04 : Joystick Interface | |
19 // 11 A1 00 - 11 A1 52 : DSP/DAC/I2S Registers | |
20 // 11 B0 00 - 11 D0 00 : DSP Local RAM (8KB) | |
21 // 11 D0 00 - 11 E0 00 : Wave table ROM | |
22 | |
23 int headless = 1; | |
24 | |
25 | |
26 void rom0_write_16(uint32_t address, jaguar_context *system, uint16_t value) | |
27 { | |
28 //TODO: Use write_latch and write_pending to turn two 16-bit writes into a 32-bit one | |
29 //Documentation heavily suggests that writes to most registers should be 32-bits wide | |
30 if (address < 0x100000 || address >= 0x120000) { | |
31 //Boot ROM | |
32 fprintf(stderr, "Invalid write to Boot ROM - %X:%X\n", address, value); | |
33 return; | |
34 } | |
35 if (address < 0x103000) { | |
36 if (address < 0x101000) { | |
37 if (address < 0x100400) { | |
38 //Video mode / Memory control registers | |
39 fprintf(stderr, "Unhanelde write to video mode/memory control registers - %X:%X", address, value); | |
40 } else if (address < 0x100800) { | |
41 //CLUT | |
42 address = address >> 1 & 255; | |
43 system->clut[address] = value; | |
44 } else { | |
45 //Line buffer A | |
46 address = address >> 1 & 0x3FF; | |
47 if (address < LINEBUFFER_WORDS) { | |
48 system->line_buffer_a[address] = value; | |
49 } | |
50 } | |
51 } else if (address < 0x101800) { | |
52 //Line buffer B | |
53 address = address >> 1 & 0x3FF; | |
54 if (address < LINEBUFFER_WORDS) { | |
55 system->line_buffer_b[address] = value; | |
56 } | |
57 } else if (address < 0x102100) { | |
58 //Write Line Buffer | |
59 address = address >> 1 & 0x3FF; | |
60 if (address < LINEBUFFER_WORDS) { | |
61 system->write_line_buffer[address] = value; | |
62 } | |
63 } else { | |
64 //GPU/Blitter registers | |
65 fprintf(stderr, "Unhandled write to GPU/Blitter registers %X: %X\n", address, value); | |
66 } | |
67 } else if (address < 0x11A100) { | |
68 if (address < 0x110000) { | |
69 //GPU Local RAM | |
70 uint32_t offset = address >> 2 & (GPU_RAM_BYTES / sizeof(uint32_t) - 1); | |
71 uint32_t value32 = value; | |
72 if (address & 2) { | |
73 system->gpu_local[offset] &= 0xFFFF0000; | |
74 } else { | |
75 system->gpu_local[offset] &= 0x0000FFFF; | |
76 value32 = value32 << 16; | |
77 } | |
78 system->gpu_local[offset] |= value32; | |
79 } else if (address < 0x114000) { | |
80 //timer clock registers | |
81 fprintf(stderr, "Unhanelde write to timer/clock registers - %X:%X", address, value); | |
82 } else { | |
83 //joystick interface | |
84 fprintf(stderr, "Unhanelde write to joystick interface - %X:%X", address, value); | |
85 } | |
86 } else if (address < 0x11B000) { | |
87 //DSP/DAC/I2S Registers | |
88 fprintf(stderr, "Unhanelde write to DSP/DAC/I2S registers - %X:%X", address, value); | |
89 } else if (address < 0x11D000) { | |
90 //DSP local RAM | |
91 uint32_t offset = address >> 2 & (DSP_RAM_BYTES / sizeof(uint32_t) - 1); | |
92 uint32_t value32 = value; | |
93 if (address & 2) { | |
94 system->dsp_local[offset] &= 0xFFFF0000; | |
95 } else { | |
96 system->dsp_local[offset] &= 0x0000FFFF; | |
97 value32 = value32 << 16; | |
98 } | |
99 system->gpu_local[offset] |= value32; | |
100 } else { | |
101 //Wave table ROM | |
102 fprintf(stderr, "Invalid write to wave table ROM - %X:%X\n", address, value); | |
103 } | |
104 } | |
105 | |
106 uint16_t rom0_read_16(uint32_t address, jaguar_context *system) | |
107 { | |
108 if (address < 0x100000 || address >= 0x120000) { | |
109 //Boot ROM | |
110 address = address >> 1 & ((system->bios_size >> 1) - 1); | |
111 return system->bios[address]; | |
112 } | |
113 if (address < 0x103000) { | |
114 if (address < 0x101000) { | |
115 if (address < 0x100400) { | |
116 //Video mode / Memory control registers | |
117 fprintf(stderr, "Unhandled read from video mode/memory control registers - %X", address); | |
118 } else if (address < 0x100800) { | |
119 //CLUT | |
120 address = address >> 1 & 255; | |
121 return system->clut[address]; | |
122 } else { | |
123 //Line buffer A | |
124 address = address >> 1 & 0x3FF; | |
125 if (address < LINEBUFFER_WORDS) { | |
126 return system->line_buffer_a[address]; | |
127 } | |
128 } | |
129 } else if (address < 0x101800) { | |
130 //Line buffer B | |
131 address = address >> 1 & 0x3FF; | |
132 if (address < LINEBUFFER_WORDS) { | |
133 return system->line_buffer_b[address]; | |
134 } | |
135 } else if (address < 0x102100) { | |
136 //Write Line Buffer | |
137 address = address >> 1 & 0x3FF; | |
138 if (address < LINEBUFFER_WORDS) { | |
139 return system->write_line_buffer[address]; | |
140 } | |
141 } else { | |
142 //GPU/Blitter registers | |
143 fprintf(stderr, "Unhandled read from GPU/Blitter registers %X\n", address); | |
144 } | |
145 } else if (address < 0x11A100) { | |
146 if (address < 0x110000) { | |
147 //GPU Local RAM | |
148 uint32_t offset = address >> 2 & (GPU_RAM_BYTES / sizeof(uint32_t) - 1); | |
149 if (address & 2) { | |
150 return system->gpu_local[offset]; | |
151 } else { | |
152 return system->gpu_local[offset] >> 16; | |
153 } | |
154 } else if (address < 0x114000) { | |
155 //timer clock registers | |
156 fprintf(stderr, "Unhandled read from timer/clock registers - %X", address); | |
157 } else { | |
158 //joystick interface | |
159 fprintf(stderr, "Unhandled read from joystick interface - %X", address); | |
160 } | |
161 } else if (address < 0x11B000) { | |
162 //DSP/DAC/I2S Registers | |
163 fprintf(stderr, "Unhandled read from DSP/DAC/I2S registers - %X", address); | |
164 } else if (address < 0x11D000) { | |
165 //DSP local RAM | |
166 uint32_t offset = address >> 2 & (DSP_RAM_BYTES / sizeof(uint32_t) - 1); | |
167 if (address & 2) { | |
168 return system->dsp_local[offset]; | |
169 } else { | |
170 return system->dsp_local[offset] >> 16; | |
171 } | |
172 } else { | |
173 //Wave table ROM | |
174 fprintf(stderr, "Unhandled read from wave table ROM - %X\n", address); | |
175 } | |
176 return 0xFFFF; | |
177 } | |
178 | |
179 | |
180 void *rom0_write_m68k(uint32_t address, void *context, uint16_t value) | |
181 { | |
182 rom0_write_16(address, ((m68k_context *)context)->system, value); | |
183 return context; | |
184 } | |
185 | |
186 uint16_t rom0_read_m68k(uint32_t address, void *context) | |
187 { | |
188 return rom0_read_16(address, ((m68k_context *)context)->system); | |
189 } | |
190 | |
191 void *rom0_write_m68k_b(uint32_t address, void *context, uint8_t value) | |
192 { | |
193 //seems unlikely these areas support byte access | |
194 uint16_t value16 = value; | |
195 value16 |= value16 << 8; | |
196 rom0_write_16(address, ((m68k_context *)context)->system, value16); | |
197 return context; | |
198 } | |
199 | |
200 uint8_t rom0_read_m68k_b(uint32_t address, void *context) | |
201 { | |
202 uint16_t value = rom0_read_16(address, ((m68k_context *)context)->system); | |
203 if (address & 1) { | |
204 return value; | |
205 } | |
206 return value >> 8; | |
207 } | |
208 | |
209 m68k_context * sync_components(m68k_context * context, uint32_t address) | |
210 { | |
211 if (context->current_cycle > 0x10000000) { | |
212 context->current_cycle -= 0x10000000; | |
213 } | |
214 return context; | |
215 } | |
216 | |
217 jaguar_context *init_jaguar(uint16_t *bios, uint32_t bios_size, uint16_t *cart, uint32_t cart_size) | |
218 { | |
219 jaguar_context *system = calloc(1, sizeof(jaguar_context)); | |
220 system->bios = bios; | |
221 system->bios_size = bios_size; | |
222 system->cart = cart; | |
223 system->cart_size = cart_size; | |
224 | |
225 memmap_chunk jag_m68k_map[8]; | |
226 for (uint32_t start = 0, index=0; index < 8; index++, start += 0x200000) | |
227 { | |
228 jag_m68k_map[index].start = start; | |
229 jag_m68k_map[index].end = start + 0x200000; | |
230 jag_m68k_map[index].mask = index ? 0x1FFFFF : 0xFFFFFF; | |
231 jag_m68k_map[index].aux_mask = bios_size - 1; | |
232 jag_m68k_map[index].ptr_index = index; | |
233 jag_m68k_map[index].flags = MMAP_READ | MMAP_WRITE | MMAP_PTR_IDX | MMAP_FUNC_NULL | MMAP_AUX_BUFF; | |
234 jag_m68k_map[index].buffer = bios; | |
235 jag_m68k_map[index].read_16 = rom0_read_m68k; | |
236 jag_m68k_map[index].read_8 = rom0_read_m68k_b; | |
237 jag_m68k_map[index].write_16 = rom0_write_m68k; | |
238 jag_m68k_map[index].write_8 = rom0_write_m68k_b; | |
239 } | |
240 m68k_options *opts = malloc(sizeof(m68k_options)); | |
241 init_m68k_opts(opts, jag_m68k_map, 8, 2); | |
242 system->m68k = init_68k_context(opts); | |
243 system->m68k->system = system; | |
244 return system; | |
245 } | |
246 | |
247 //modified copy of the version in blastem.c | |
248 uint16_t *load_rom(char * filename, uint32_t *size) | |
249 { | |
250 FILE * f = fopen(filename, "rb"); | |
251 if (!f) { | |
252 return 0; | |
253 } | |
254 fseek(f, 0, SEEK_END); | |
255 long filesize = ftell(f); | |
256 fseek(f, 0, SEEK_SET); | |
257 | |
258 *size = nearest_pow2(filesize); | |
259 uint16_t *cart = malloc(*size); | |
260 if (filesize != fread(cart, 1, filesize, f)) { | |
261 fatal_error("Error reading from %s\n", filename); | |
262 } | |
263 while (filesize < *size) | |
264 { | |
265 cart[filesize / 2] = 0xFFFF; | |
266 filesize += 2; | |
267 } | |
268 fclose(f); | |
269 return cart; | |
270 } | |
271 | |
272 //temporary main function until I clean up blastem.c | |
273 int main(int argc, char **argv) | |
274 { | |
275 if (argc < 3) { | |
276 fputs("Usage: blastjag BIOS ROM\n", stderr); | |
277 return 1; | |
278 } | |
279 uint32_t bios_size; | |
280 uint16_t *bios = load_rom(argv[1], &bios_size); | |
281 if (!bios_size) { | |
282 fatal_error("Failed to read BIOS from %s\n", argv[1]); | |
283 } | |
284 uint32_t cart_size; | |
285 uint16_t *cart = load_rom(argv[2], &cart_size); | |
286 if (!bios_size) { | |
287 fatal_error("Failed to read cart from %s\n", argv[2]); | |
288 } | |
289 jaguar_context *system = init_jaguar(bios, bios_size, cart, cart_size); | |
290 m68k_reset(system->m68k); | |
291 return 0; | |
292 } |