Mercurial > repos > blastem
comparison vdp.c @ 1151:681e8a13b261
Fix some issues with VDP interface in Mode 4/PBC mode
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 04 Jan 2017 22:48:00 -0800 |
parents | 322d28e6f13c |
children | ddbb61be6119 |
comparison
equal
deleted
inserted
replaced
1150:322d28e6f13c | 1151:681e8a13b261 |
---|---|
179 //TODO: Figure out which slots are refresh when display is off in 32-cell mode | 179 //TODO: Figure out which slots are refresh when display is off in 32-cell mode |
180 //These numbers are guesses based on H40 numbers | 180 //These numbers are guesses based on H40 numbers |
181 return slot == 243 || slot == 19 || slot == 51 || slot == 83 || slot == 115; | 181 return slot == 243 || slot == 19 || slot == 51 || slot == 83 || slot == 115; |
182 //The numbers below are the refresh slots during active display | 182 //The numbers below are the refresh slots during active display |
183 //return (slot == 29 || slot == 61 || slot == 93 || slot == 125); | 183 //return (slot == 29 || slot == 61 || slot == 93 || slot == 125); |
184 } | |
185 } | |
186 | |
187 static void increment_address(vdp_context *context) | |
188 { | |
189 context->address += context->regs[REG_AUTOINC]; | |
190 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { | |
191 context->address++; | |
184 } | 192 } |
185 } | 193 } |
186 | 194 |
187 static void render_sprite_cells(vdp_context * context) | 195 static void render_sprite_cells(vdp_context * context) |
188 { | 196 { |
781 if (context->flags2 & FLAG2_READ_PENDING) { | 789 if (context->flags2 & FLAG2_READ_PENDING) { |
782 context->prefetch |= context->vdpmem[context->address | 1]; | 790 context->prefetch |= context->vdpmem[context->address | 1]; |
783 context->flags |= FLAG_READ_FETCHED; | 791 context->flags |= FLAG_READ_FETCHED; |
784 context->flags2 &= ~FLAG2_READ_PENDING; | 792 context->flags2 &= ~FLAG2_READ_PENDING; |
785 //Should this happen after the prefetch or after the read? | 793 //Should this happen after the prefetch or after the read? |
786 //context->address += context->regs[REG_AUTOINC]; | 794 //increment_address(context); |
787 } else { | 795 } else { |
788 context->prefetch = context->vdpmem[context->address & 0xFFFE] << 8; | 796 context->prefetch = context->vdpmem[context->address & 0xFFFE] << 8; |
789 context->flags2 |= FLAG2_READ_PENDING; | 797 context->flags2 |= FLAG2_READ_PENDING; |
790 } | 798 } |
791 break; | 799 break; |
792 case VRAM_READ8: | 800 case VRAM_READ8: { |
793 context->prefetch = context->vdpmem[context->address ^ 1]; | 801 uint32_t address = context->address ^ 1; |
802 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { | |
803 address = mode4_address_map[address & 0x3FFF]; | |
804 } | |
805 context->prefetch = context->vdpmem[address]; | |
794 context->prefetch |= context->fifo[context->fifo_write].value & 0xFF00; | 806 context->prefetch |= context->fifo[context->fifo_write].value & 0xFF00; |
795 context->flags |= FLAG_READ_FETCHED; | 807 context->flags |= FLAG_READ_FETCHED; |
796 //Should this happen after the prefetch or after the read? | 808 //Should this happen after the prefetch or after the read? |
797 //context->address += context->regs[REG_AUTOINC]; | 809 //increment_address(context); |
798 break; | 810 break; |
811 } | |
799 case CRAM_READ: | 812 case CRAM_READ: |
800 context->prefetch = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; | 813 context->prefetch = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; |
801 context->prefetch |= context->fifo[context->fifo_write].value & ~CRAM_BITS; | 814 context->prefetch |= context->fifo[context->fifo_write].value & ~CRAM_BITS; |
802 context->flags |= FLAG_READ_FETCHED; | 815 context->flags |= FLAG_READ_FETCHED; |
803 //Should this happen after the prefetch or after the read? | 816 //Should this happen after the prefetch or after the read? |
804 //context->address += context->regs[REG_AUTOINC]; | 817 //increment_address(context); |
805 break; | 818 break; |
806 case VSRAM_READ: { | 819 case VSRAM_READ: { |
807 uint16_t address = (context->address /2) & 63; | 820 uint16_t address = (context->address /2) & 63; |
808 if (address >= VSRAM_SIZE) { | 821 if (address >= VSRAM_SIZE) { |
809 address = 0; | 822 address = 0; |
810 } | 823 } |
811 context->prefetch = context->vsram[address] & VSRAM_BITS; | 824 context->prefetch = context->vsram[address] & VSRAM_BITS; |
812 context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; | 825 context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; |
813 context->flags |= FLAG_READ_FETCHED; | 826 context->flags |= FLAG_READ_FETCHED; |
814 //Should this happen after the prefetch or after the read? | 827 //Should this happen after the prefetch or after the read? |
815 //context->address += context->regs[REG_AUTOINC]; | 828 //increment_address(context); |
816 break; | 829 break; |
817 } | 830 } |
818 } | 831 } |
819 } | 832 } |
820 } | 833 } |
2161 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); | 2174 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); |
2162 } | 2175 } |
2163 } | 2176 } |
2164 } else { | 2177 } else { |
2165 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; | 2178 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; |
2179 context->address = (context->address &0xC000) | (value & 0x3FFF); | |
2180 //Genesis Plus GX doesn't clear out the mode bits in Mode 4, but instead | |
2181 //ignores the uppper mode bits when it comes to reads/writes | |
2182 //testing on hardware is needed to determine which is truly correct | |
2183 context->cd = (mode_5 ? context->cd &0x3C : 0) | (value >> 14); | |
2166 if ((value & 0xC000) == 0x8000) { | 2184 if ((value & 0xC000) == 0x8000) { |
2167 //Register write | 2185 //Register write |
2168 uint8_t reg = (value >> 8) & 0x1F; | 2186 uint8_t reg = (value >> 8) & 0x1F; |
2169 if (reg < (mode_5 ? VDP_REGS : 0xB)) { | 2187 if (reg < (mode_5 ? VDP_REGS : 0xB)) { |
2170 //printf("register %d set to %X\n", reg, value & 0xFF); | 2188 //printf("register %d set to %X\n", reg, value & 0xFF); |
2182 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); | 2200 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); |
2183 if (!context->double_res) { | 2201 if (!context->double_res) { |
2184 context->flags2 &= ~FLAG2_EVEN_FIELD; | 2202 context->flags2 &= ~FLAG2_EVEN_FIELD; |
2185 } | 2203 } |
2186 } | 2204 } |
2187 context->cd &= 0x3C; | |
2188 } | 2205 } |
2189 } else if (mode_5) { | 2206 } else if (mode_5) { |
2190 context->flags |= FLAG_PENDING; | 2207 context->flags |= FLAG_PENDING; |
2191 context->address = (context->address &0xC000) | (value & 0x3FFF); | |
2192 context->cd = (context->cd &0x3C) | (value >> 14); | |
2193 //Should these be taken care of here or after the second write? | 2208 //Should these be taken care of here or after the second write? |
2194 //context->flags &= ~FLAG_READ_FETCHED; | 2209 //context->flags &= ~FLAG_READ_FETCHED; |
2195 //context->flags2 &= ~FLAG2_READ_PENDING; | 2210 //context->flags2 &= ~FLAG2_READ_PENDING; |
2196 } else { | 2211 } else { |
2197 context->address = value & 0x3FFF; | |
2198 context->cd = value >> 14; | |
2199 context->flags &= ~FLAG_READ_FETCHED; | 2212 context->flags &= ~FLAG_READ_FETCHED; |
2200 context->flags2 &= ~FLAG2_READ_PENDING; | 2213 context->flags2 &= ~FLAG2_READ_PENDING; |
2201 } | 2214 } |
2202 } | 2215 } |
2203 return 0; | 2216 return 0; |
2208 if (context->flags2 & FLAG2_BYTE_PENDING) { | 2221 if (context->flags2 & FLAG2_BYTE_PENDING) { |
2209 uint16_t full_val = value << 8 | context->pending_byte; | 2222 uint16_t full_val = value << 8 | context->pending_byte; |
2210 context->flags2 &= ~FLAG2_BYTE_PENDING; | 2223 context->flags2 &= ~FLAG2_BYTE_PENDING; |
2211 //TODO: Deal with fact that Vbus->VDP DMA doesn't do anything in PBC mode | 2224 //TODO: Deal with fact that Vbus->VDP DMA doesn't do anything in PBC mode |
2212 vdp_control_port_write(context, full_val); | 2225 vdp_control_port_write(context, full_val); |
2226 if (context->cd == VRAM_READ) { | |
2227 context->cd = VRAM_READ8; | |
2228 } | |
2213 } else { | 2229 } else { |
2214 context->pending_byte = value; | 2230 context->pending_byte = value; |
2215 context->flags2 |= FLAG2_BYTE_PENDING; | 2231 context->flags2 |= FLAG2_BYTE_PENDING; |
2216 } | 2232 } |
2217 } | 2233 } |
2245 cur->partial = 0; | 2261 cur->partial = 0; |
2246 if (context->fifo_read < 0) { | 2262 if (context->fifo_read < 0) { |
2247 context->fifo_read = context->fifo_write; | 2263 context->fifo_read = context->fifo_write; |
2248 } | 2264 } |
2249 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); | 2265 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); |
2250 context->address += context->regs[REG_AUTOINC]; | 2266 increment_address(context); |
2267 return 0; | |
2268 } | |
2269 | |
2270 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value) | |
2271 { | |
2272 if (context->flags & FLAG_PENDING) { | |
2273 context->flags &= ~FLAG_PENDING; | |
2274 context->flags2 &= ~FLAG2_BYTE_PENDING; | |
2275 //Should these be cleared here? | |
2276 context->flags &= ~FLAG_READ_FETCHED; | |
2277 context->flags2 &= ~FLAG2_READ_PENDING; | |
2278 } | |
2279 /*if (context->fifo_cur == context->fifo_end) { | |
2280 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); | |
2281 }*/ | |
2282 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { | |
2283 context->flags &= ~FLAG_DMA_RUN; | |
2284 } | |
2285 while (context->fifo_write == context->fifo_read) { | |
2286 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); | |
2287 } | |
2288 fifo_entry * cur = context->fifo + context->fifo_write; | |
2289 cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; | |
2290 cur->address = context->address; | |
2291 cur->value = value; | |
2292 cur->cd = context->cd | 1; | |
2293 cur->partial = 1; | |
2294 if (context->fifo_read < 0) { | |
2295 context->fifo_read = context->fifo_write; | |
2296 } | |
2297 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); | |
2298 increment_address(context); | |
2299 } | |
2300 | |
2301 void vdp_test_port_write(vdp_context * context, uint16_t value) | |
2302 { | |
2303 //TODO: implement test register | |
2304 } | |
2305 | |
2306 uint16_t vdp_control_port_read(vdp_context * context) | |
2307 { | |
2308 context->flags &= ~FLAG_PENDING; | |
2309 context->flags2 &= ~FLAG2_BYTE_PENDING; | |
2310 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch | |
2311 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00; | |
2312 if (context->fifo_read < 0) { | |
2313 value |= 0x200; | |
2314 } | |
2315 if (context->fifo_read == context->fifo_write) { | |
2316 value |= 0x100; | |
2317 } | |
2318 if (context->flags2 & FLAG2_VINT_PENDING) { | |
2319 value |= 0x80; | |
2320 } | |
2321 if (context->flags & FLAG_DOT_OFLOW) { | |
2322 value |= 0x40; | |
2323 } | |
2324 if (context->flags2 & FLAG2_SPRITE_COLLIDE) { | |
2325 value |= 0x20; | |
2326 context->flags2 &= ~FLAG2_SPRITE_COLLIDE; | |
2327 } | |
2328 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) { | |
2329 value |= 0x10; | |
2330 } | |
2331 uint32_t line= context->vcounter; | |
2332 uint32_t slot = context->hslot; | |
2333 uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); | |
2251 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { | 2334 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { |
2252 context->address++; | 2335 inactive_start = MODE4_INACTIVE_START; |
2253 } | 2336 } |
2254 return 0; | 2337 if ((line >= inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { |
2255 } | 2338 value |= 0x8; |
2256 | 2339 } |
2257 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value) | 2340 if (context->regs[REG_MODE_4] & BIT_H40) { |
2341 if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) { | |
2342 value |= 0x4; | |
2343 } | |
2344 } else { | |
2345 if (slot < HBLANK_END_H32 || slot > HBLANK_START_H32) { | |
2346 value |= 0x4; | |
2347 } | |
2348 } | |
2349 if (context->cd & 0x20) { | |
2350 value |= 0x2; | |
2351 } | |
2352 if (context->flags2 & FLAG2_REGION_PAL) { | |
2353 value |= 0x1; | |
2354 } | |
2355 //printf("status read at cycle %d returned %X\n", context->cycles, value); | |
2356 return value; | |
2357 } | |
2358 | |
2359 uint16_t vdp_data_port_read(vdp_context * context) | |
2258 { | 2360 { |
2259 if (context->flags & FLAG_PENDING) { | 2361 if (context->flags & FLAG_PENDING) { |
2260 context->flags &= ~FLAG_PENDING; | 2362 context->flags &= ~FLAG_PENDING; |
2261 //Should these be cleared here? | 2363 //Should these be cleared here? |
2262 context->flags &= ~FLAG_READ_FETCHED; | 2364 context->flags &= ~FLAG_READ_FETCHED; |
2263 context->flags2 &= ~FLAG2_READ_PENDING; | 2365 context->flags2 &= ~FLAG2_READ_PENDING; |
2264 } | 2366 } |
2265 /*if (context->fifo_cur == context->fifo_end) { | 2367 if (context->cd & 1) { |
2266 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); | 2368 warning("Read from VDP data port while writes are configured, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd); |
2267 }*/ | 2369 } |
2268 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { | 2370 while (!(context->flags & FLAG_READ_FETCHED)) { |
2269 context->flags &= ~FLAG_DMA_RUN; | |
2270 } | |
2271 while (context->fifo_write == context->fifo_read) { | |
2272 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); | 2371 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); |
2273 } | 2372 } |
2274 fifo_entry * cur = context->fifo + context->fifo_write; | 2373 context->flags &= ~FLAG_READ_FETCHED; |
2275 cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; | 2374 //Should this happen after the prefetch or after the read? |
2276 cur->address = context->address; | 2375 increment_address(context); |
2277 cur->value = value; | 2376 return context->prefetch; |
2278 cur->cd = context->cd; | 2377 } |
2279 cur->partial = 1; | 2378 |
2280 if (context->fifo_read < 0) { | 2379 uint8_t vdp_data_port_read_pbc(vdp_context * context) |
2281 context->fifo_read = context->fifo_write; | |
2282 } | |
2283 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); | |
2284 context->address += context->regs[REG_AUTOINC]; | |
2285 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { | |
2286 context->address++; | |
2287 } | |
2288 } | |
2289 | |
2290 void vdp_test_port_write(vdp_context * context, uint16_t value) | |
2291 { | |
2292 //TODO: implement test register | |
2293 } | |
2294 | |
2295 uint16_t vdp_control_port_read(vdp_context * context) | |
2296 { | |
2297 context->flags &= ~FLAG_PENDING; | |
2298 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch | |
2299 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00; | |
2300 if (context->fifo_read < 0) { | |
2301 value |= 0x200; | |
2302 } | |
2303 if (context->fifo_read == context->fifo_write) { | |
2304 value |= 0x100; | |
2305 } | |
2306 if (context->flags2 & FLAG2_VINT_PENDING) { | |
2307 value |= 0x80; | |
2308 } | |
2309 if (context->flags & FLAG_DOT_OFLOW) { | |
2310 value |= 0x40; | |
2311 } | |
2312 if (context->flags2 & FLAG2_SPRITE_COLLIDE) { | |
2313 value |= 0x20; | |
2314 context->flags2 &= ~FLAG2_SPRITE_COLLIDE; | |
2315 } | |
2316 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) { | |
2317 value |= 0x10; | |
2318 } | |
2319 uint32_t line= context->vcounter; | |
2320 uint32_t slot = context->hslot; | |
2321 uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); | |
2322 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { | |
2323 inactive_start = MODE4_INACTIVE_START; | |
2324 } | |
2325 if ((line >= inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { | |
2326 value |= 0x8; | |
2327 } | |
2328 if (context->regs[REG_MODE_4] & BIT_H40) { | |
2329 if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) { | |
2330 value |= 0x4; | |
2331 } | |
2332 } else { | |
2333 if (slot < HBLANK_END_H32 || slot > HBLANK_START_H32) { | |
2334 value |= 0x4; | |
2335 } | |
2336 } | |
2337 if (context->cd & 0x20) { | |
2338 value |= 0x2; | |
2339 } | |
2340 if (context->flags2 & FLAG2_REGION_PAL) { | |
2341 value |= 0x1; | |
2342 } | |
2343 //printf("status read at cycle %d returned %X\n", context->cycles, value); | |
2344 return value; | |
2345 } | |
2346 | |
2347 uint16_t vdp_data_port_read(vdp_context * context) | |
2348 { | 2380 { |
2349 if (context->flags & FLAG_PENDING) { | 2381 if (context->flags & FLAG_PENDING) { |
2350 context->flags &= ~FLAG_PENDING; | 2382 context->flags &= ~FLAG_PENDING; |
2351 //Should these be cleared here? | 2383 context->flags2 &= ~FLAG2_BYTE_PENDING; |
2384 | |
2385 } | |
2386 if (context->flags & FLAG_READ_FETCHED) { | |
2352 context->flags &= ~FLAG_READ_FETCHED; | 2387 context->flags &= ~FLAG_READ_FETCHED; |
2353 context->flags2 &= ~FLAG2_READ_PENDING; | 2388 //Should this happen after the prefetch or after the read? |
2354 } | 2389 increment_address(context); |
2355 if (context->cd & 1) { | 2390 } |
2356 warning("Read from VDP data port while writes are configured, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd); | 2391 context->cd &= ~1; |
2357 } | 2392 if (context->cd == VRAM_READ) { |
2358 while (!(context->flags & FLAG_READ_FETCHED)) { | 2393 context->cd = VRAM_READ8; |
2359 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); | 2394 } |
2360 } | |
2361 context->flags &= ~FLAG_READ_FETCHED; | |
2362 //Should this happen after the prefetch or after the read? | |
2363 context->address += context->regs[REG_AUTOINC]; | |
2364 return context->prefetch; | |
2365 } | |
2366 | |
2367 uint8_t vdp_data_port_read_pbc(vdp_context * context) | |
2368 { | |
2369 if (context->flags & FLAG_PENDING) { | |
2370 context->flags &= ~FLAG_PENDING; | |
2371 //Should these be cleared here? | |
2372 context->flags &= ~FLAG_READ_FETCHED; | |
2373 context->flags2 &= ~FLAG2_READ_PENDING; | |
2374 } | |
2375 context->flags &= ~FLAG_READ_FETCHED; | |
2376 //Should this happen after the prefetch or after the read? | |
2377 context->address += context->regs[REG_AUTOINC]; | |
2378 return context->prefetch; | 2395 return context->prefetch; |
2379 } | 2396 } |
2380 | 2397 |
2381 uint16_t vdp_hv_counter_read(vdp_context * context) | 2398 uint16_t vdp_hv_counter_read(vdp_context * context) |
2382 { | 2399 { |