Mercurial > repos > blastem
comparison lc8951.c @ 2144:10e4439d8f13
Fix speed of CDC to PCM RAM DMA
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 26 Mar 2022 00:54:47 -0700 |
parents | d9151d0894c7 |
children | 4cd60eecb0b1 |
comparison
equal
deleted
inserted
replaced
2143:67f20f9188b0 | 2144:10e4439d8f13 |
---|---|
83 { | 83 { |
84 //This seems to vary somewhat between Sega CD models | 84 //This seems to vary somewhat between Sega CD models |
85 //unclear if the difference is in the lc8951 or gate array | 85 //unclear if the difference is in the lc8951 or gate array |
86 context->regs[IFSTAT] = 0xFF; | 86 context->regs[IFSTAT] = 0xFF; |
87 context->ar_mask = 0x1F; | 87 context->ar_mask = 0x1F; |
88 context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period | 88 context->clock_step = (2 + 2); // external divider, internal divider |
89 context->cycles_per_byte = context->clock_step * 6; | |
89 context->byte_handler = byte_handler; | 90 context->byte_handler = byte_handler; |
90 context->handler_data = handler_data; | 91 context->handler_data = handler_data; |
91 context->decode_end = CYCLE_NEVER; | 92 context->decode_end = CYCLE_NEVER; |
92 context->transfer_end = CYCLE_NEVER; | 93 context->transfer_end = CYCLE_NEVER; |
94 context->next_byte_cycle = CYCLE_NEVER; | |
95 } | |
96 | |
97 void lc8951_set_dma_multiple(lc8951 *context, uint32_t multiple) | |
98 { | |
99 context->cycles_per_byte = context->clock_step * multiple; | |
100 if (context->transfer_end != CYCLE_NEVER) { | |
101 uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); | |
102 context->transfer_end = context->next_byte_cycle + transfer_size * context->cycles_per_byte; | |
103 } | |
93 } | 104 } |
94 | 105 |
95 void lc8951_reg_write(lc8951 *context, uint8_t value) | 106 void lc8951_reg_write(lc8951 *context, uint8_t value) |
96 { | 107 { |
97 switch (context->ar) | 108 switch (context->ar) |
128 break; | 139 break; |
129 case DTTRG: | 140 case DTTRG: |
130 if (context->ifctrl & BIT_DOUTEN) { | 141 if (context->ifctrl & BIT_DOUTEN) { |
131 context->regs[IFSTAT] &= ~BIT_DTBSY; | 142 context->regs[IFSTAT] &= ~BIT_DTBSY; |
132 uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); | 143 uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); |
133 context->transfer_end = context->cycle + transfer_size * context->clock_step; | 144 context->transfer_end = context->cycle + transfer_size * context->cycles_per_byte; |
145 context->next_byte_cycle = context->cycle; | |
134 printf("DTTRG: size %u, cycle %u, end %u\n", transfer_size, context->cycle, context->transfer_end); | 146 printf("DTTRG: size %u, cycle %u, end %u\n", transfer_size, context->cycle, context->transfer_end); |
135 } | 147 } |
136 break; | 148 break; |
137 case DTACK: | 149 case DTACK: |
138 context->regs[IFSTAT] |= BIT_DTEI; | 150 context->regs[IFSTAT] |= BIT_DTEI; |
249 context->regs[STAT1] = 0xFF; | 261 context->regs[STAT1] = 0xFF; |
250 context->regs[STAT2] = 0xF2; | 262 context->regs[STAT2] = 0xF2; |
251 } | 263 } |
252 context->regs[STAT3] |= BIT_WLONG; | 264 context->regs[STAT3] |= BIT_WLONG; |
253 } | 265 } |
254 if (context->transfer_end != CYCLE_NEVER) { | 266 if (context->cycle >= context->next_byte_cycle) { |
255 if (context->byte_handler(context->handler_data, context->buffer[context->dac & (sizeof(context->buffer)-1)])) { | 267 if (context->byte_handler(context->handler_data, context->buffer[context->dac & (sizeof(context->buffer)-1)])) { |
268 context->next_byte_cycle += context->cycles_per_byte; | |
256 context->dac++; | 269 context->dac++; |
257 context->regs[DBCL]--; | 270 context->regs[DBCL]--; |
258 if (context->regs[DBCL] == 0xFF) { | 271 if (context->regs[DBCL] == 0xFF) { |
259 context->regs[DBCH]--; | 272 context->regs[DBCH]--; |
260 if (context->regs[DBCH] == 0xFF) { | 273 if (context->regs[DBCH] == 0xFF) { |
262 context->regs[IFSTAT] |= BIT_DTBSY; | 275 context->regs[IFSTAT] |= BIT_DTBSY; |
263 if (context->cycle != context->transfer_end) { | 276 if (context->cycle != context->transfer_end) { |
264 printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle); | 277 printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle); |
265 } | 278 } |
266 context->transfer_end = CYCLE_NEVER; | 279 context->transfer_end = CYCLE_NEVER; |
280 context->next_byte_cycle = CYCLE_NEVER; | |
267 } | 281 } |
268 } | 282 } |
269 } else { | 283 } else { |
270 // pause transfer | 284 // pause transfer |
285 context->next_byte_cycle = CYCLE_NEVER; | |
271 context->transfer_end = CYCLE_NEVER; | 286 context->transfer_end = CYCLE_NEVER; |
272 } | 287 } |
273 } | 288 } |
274 } | 289 } |
275 } | 290 } |
282 //HACK!!! Work around Sub CPU running longer than we would like and dragging other components with it | 297 //HACK!!! Work around Sub CPU running longer than we would like and dragging other components with it |
283 uint32_t step_diff = (context->cycle - cycle) / context->clock_step; | 298 uint32_t step_diff = (context->cycle - cycle) / context->clock_step; |
284 if (step_diff) { | 299 if (step_diff) { |
285 context->cycle -= step_diff * context->clock_step; | 300 context->cycle -= step_diff * context->clock_step; |
286 } | 301 } |
287 context->transfer_end = context->cycle + transfer_size * context->clock_step; | 302 context->transfer_end = context->cycle + transfer_size * context->cycles_per_byte; |
303 context->next_byte_cycle = context->cycle; | |
288 if (step_diff) { | 304 if (step_diff) { |
289 lc8951_run(context, cycle); | 305 lc8951_run(context, cycle); |
290 } | 306 } |
291 } | 307 } |
292 } | 308 } |