Mercurial > repos > blastem
comparison jaguar.c @ 1097:faa3a4617f62
Get Jaguar video interrupt working
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 05 Nov 2016 00:23:11 -0700 |
parents | 1dba006bad47 |
children | 653558f6fa7a |
comparison
equal
deleted
inserted
replaced
1096:1ab30d427db8 | 1097:faa3a4617f62 |
---|---|
1 #include <stdint.h> | 1 #include <stdint.h> |
2 #include <stdio.h> | 2 #include <stdio.h> |
3 #include <stddef.h> | 3 #include <stddef.h> |
4 #include <stdlib.h> | 4 #include <stdlib.h> |
5 #include "m68k_core.h" | 5 #include "m68k_core.h" |
6 #include "68kinst.h" | |
6 #include "jaguar.h" | 7 #include "jaguar.h" |
7 #include "util.h" | 8 #include "util.h" |
8 #include "debug.h" | 9 #include "debug.h" |
9 #include "config.h" | 10 #include "config.h" |
10 #include "render.h" | 11 #include "render.h" |
56 | 57 |
57 void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay) | 58 void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay) |
58 { | 59 { |
59 } | 60 } |
60 | 61 |
62 void jag_update_m68k_int(jaguar_context *system) | |
63 { | |
64 m68k_context *m68k = system->m68k; | |
65 if (m68k->sync_cycle - m68k->current_cycle > system->max_cycles) { | |
66 m68k->sync_cycle = m68k->current_cycle + system->max_cycles; | |
67 } | |
68 //TODO: Support other interrupt sources | |
69 if (!system->cpu_int_control || (m68k->status & 0x7)) { | |
70 m68k->int_cycle = CYCLE_NEVER; | |
71 } else if(system->cpu_int_control & system->video->cpu_int_pending) { | |
72 m68k->int_cycle = m68k->current_cycle; | |
73 //supposedly all interrupts on the jaguar are "level 0" autovector interrupts | |
74 //which I assume means they're abusing the "spurious interrupt" vector | |
75 m68k->int_num = VECTOR_USER0 - VECTOR_SPURIOUS_INTERRUPT; | |
76 } else { | |
77 m68k->int_cycle = jag_next_vid_interrupt(system->video); | |
78 m68k->int_num = VECTOR_USER0 - VECTOR_SPURIOUS_INTERRUPT; | |
79 } | |
80 | |
81 if (m68k->int_cycle > m68k->current_cycle && m68k->int_pending == INT_PENDING_SR_CHANGE) { | |
82 m68k->int_pending = INT_PENDING_NONE; | |
83 } | |
84 | |
85 m68k->target_cycle = m68k->int_cycle < m68k->sync_cycle ? m68k->int_cycle : m68k->sync_cycle; | |
86 if (m68k->should_return) { | |
87 m68k->target_cycle = m68k->current_cycle; | |
88 } else if (m68k->target_cycle < m68k->current_cycle) { | |
89 //Changes to SR can result in an interrupt cycle that's in the past | |
90 //This can cause issues with the implementation of STOP though | |
91 m68k->target_cycle = m68k->current_cycle; | |
92 } | |
93 } | |
61 | 94 |
62 void rom0_write_16(uint32_t address, jaguar_context *system, uint16_t value) | 95 void rom0_write_16(uint32_t address, jaguar_context *system, uint16_t value) |
63 { | 96 { |
64 //TODO: Use write_latch and write_pending to turn two 16-bit writes into a 32-bit one | 97 //TODO: Use write_latch and write_pending to turn two 16-bit writes into a 32-bit one |
65 //Documentation heavily suggests that writes to most registers should be 32-bits wide | 98 //Documentation heavily suggests that writes to most registers should be 32-bits wide |
109 system->memcon1 = value; | 142 system->memcon1 = value; |
110 break; | 143 break; |
111 case 2: | 144 case 2: |
112 system->memcon2 = value; | 145 system->memcon2 = value; |
113 break; | 146 break; |
147 case 0xE0: | |
148 printf("INT1 write: %X\n", value); | |
149 system->cpu_int_control = value & 0x1F; | |
150 system->video->cpu_int_pending &= ~(value >> 8); | |
151 //TODO: apply mask to int pending fields on other components once they are implemented | |
152 break; | |
153 case 0xE2: | |
154 //no real handling of bus conflicts presently, so this doesn't really need to do anything yet | |
155 printf("INT2 write: %X\n", value); | |
156 break; | |
114 default: | 157 default: |
115 jag_video_reg_write(system->video, address, value); | 158 jag_video_reg_write(system->video, address, value); |
159 jag_update_m68k_int(system); | |
116 break; | 160 break; |
117 } | 161 } |
118 } else if (address < 0x100800) { | 162 } else if (address < 0x100800) { |
119 //CLUT | 163 //CLUT |
120 address = address >> 1 & 255; | 164 address = address >> 1 & 255; |
142 //GPU/Blitter registers | 186 //GPU/Blitter registers |
143 if (address < 0x102200) { | 187 if (address < 0x102200) { |
144 fprintf(stderr, "Unhandled write to GPU registers %X: %X\n", address, value); | 188 fprintf(stderr, "Unhandled write to GPU registers %X: %X\n", address, value); |
145 if (address == 0x102116 && (value & 1)) { | 189 if (address == 0x102116 && (value & 1)) { |
146 FILE *f = fopen("gpu.bin", "wb"); | 190 FILE *f = fopen("gpu.bin", "wb"); |
147 fwrite(system->gpu_local, 1, sizeof(system->gpu_local), f); | 191 uint8_t buf[4]; |
192 for (int i = 0; i < GPU_RAM_BYTES/sizeof(uint32_t); i++) | |
193 { | |
194 buf[0] = system->gpu_local[i] >> 24; | |
195 buf[1] = system->gpu_local[i] >> 16; | |
196 buf[2] = system->gpu_local[i] >> 8; | |
197 buf[3] = system->gpu_local[i]; | |
198 fwrite(buf, 1, sizeof(buf), f); | |
199 } | |
148 fclose(f); | 200 fclose(f); |
149 } | 201 } |
150 } else { | 202 } else { |
151 fprintf(stderr, "Unhandled write to Blitter registers %X: %X\n", address, value); | 203 fprintf(stderr, "Unhandled write to Blitter registers %X: %X\n", address, value); |
152 } | 204 } |
153 } | 205 } |
154 } else if (address < 0x11A100) { | 206 } else if (address < 0x11A100) { |
155 if (address < 0x110000) { | 207 if (address < 0x110000) { |
156 //GPU Local RAM | 208 //GPU Local RAM |
157 uint32_t offset = address >> 2 & (GPU_RAM_BYTES / sizeof(uint32_t) - 1); | 209 uint32_t offset = address >> 2 & (GPU_RAM_BYTES / sizeof(uint32_t) - 1); |
158 uint32_t value32 = value; | 210 uint32_t value32 = value; |
159 if (address & 2) { | 211 if (address & 2) { |
160 system->gpu_local[offset] &= 0xFFFF0000; | 212 system->gpu_local[offset] &= 0xFFFF0000; |
161 } else { | 213 } else { |
162 system->gpu_local[offset] &= 0x0000FFFF; | 214 system->gpu_local[offset] &= 0x0000FFFF; |
199 } | 251 } |
200 if (address < 0x103000) { | 252 if (address < 0x103000) { |
201 if (address < 0x101000) { | 253 if (address < 0x101000) { |
202 if (address < 0x100400) { | 254 if (address < 0x100400) { |
203 //Video mode / Memory control registers | 255 //Video mode / Memory control registers |
204 fprintf(stderr, "Unhandled read from video mode/memory control registers - %X\n", address); | 256 switch (address & 0x3FE) |
257 { | |
258 case 0xE0: | |
259 puts("INT1 read"); | |
260 //TODO: Bitwise or with cpu_int_pending fields from other components once implemented | |
261 return system->video->cpu_int_pending; | |
262 break; | |
263 default: | |
264 fprintf(stderr, "Unhandled read from video mode/memory control registers - %X\n", address); | |
265 } | |
205 } else if (address < 0x100800) { | 266 } else if (address < 0x100800) { |
206 //CLUT | 267 //CLUT |
207 address = address >> 1 & 255; | 268 address = address >> 1 & 255; |
208 return system->video->clut[address]; | 269 return system->video->clut[address]; |
209 } else { | 270 } else { |
375 | 436 |
376 m68k_context * sync_components(m68k_context * context, uint32_t address) | 437 m68k_context * sync_components(m68k_context * context, uint32_t address) |
377 { | 438 { |
378 jaguar_context *system = context->system; | 439 jaguar_context *system = context->system; |
379 jag_video_run(system->video, context->current_cycle); | 440 jag_video_run(system->video, context->current_cycle); |
441 jag_update_m68k_int(system); | |
380 if (context->current_cycle > 0x10000000) { | 442 if (context->current_cycle > 0x10000000) { |
381 context->current_cycle -= 0x10000000; | 443 context->current_cycle -= 0x10000000; |
382 system->video->cycles -= 0x10000000; | 444 system->video->cycles -= 0x10000000; |
383 } | 445 } |
446 if (context->int_ack) { | |
447 context->int_ack = 0; | |
448 //hack until 68K core more properly supports non-autovector interrupts | |
449 context->status |= 1; | |
450 } | |
451 jag_update_m68k_int(system); | |
384 return context; | 452 return context; |
385 } | 453 } |
386 | 454 |
387 | 455 |
388 void *rom0_write_m68k(uint32_t address, void *context, uint16_t value) | 456 void *rom0_write_m68k(uint32_t address, void *context, uint16_t value) |
429 jaguar_context *system = calloc(1, sizeof(jaguar_context)); | 497 jaguar_context *system = calloc(1, sizeof(jaguar_context)); |
430 system->bios = bios; | 498 system->bios = bios; |
431 system->bios_size = bios_size; | 499 system->bios_size = bios_size; |
432 system->cart = cart; | 500 system->cart = cart; |
433 system->cart_size = cart_size; | 501 system->cart_size = cart_size; |
502 //TODO: Figure out a better default for this and make it configurable | |
503 system->max_cycles = 3000; | |
434 | 504 |
435 memmap_chunk *jag_m68k_map = calloc(8, sizeof(memmap_chunk)); | 505 memmap_chunk *jag_m68k_map = calloc(8, sizeof(memmap_chunk)); |
436 for (uint32_t start = 0, index=0; index < 8; index++, start += 0x200000) | 506 for (uint32_t start = 0, index=0; index < 8; index++, start += 0x200000) |
437 { | 507 { |
438 jag_m68k_map[index].start = start; | 508 jag_m68k_map[index].start = start; |
448 jag_m68k_map[index].write_8 = rom0_write_m68k_b; | 518 jag_m68k_map[index].write_8 = rom0_write_m68k_b; |
449 } | 519 } |
450 m68k_options *opts = malloc(sizeof(m68k_options)); | 520 m68k_options *opts = malloc(sizeof(m68k_options)); |
451 init_m68k_opts(opts, jag_m68k_map, 8, 2); | 521 init_m68k_opts(opts, jag_m68k_map, 8, 2); |
452 system->m68k = init_68k_context(opts, handle_m68k_reset); | 522 system->m68k = init_68k_context(opts, handle_m68k_reset); |
523 system->m68k->sync_cycle = system->max_cycles; | |
453 system->m68k->system = system; | 524 system->m68k->system = system; |
454 system->video = jag_video_init(); | 525 system->video = jag_video_init(); |
455 system->video->system = system; | 526 system->video->system = system; |
456 return system; | 527 return system; |
457 } | 528 } |