comparison cdd_mcu.c @ 2064:91e4d2fe5cd9 segacd

Get CDD working well enough to get into BIOS CD player
author Michael Pavone <pavone@retrodev.com>
date Fri, 28 Jan 2022 22:48:06 -0800
parents 07ed42bd7b4c
children 02a9846668d1
comparison
equal deleted inserted replaced
2063:d59ace2d7a6a 2064:91e4d2fe5cd9
71 context->head_pba += SEEK_SPEED; 71 context->head_pba += SEEK_SPEED;
72 if (context->head_pba > context->seek_pba) { 72 if (context->head_pba > context->seek_pba) {
73 context->head_pba = context->seek_pba; 73 context->head_pba = context->seek_pba;
74 } 74 }
75 } else { 75 } else {
76 context->head_pba -= SEEK_SPEED; 76 if (context->head_pba >= SEEK_SPEED) {
77 context->head_pba -= SEEK_SPEED;
78 } else {
79 context->head_pba = 0;
80 }
77 if (context->head_pba < context->seek_pba) { 81 if (context->head_pba < context->seek_pba) {
78 context->head_pba = context->seek_pba; 82 context->head_pba = context->seek_pba;
79 } 83 }
80 } 84 }
81 } 85 }
143 } 147 }
144 } 148 }
145 break; 149 break;
146 150
147 } 151 }
148 switch (context->requested_format) 152 if (context->first_cmd_received) {
149 { 153 switch (context->requested_format)
150 case SF_ABSOLUTE: 154 {
151 if (context->toc_valid) { 155 case SF_ABSOLUTE:
152 lba_to_status(context, context->head_pba - LEADIN_SECTORS); 156 if (context->toc_valid) {
153 context->status_buffer.format = SF_ABSOLUTE; 157 lba_to_status(context, context->head_pba - LEADIN_SECTORS);
158 context->status_buffer.format = SF_ABSOLUTE;
159 } else {
160 context->status_buffer.format = SF_NOTREADY;
161 }
162 break;
163 case SF_RELATIVE:
164 if (context->toc_valid) {
165 uint32_t lba =context->head_pba - LEADIN_SECTORS;
166 for (uint32_t i = 0; i < context->media->num_tracks; i++)
167 {
168 if (lba < context->media->tracks[i].end_lba) {
169 if (context->media->tracks[i].fake_pregap) {
170 if (lba > context->media->tracks[i].fake_pregap) {
171 lba -= context->media->tracks[i].fake_pregap;
172 } else {
173 //relative time counts down to 0 in pregap
174 lba = context->media->tracks[i].fake_pregap - lba;
175 break;
176 }
177 }
178 if (lba < context->media->tracks[i].start_lba) {
179 //relative time counts down to 0 in pregap
180 lba = context->media->tracks[i].start_lba - lba;
181 } else {
182 lba -= context->media->tracks[i].start_lba;
183 }
184 break;
185 } else if (context->media->tracks[i].fake_pregap) {
186 lba -= context->media->tracks[i].fake_pregap;
187 }
188 }
189 lba_to_status(context, lba);
190 context->status_buffer.format = SF_ABSOLUTE;
191 } else {
192 context->status_buffer.format = SF_NOTREADY;
193 }
194 break;
195 case SF_TOCO:
196 if (context->toc_valid) {
197 uint32_t total_fake_pregap = 0;
198 for (uint32_t i = 0; i < context->media->num_tracks; i++)
199 {
200 total_fake_pregap += context->media->tracks[i].fake_pregap;
201 }
202 lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + total_fake_pregap);
203 context->status_buffer.format = SF_TOCO;
204 } else {
205 context->status_buffer.format = SF_NOTREADY;
206 }
207 break;
208 case SF_TOCT:
209 if (context->toc_valid) {
210 context->status_buffer.b.toct.first_track_high = 0;
211 context->status_buffer.b.toct.first_track_low = 1;
212 context->status_buffer.b.toct.last_track_high = (context->media->num_tracks + 1) / 10;
213 context->status_buffer.b.toct.last_track_low = (context->media->num_tracks + 1) % 10;
214 context->status_buffer.b.toct.version = 0;
215 context->status_buffer.format = SF_TOCT;
216 } else {
217 context->status_buffer.format = SF_NOTREADY;
218 }
219 break;
220 case SF_TOCN:
221 if (context->toc_valid) {
222 uint32_t lba = context->media->tracks[context->requested_track - 1].start_lba;
223 if (context->requested_track > 1) {
224 lba += context->media->tracks[1].fake_pregap;
225 }
226 lba_to_status(context, lba);
227 context->status_buffer.b.tocn.track_low = context->requested_track % 10;
228 context->status_buffer.format = SF_TOCN;
229 } else {
230 context->status_buffer.format = SF_NOTREADY;
231 }
232 break;
233 case SF_NOTREADY:
234 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1);
235 context->status_buffer.format = SF_NOTREADY;
236 break;
237 }
238 if (context->error_status == DS_STOP) {
239 if (context->requested_format >= SF_TOCO && context->requested_format <= SF_TOCN) {
240 context->status_buffer.status = DS_TOC_READ;
241 } else {
242 context->status_buffer.status = context->status;
243 }
154 } else { 244 } else {
245 context->status_buffer.status = context->error_status;
155 context->status_buffer.format = SF_NOTREADY; 246 context->status_buffer.format = SF_NOTREADY;
156 } 247 context->error_status = DS_STOP;
157 break; 248 }
158 case SF_RELATIVE: 249 if (context->requested_format != SF_TOCN) {
159 if (context->toc_valid) { 250 context->status_buffer.b.time.flags = 1; //TODO: populate these
160 uint32_t lba =context->head_pba - LEADIN_SECTORS; 251 }
161 for (uint32_t i = 0; i < context->media->num_tracks; i++) 252 } else {
162 { 253 // Did not receive our first command so just send zeroes
163 if (lba < context->media->tracks[i].end_lba) {
164 if (context->media->tracks[i].fake_pregap) {
165 if (lba > context->media->tracks[i].fake_pregap) {
166 lba -= context->media->tracks[i].fake_pregap;
167 } else {
168 //relative time counts down to 0 in pregap
169 lba = context->media->tracks[i].fake_pregap - lba;
170 break;
171 }
172 }
173 if (lba < context->media->tracks[i].start_lba) {
174 //relative time counts down to 0 in pregap
175 lba = context->media->tracks[i].start_lba - lba;
176 } else {
177 lba -= context->media->tracks[i].start_lba;
178 }
179 break;
180 } else if (context->media->tracks[i].fake_pregap) {
181 lba -= context->media->tracks[i].fake_pregap;
182 }
183 }
184 lba_to_status(context, lba);
185 context->status_buffer.format = SF_ABSOLUTE;
186 } else {
187 context->status_buffer.format = SF_NOTREADY;
188 }
189 break;
190 case SF_TOCO:
191 if (context->toc_valid) {
192 lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + (context->media->num_tracks > 1 ? context->media->tracks[1].fake_pregap : 0));
193 context->status_buffer.format = SF_TOCO;
194 } else {
195 context->status_buffer.format = SF_NOTREADY;
196 }
197 break;
198 case SF_TOCT:
199 if (context->toc_valid) {
200 context->status_buffer.b.toct.first_track_high = 0;
201 context->status_buffer.b.toct.first_track_low = 1;
202 context->status_buffer.b.toct.last_track_high = (context->media->num_tracks + 1) / 10;
203 context->status_buffer.b.toct.last_track_low = (context->media->num_tracks + 1) % 10;
204 context->status_buffer.b.toct.version = 0;
205 context->status_buffer.format = SF_TOCT;
206 } else {
207 context->status_buffer.format = SF_NOTREADY;
208 }
209 break;
210 case SF_TOCN:
211 if (context->toc_valid) {
212 uint32_t lba = context->media->tracks[context->requested_track - 1].start_lba;
213 if (context->requested_track > 1) {
214 lba += context->media->tracks[1].fake_pregap;
215 }
216 lba_to_status(context, lba);
217 context->status_buffer.b.tocn.track_low = context->requested_track % 10;
218 context->status_buffer.format = SF_TOCN;
219 } else {
220 context->status_buffer.format = SF_NOTREADY;
221 }
222 break;
223 case SF_NOTREADY:
224 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1); 254 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1);
225 context->status_buffer.format = SF_NOTREADY;
226 break;
227 }
228 if (context->error_status == DS_STOP) {
229 context->status_buffer.status = context->status;
230 } else {
231 context->status_buffer.status = context->error_status;
232 context->error_status = DS_STOP;
233 }
234 if (context->requested_format != SF_TOCN) {
235 context->status_buffer.b.time.flags = 0; //TODO: populate these
236 } 255 }
237 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer); 256 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer);
238 if (context->status_buffer.format != SF_NOTREADY) { 257 if (context->status_buffer.format != SF_NOTREADY) {
239 printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n", 258 printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n",
240 context->status_buffer.status, context->status_buffer.format, 259 context->status_buffer.status, context->status_buffer.format,
247 } 266 }
248 267
249 static void run_command(cdd_mcu *context) 268 static void run_command(cdd_mcu *context)
250 { 269 {
251 uint8_t check = checksum((uint8_t*)&context->cmd_buffer); 270 uint8_t check = checksum((uint8_t*)&context->cmd_buffer);
271 printf("cmd %X, checksum: %X, calc: %X\n", context->cmd_buffer.cmd_type, context->cmd_buffer.checksum, check);
252 if (check != context->cmd_buffer.checksum) { 272 if (check != context->cmd_buffer.checksum) {
253 context->error_status = DS_SUM_ERROR; 273 context->error_status = DS_SUM_ERROR;
254 return; 274 return;
255 } 275 }
256 if (context->cmd_buffer.must_be_zero) { 276 if (context->cmd_buffer.must_be_zero) {
257 context->error_status = DS_CMD_ERROR; 277 context->error_status = DS_CMD_ERROR;
258 return; 278 return;
259 } 279 }
280 context->first_cmd_received = 1;
260 switch (context->cmd_buffer.cmd_type) 281 switch (context->cmd_buffer.cmd_type)
261 { 282 {
262 case CMD_NOP: 283 case CMD_NOP:
263 break; 284 break;
264 case CMD_STOP: 285 case CMD_STOP:
265 puts("CDD CMD: STOP"); 286 puts("CDD CMD: STOP");
266 context->status = DS_STOP; 287 context->status = DS_STOP;
288 context->requested_format = SF_ABSOLUTE;
267 break; 289 break;
268 case CMD_READ: 290 case CMD_READ:
269 case CMD_SEEK: { 291 case CMD_SEEK: {
270 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { 292 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) {
271 context->error_status = DS_CMD_ERROR; 293 context->error_status = DS_CMD_ERROR;
351 { 373 {
352 uint32_t cd_cycle = mclks_to_cd_block(cycle); 374 uint32_t cd_cycle = mclks_to_cd_block(cycle);
353 if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) { 375 if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) {
354 //it's a little unclear if this gates the actual cd block clock or just handshaking 376 //it's a little unclear if this gates the actual cd block clock or just handshaking
355 //assum it's actually the clock for now 377 //assum it's actually the clock for now
356 context->cycle = cycle; 378 context->cycle = cd_cycle;
357 return; 379 return;
358 } 380 }
359 uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS; 381 uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS;
360 uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; 382 uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER;
361 uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; 383 uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER;