comparison lc8951.c @ 2065:02a9846668d1 segacd

Implement transfer of data from CDC to elsewhere. Other miscellaneous CDD/CDC improvements
author Michael Pavone <pavone@retrodev.com>
date Sat, 29 Jan 2022 17:43:37 -0800
parents 07ed42bd7b4c
children a61a8a87410c
comparison
equal deleted inserted replaced
2064:91e4d2fe5cd9 2065:02a9846668d1
62 62
63 //datasheet timing info 63 //datasheet timing info
64 //3 cycles for memory operation 64 //3 cycles for memory operation
65 //6 cycles min for DMA-mode host transfer 65 //6 cycles min for DMA-mode host transfer
66 66
67 void lc8951_init(lc8951 *context) 67 void lc8951_init(lc8951 *context, lcd8951_byte_recv_fun byte_handler, void *handler_data)
68 { 68 {
69 //This seems to vary somewhat between Sega CD models 69 //This seems to vary somewhat between Sega CD models
70 //unclear if the difference is in the lc8951 or gate array 70 //unclear if the difference is in the lc8951 or gate array
71 context->regs[IFSTAT] = 0xFF; 71 context->regs[IFSTAT] = 0xFF;
72 context->ar_mask = 0x1F; 72 context->ar_mask = 0x1F;
73 context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period 73 context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period
74 context->byte_handler = byte_handler;
75 context->handler_data = handler_data;
76 context->decode_end = CYCLE_NEVER;
77 context->transfer_end = CYCLE_NEVER;
74 } 78 }
75 79
76 void lc8951_reg_write(lc8951 *context, uint8_t value) 80 void lc8951_reg_write(lc8951 *context, uint8_t value)
77 { 81 {
78 printf("CDC write %X: %X\n", context->ar, value); 82 printf("CDC write %X: %X\n", context->ar, value);
89 if (!(value & BIT_SOUTEN)) { 93 if (!(value & BIT_SOUTEN)) {
90 context->regs[IFSTAT] |= BIT_STBSY; 94 context->regs[IFSTAT] |= BIT_STBSY;
91 } 95 }
92 if (!(value & BIT_DOUTEN)) { 96 if (!(value & BIT_DOUTEN)) {
93 context->regs[IFSTAT] |= BIT_DTBSY; 97 context->regs[IFSTAT] |= BIT_DTBSY;
98 context->transfer_end = CYCLE_NEVER;
94 } 99 }
95 break; 100 break;
96 case DBCL: 101 case DBCL:
97 context->regs[context->ar] = value; 102 context->regs[context->ar] = value;
98 break; 103 break;
106 case DACH: 111 case DACH:
107 context->dac &= 0xFF; 112 context->dac &= 0xFF;
108 context->dac |= value << 8; 113 context->dac |= value << 8;
109 break; 114 break;
110 case DTTRG: 115 case DTTRG:
111 if (value & BIT_DOUTEN) { 116 if (context->ifctrl & BIT_DOUTEN) {
112 context->regs[IFSTAT] &= ~BIT_DTBSY; 117 context->regs[IFSTAT] &= ~BIT_DTBSY;
113 uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); 118 uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8);
114 context->transfer_end = context->cycle + transfer_size * context->clock_step; 119 context->transfer_end = context->cycle + transfer_size * context->clock_step;
120 printf("DTTRG: size %u, cycle %u, end %u\n", transfer_size, context->cycle, context->transfer_end);
115 } 121 }
116 break; 122 break;
117 case DTACK: 123 case DTACK:
118 context->regs[IFSTAT] |= BIT_DTEI; 124 context->regs[IFSTAT] |= BIT_DTEI;
119 break; 125 break;
206 block_start &= (sizeof(context->buffer)-1); 212 block_start &= (sizeof(context->buffer)-1);
207 } 213 }
208 printf("Decode done %X:%X:%X mode %X\n", context->regs[HEAD0], context->regs[HEAD1], context->regs[HEAD2], context->regs[HEAD3]); 214 printf("Decode done %X:%X:%X mode %X\n", context->regs[HEAD0], context->regs[HEAD1], context->regs[HEAD2], context->regs[HEAD3]);
209 } 215 }
210 if (context->transfer_end != CYCLE_NEVER) { 216 if (context->transfer_end != CYCLE_NEVER) {
211 //TODO: transfer byte to gate array destination 217 if (context->byte_handler(context->handler_data, context->buffer[context->dac & (sizeof(context->buffer)-1)])) {
212 context->dac++; 218 context->dac++;
213 context->regs[DBCL]--; 219 context->regs[DBCL]--;
214 if (!context->regs[DBCL]) { 220 if (context->regs[DBCL] == 0xFF) {
215 context->regs[DBCH]--; 221 context->regs[DBCH]--;
216 if (!context->regs[DBCH]) { 222 if (context->regs[DBCH] == 0xFF) {
217 context->regs[IFSTAT] &= ~BIT_DTEI; 223 context->regs[IFSTAT] &= ~BIT_DTEI;
218 if (context->cycle != context->transfer_end) { 224 context->regs[IFSTAT] |= BIT_DTBSY;
219 printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle); 225 if (context->cycle != context->transfer_end) {
226 printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle);
227 }
228 context->transfer_end = CYCLE_NEVER;
220 } 229 }
221 context->transfer_end = CYCLE_NEVER;
222 } 230 }
231 } else {
232 // pause transfer
233 context->transfer_end = CYCLE_NEVER;
223 } 234 }
235 }
236 }
237 }
238
239 void lc8951_resume_transfer(lc8951 *context)
240 {
241 if (context->transfer_end == CYCLE_NEVER && (context->ifctrl & BIT_DOUTEN)) {
242 uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8);
243 if (transfer_size) {
244 context->transfer_end = context->cycle + transfer_size * context->clock_step;
245 printf("RESUME: size %u, cycle %u, end %u\n", transfer_size, context->cycle, context->transfer_end);
224 } 246 }
225 } 247 }
226 } 248 }
227 249
228 void lc8951_write_byte(lc8951 *context, uint32_t cycle, int sector_offset, uint8_t byte) 250 void lc8951_write_byte(lc8951 *context, uint32_t cycle, int sector_offset, uint8_t byte)
249 //monitor only mode 271 //monitor only mode
250 context->regs[HEAD0 + sector_offset - 12] = byte; 272 context->regs[HEAD0 + sector_offset - 12] = byte;
251 } 273 }
252 } 274 }
253 if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN|BIT_WRRQ)) { 275 if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN|BIT_WRRQ)) {
254 printf("lc8951_write_byte: %X - [%X] = %X\n", sector_offset, current_write_addr, byte);
255 context->buffer[current_write_addr & (sizeof(context->buffer)-1)] = byte; 276 context->buffer[current_write_addr & (sizeof(context->buffer)-1)] = byte;
256 context->regs[WAL]++; 277 context->regs[WAL]++;
257 if (!context->regs[WAL]) { 278 if (!context->regs[WAL]) {
258 context->regs[WAH]++; 279 context->regs[WAH]++;
259 } 280 }
260 } 281 }
261 } 282 }
262 283
263 uint32_t lc8951_next_interrupt(lc8951 *context) 284 uint32_t lc8951_next_interrupt(lc8951 *context)
264 { 285 {
265 if ((!context->regs[IFSTAT]) & context->ifctrl & (BIT_CMDI|BIT_DTEI|BIT_DECI)) { 286 if ((~context->regs[IFSTAT]) & context->ifctrl & (BIT_CMDI|BIT_DTEI|BIT_DECI)) {
266 //interrupt already pending 287 //interrupt already pending
267 return context->cycle; 288 return context->cycle;
268 } 289 }
269 uint32_t deci_cycle = CYCLE_NEVER; 290 uint32_t deci_cycle = CYCLE_NEVER;
270 if (context->ifctrl & BIT_DECI) { 291 if (context->ifctrl & BIT_DECI) {