comparison lc8951.c @ 2062:07ed42bd7b4c segacd

Some progress on CDC and CDD emulation. Now passes first 3 "CDC INIT" tests in mcd-verificator
author Michael Pavone <pavone@retrodev.com>
date Fri, 28 Jan 2022 00:50:17 -0800
parents 70260f6051dd
children 02a9846668d1
comparison
equal deleted inserted replaced
2061:7c1760b5b3e5 2062:07ed42bd7b4c
1 #include "lc8951.h" 1 #include "lc8951.h"
2 #include "backend.h"
2 3
3 enum { 4 enum {
4 COMIN, 5 COMIN,
5 IFSTAT, 6 IFSTAT,
6 DBCL, 7 DBCL,
34 }; 35 };
35 36
36 //IFCTRL 37 //IFCTRL
37 #define BIT_CMDIEN 0x80 38 #define BIT_CMDIEN 0x80
38 #define BIT_DTEIEN 0x40 39 #define BIT_DTEIEN 0x40
39 #define BIT_CECIEN 0x20 40 #define BIT_DECIEN 0x20
40 #define BIT_CMDBK 0x10 41 #define BIT_CMDBK 0x10
41 #define BIT_DTWAI 0x08 42 #define BIT_DTWAI 0x08
42 #define BIT_STWAI 0x04 43 #define BIT_STWAI 0x04
43 #define BIT_DOUTEN 0x02 44 #define BIT_DOUTEN 0x02
44 #define BIT_SOUTEN 0x01 45 #define BIT_SOUTEN 0x01
50 #define BIT_DTBSY 0x08 51 #define BIT_DTBSY 0x08
51 #define BIT_STBSY 0x04 52 #define BIT_STBSY 0x04
52 #define BIT_DTEN 0x02 53 #define BIT_DTEN 0x02
53 #define BIT_STEN 0x01 54 #define BIT_STEN 0x01
54 55
56 //CTRL0
57 #define BIT_DECEN 0x80
58 #define BIT_WRRQ 0x04
59
60 //STAT3
61 #define BIT_VALST 0x80
62
55 //datasheet timing info 63 //datasheet timing info
56 //3 cycles for memory operation 64 //3 cycles for memory operation
57 //6 cycles min for DMA-mode host transfer 65 //6 cycles min for DMA-mode host transfer
58 66
59 void lc8951_init(lc8951 *context) 67 void lc8951_init(lc8951 *context)
60 { 68 {
61 //This seems to vary somewhat between Sega CD models 69 //This seems to vary somewhat between Sega CD models
62 //unclear if the difference is in the lc8951 or gate array 70 //unclear if the difference is in the lc8951 or gate array
63 context->regs[IFSTAT] = 0xFF; 71 context->regs[IFSTAT] = 0xFF;
64 context->ar_mask = 0x1F; 72 context->ar_mask = 0x1F;
73 context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period
65 } 74 }
66 75
67 void lc8951_reg_write(lc8951 *context, uint8_t value) 76 void lc8951_reg_write(lc8951 *context, uint8_t value)
68 { 77 {
78 printf("CDC write %X: %X\n", context->ar, value);
69 switch (context->ar) 79 switch (context->ar)
70 { 80 {
71 case SBOUT: 81 case SBOUT:
72 context->regs[context->ar] = value; 82 context->regs[context->ar] = value;
73 if (context->ifctrl & BIT_SOUTEN) { 83 if (context->ifctrl & BIT_SOUTEN) {
98 context->dac |= value << 8; 108 context->dac |= value << 8;
99 break; 109 break;
100 case DTTRG: 110 case DTTRG:
101 if (value & BIT_DOUTEN) { 111 if (value & BIT_DOUTEN) {
102 context->regs[IFSTAT] &= ~BIT_DTBSY; 112 context->regs[IFSTAT] &= ~BIT_DTBSY;
113 uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8);
114 context->transfer_end = context->cycle + transfer_size * context->clock_step;
103 } 115 }
104 break; 116 break;
105 case DTACK: 117 case DTACK:
106 context->regs[IFSTAT] |= BIT_DTEI; 118 context->regs[IFSTAT] |= BIT_DTEI;
107 break; 119 break;
109 context->regs[WAL] = value; 121 context->regs[WAL] = value;
110 break; 122 break;
111 case WAH_WRITE: 123 case WAH_WRITE:
112 context->regs[WAH] = value; 124 context->regs[WAH] = value;
113 break; 125 break;
126 case CTRL0:
127 context->ctrl0 = value;
128 break;
129 case CTRL1:
130 context->ctrl1 = value;
131 break;
114 case PTL_WRITE: 132 case PTL_WRITE:
115 context->regs[PTL] = value; 133 context->regs[PTL] = value;
116 break; 134 break;
117 case PTH_WRITE: 135 case PTH_WRITE:
118 context->regs[PTH] = value; 136 context->regs[PTH] = value;
137 context->ptl_internal = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer) - 1);
138 context->decoding = 1;
139 context->decode_end = context->cycle + 2352 * context->clock_step * 4;
119 break; 140 break;
120 case RESET: 141 case RESET:
121 context->comin_count = 0; 142 context->comin_count = 0;
122 context->regs[IFSTAT] = 0xFF; 143 context->regs[IFSTAT] = 0xFF;
123 break; 144 break;
150 if (context->ar >= sizeof(context->regs)) { 171 if (context->ar >= sizeof(context->regs)) {
151 value = 0xFF; 172 value = 0xFF;
152 } else { 173 } else {
153 value = context->regs[context->ar]; 174 value = context->regs[context->ar];
154 } 175 }
176 printf("CDC read %X: %X\n", context->ar, value);
155 context->ar++; 177 context->ar++;
156 context->ar &= context->ar_mask; 178 context->ar &= context->ar_mask;
157 return value; 179 return value;
158 } 180 }
159 181
160 void lc8951_ar_write(lc8951 *context, uint8_t value) 182 void lc8951_ar_write(lc8951 *context, uint8_t value)
161 { 183 {
162 context->ar = value & context->ar_mask; 184 context->ar = value & context->ar_mask;
163 } 185 }
186
187 //25 MHz clock input (1/2 SCD MCLK)
188 //internal /2 divider
189 //3 cycles for each SRAM access (though might be crystal frequency rather than internal frequency)
190 //6 cycle period for DMA transfer out
191 //
192
193 void lc8951_run(lc8951 *context, uint32_t cycle)
194 {
195 for(; context->cycle < cycle; context->cycle += context->clock_step)
196 {
197 if (context->cycle >= context->decode_end) {
198 context->decode_end = CYCLE_NEVER;
199 context->regs[IFSTAT] &= ~BIT_DECI;
200 context->regs[STAT3] &= ~BIT_VALST;
201 uint16_t block_start = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer)-1);
202 for (int reg = HEAD0; reg < PTL; reg++)
203 {
204 printf("Setting HEAD%d to buffer[%X]\n", reg - HEAD0, block_start);
205 context->regs[reg] =context->buffer[block_start++];
206 block_start &= (sizeof(context->buffer)-1);
207 }
208 printf("Decode done %X:%X:%X mode %X\n", context->regs[HEAD0], context->regs[HEAD1], context->regs[HEAD2], context->regs[HEAD3]);
209 }
210 if (context->transfer_end != CYCLE_NEVER) {
211 //TODO: transfer byte to gate array destination
212 context->dac++;
213 context->regs[DBCL]--;
214 if (!context->regs[DBCL]) {
215 context->regs[DBCH]--;
216 if (!context->regs[DBCH]) {
217 context->regs[IFSTAT] &= ~BIT_DTEI;
218 if (context->cycle != context->transfer_end) {
219 printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle);
220 }
221 context->transfer_end = CYCLE_NEVER;
222 }
223 }
224 }
225 }
226 }
227
228 void lc8951_write_byte(lc8951 *context, uint32_t cycle, int sector_offset, uint8_t byte)
229 {
230 lc8951_run(context, cycle);
231 uint16_t current_write_addr = context->regs[WAL] | (context->regs[WAH] << 8);
232 if (sector_offset == 12) {
233 //we've recevied the sync pattern for the next block
234
235 //header/status regs no longer considered "valid"
236 context->regs[STAT3] |= BIT_VALST;
237 if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN|BIT_WRRQ)) {
238 uint16_t block_start = current_write_addr - 2352;
239 context->regs[PTL] = block_start;
240 context->regs[PTH] = block_start >> 8;
241 printf("Decoding block starting at %X\n", block_start);
242 context->ptl_internal = block_start & (sizeof(context->buffer)-1);
243 context->decode_end = context->cycle + 2352 * context->clock_step * 4;
244 }
245 }
246 if (sector_offset >= 12 && sector_offset < 16) {
247 //TODO: Handle SHDREN = 1
248 if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN)) {
249 //monitor only mode
250 context->regs[HEAD0 + sector_offset - 12] = byte;
251 }
252 }
253 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;
256 context->regs[WAL]++;
257 if (!context->regs[WAL]) {
258 context->regs[WAH]++;
259 }
260 }
261 }
262
263 uint32_t lc8951_next_interrupt(lc8951 *context)
264 {
265 if ((!context->regs[IFSTAT]) & context->ifctrl & (BIT_CMDI|BIT_DTEI|BIT_DECI)) {
266 //interrupt already pending
267 return context->cycle;
268 }
269 uint32_t deci_cycle = CYCLE_NEVER;
270 if (context->ifctrl & BIT_DECI) {
271 deci_cycle = context->decode_end;
272 }
273 uint32_t dtei_cycle = CYCLE_NEVER;
274 if (context->ifctrl & BIT_DTEI) {
275 dtei_cycle = context->transfer_end;
276 }
277 return deci_cycle < dtei_cycle ? deci_cycle : dtei_cycle;
278 }