Mercurial > repos > blastem
comparison lc8951.c @ 2067:f22e04b69272 segacd
More CDC/CDD improvements
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 30 Jan 2022 11:58:17 -0800 |
parents | a61a8a87410c |
children | c69e42444f96 |
comparison
equal
deleted
inserted
replaced
2066:a61a8a87410c | 2067:f22e04b69272 |
---|---|
55 | 55 |
56 //CTRL0 | 56 //CTRL0 |
57 #define BIT_DECEN 0x80 | 57 #define BIT_DECEN 0x80 |
58 #define BIT_WRRQ 0x04 | 58 #define BIT_WRRQ 0x04 |
59 | 59 |
60 //STAT0 | |
61 #define BIT_CRCOK 0x80 | |
62 | |
60 //STAT3 | 63 //STAT3 |
61 #define BIT_VALST 0x80 | 64 #define BIT_VALST 0x80 |
62 | |
63 #define DECI_AUTO_CLEAR 575 | |
64 | 65 |
65 //datasheet timing info | 66 //datasheet timing info |
66 //3 cycles for memory operation | 67 //3 cycles for memory operation |
67 //6 cycles min for DMA-mode host transfer | 68 //6 cycles min for DMA-mode host transfer |
68 | 69 |
75 context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period | 76 context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period |
76 context->byte_handler = byte_handler; | 77 context->byte_handler = byte_handler; |
77 context->handler_data = handler_data; | 78 context->handler_data = handler_data; |
78 context->decode_end = CYCLE_NEVER; | 79 context->decode_end = CYCLE_NEVER; |
79 context->transfer_end = CYCLE_NEVER; | 80 context->transfer_end = CYCLE_NEVER; |
80 context->deci_clear = CYCLE_NEVER; | |
81 } | 81 } |
82 | 82 |
83 void lc8951_reg_write(lc8951 *context, uint8_t value) | 83 void lc8951_reg_write(lc8951 *context, uint8_t value) |
84 { | 84 { |
85 switch (context->ar) | 85 switch (context->ar) |
140 case PTL_WRITE: | 140 case PTL_WRITE: |
141 context->regs[PTL] = value; | 141 context->regs[PTL] = value; |
142 break; | 142 break; |
143 case PTH_WRITE: | 143 case PTH_WRITE: |
144 context->regs[PTH] = value; | 144 context->regs[PTH] = value; |
145 context->ptl_internal = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer) - 1); | 145 //TODO: Datasheet says any write to PT triggers a decode, but initial tests suggest that's not the case |
146 context->decoding = 1; | 146 //Need to do more tests with other CTRL0/CTRL1 settings |
147 context->decode_end = context->cycle + 2352 * context->clock_step * 4; | 147 //context->decode_end = context->cycle + 2352 * context->clock_step * 4; |
148 break; | 148 break; |
149 case RESET: | 149 case RESET: |
150 context->comin_count = 0; | 150 context->comin_count = 0; |
151 context->regs[IFSTAT] = 0xFF; | 151 context->regs[IFSTAT] = 0xFF; |
152 break; | 152 break; |
173 } | 173 } |
174 return value; | 174 return value; |
175 } | 175 } |
176 if (context->ar == STAT3) { | 176 if (context->ar == STAT3) { |
177 context->regs[IFSTAT] |= BIT_DECI; | 177 context->regs[IFSTAT] |= BIT_DECI; |
178 context->deci_clear = CYCLE_NEVER; | |
179 } | 178 } |
180 if (context->ar >= sizeof(context->regs)) { | 179 if (context->ar >= sizeof(context->regs)) { |
181 value = 0xFF; | 180 value = 0xFF; |
182 } else { | 181 } else { |
183 value = context->regs[context->ar]; | 182 value = context->regs[context->ar]; |
204 for(; context->cycle < cycle; context->cycle += context->clock_step) | 203 for(; context->cycle < cycle; context->cycle += context->clock_step) |
205 { | 204 { |
206 if (context->cycle >= context->decode_end) { | 205 if (context->cycle >= context->decode_end) { |
207 context->decode_end = CYCLE_NEVER; | 206 context->decode_end = CYCLE_NEVER; |
208 context->regs[IFSTAT] &= ~BIT_DECI; | 207 context->regs[IFSTAT] &= ~BIT_DECI; |
209 context->deci_clear = context->cycle + DECI_AUTO_CLEAR; | |
210 context->regs[STAT3] &= ~BIT_VALST; | 208 context->regs[STAT3] &= ~BIT_VALST; |
211 uint16_t block_start = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer)-1); | 209 if (context->ctrl0 & BIT_WRRQ) { |
212 for (int reg = HEAD0; reg < PTL; reg++) | 210 uint16_t block_start = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer)-1); |
213 { | 211 for (int reg = HEAD0; reg < PTL; reg++) |
214 printf("Setting HEAD%d to buffer[%X]\n", reg - HEAD0, block_start); | 212 { |
215 context->regs[reg] =context->buffer[block_start++]; | 213 printf("Setting HEAD%d to buffer[%X]\n", reg - HEAD0, block_start); |
216 block_start &= (sizeof(context->buffer)-1); | 214 context->regs[reg] =context->buffer[block_start++]; |
215 block_start &= (sizeof(context->buffer)-1); | |
216 } | |
217 } | 217 } |
218 printf("Decode done %X:%X:%X mode %X\n", context->regs[HEAD0], context->regs[HEAD1], context->regs[HEAD2], context->regs[HEAD3]); | 218 printf("Decode done %X:%X:%X mode %X\n", context->regs[HEAD0], context->regs[HEAD1], context->regs[HEAD2], context->regs[HEAD3]); |
219 context->regs[STAT0] |= BIT_CRCOK; | |
219 } | 220 } |
220 if (context->transfer_end != CYCLE_NEVER) { | 221 if (context->transfer_end != CYCLE_NEVER) { |
221 if (context->byte_handler(context->handler_data, context->buffer[context->dac & (sizeof(context->buffer)-1)])) { | 222 if (context->byte_handler(context->handler_data, context->buffer[context->dac & (sizeof(context->buffer)-1)])) { |
222 context->dac++; | 223 context->dac++; |
223 context->regs[DBCL]--; | 224 context->regs[DBCL]--; |
235 } else { | 236 } else { |
236 // pause transfer | 237 // pause transfer |
237 context->transfer_end = CYCLE_NEVER; | 238 context->transfer_end = CYCLE_NEVER; |
238 } | 239 } |
239 } | 240 } |
240 if (context->cycle >= context->deci_clear) { | |
241 context->regs[IFSTAT] |= BIT_DECI; | |
242 context->deci_clear = CYCLE_NEVER; | |
243 } | |
244 } | 241 } |
245 } | 242 } |
246 | 243 |
247 void lc8951_resume_transfer(lc8951 *context, uint32_t cycle) | 244 void lc8951_resume_transfer(lc8951 *context, uint32_t cycle) |
248 { | 245 { |
270 if (sector_offset == 12) { | 267 if (sector_offset == 12) { |
271 //we've recevied the sync pattern for the next block | 268 //we've recevied the sync pattern for the next block |
272 | 269 |
273 //header/status regs no longer considered "valid" | 270 //header/status regs no longer considered "valid" |
274 context->regs[STAT3] |= BIT_VALST; | 271 context->regs[STAT3] |= BIT_VALST; |
275 if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN|BIT_WRRQ)) { | 272 //!DECI is set inactive at the same time as !VALST |
276 uint16_t block_start = current_write_addr - 2352; | 273 context->regs[IFSTAT] |= BIT_DECI; |
277 context->regs[PTL] = block_start; | 274 if (context->ctrl0 & BIT_DECEN) { |
278 context->regs[PTH] = block_start >> 8; | 275 if (context->ctrl0 & BIT_WRRQ) { |
279 printf("Decoding block starting at %X\n", block_start); | 276 uint16_t block_start = current_write_addr - 2352; |
280 context->ptl_internal = block_start & (sizeof(context->buffer)-1); | 277 context->regs[PTL] = block_start; |
278 context->regs[PTH] = block_start >> 8; | |
279 } | |
280 printf("Decoding block starting at %X\n", context->regs[PTL] | (context->regs[PTH] << 8)); | |
281 //TODO: Datasheet has some hints about how long decoding takes in the form of how long DECI is asserted | |
281 context->decode_end = context->cycle + 2352 * context->clock_step * 4; | 282 context->decode_end = context->cycle + 2352 * context->clock_step * 4; |
282 } | 283 } |
283 } | 284 } |
284 if (sector_offset >= 12 && sector_offset < 16) { | 285 if (sector_offset >= 12 && sector_offset < 16) { |
285 //TODO: Handle SHDREN = 1 | 286 //TODO: Handle SHDREN = 1 |
320 context->decode_end -= deduction; | 321 context->decode_end -= deduction; |
321 } | 322 } |
322 if (context->transfer_end != CYCLE_NEVER) { | 323 if (context->transfer_end != CYCLE_NEVER) { |
323 context->transfer_end -= deduction; | 324 context->transfer_end -= deduction; |
324 } | 325 } |
325 if (context->deci_clear != CYCLE_NEVER) { | 326 } |
326 context->transfer_end -= deduction; | |
327 } | |
328 } |