]> Shamusworld >> Repos - virtualjaguar/blob - src/cdrom.cpp
Removed some cruft and nonstandard int/uint types, added M series BIOS.
[virtualjaguar] / src / cdrom.cpp
1 //
2 // CD handler
3 //
4 // Originally by David Raingeard
5 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
6 // Extensive rewrites/cleanups/fixes by James Hammons
7 // (C) 2010 Underground Software
8 //
9 // JLH = James Hammons <jlhamm@acm.org>
10 //
11 // Who  When        What
12 // ---  ----------  -------------------------------------------------------------
13 // JLH  01/16/2010  Created this log ;-)
14 //
15
16 #include "cdrom.h"
17
18 #include <string.h>                                                                     // For memset, etc.
19 //#include "jaguar.h"                                                                   // For GET32/SET32 macros
20 //#include "m68k.h"     //???
21 //#include "memory.h"
22 #include "cdintf.h"                                                                     // System agnostic CD interface functions
23 #include "log.h"
24 #include "dac.h"
25
26 //#define CDROM_LOG                                                                     // For CDROM logging, obviously
27
28 /*
29 BUTCH     equ  $DFFF00          ; base of Butch=interrupt control register, R/W
30 DSCNTRL   equ  BUTCH+4          ; DSA control register, R/W
31 DS_DATA   equ  BUTCH+$A         ; DSA TX/RX data, R/W
32 I2CNTRL   equ  BUTCH+$10        ; i2s bus control register, R/W
33 SBCNTRL   equ  BUTCH+$14        ; CD subcode control register, R/W
34 SUBDATA   equ  BUTCH+$18        ; Subcode data register A
35 SUBDATB   equ  BUTCH+$1C        ; Subcode data register B
36 SB_TIME   equ  BUTCH+$20        ; Subcode time and compare enable (D24)
37 FIFO_DATA equ  BUTCH+$24        ; i2s FIFO data
38 I2SDAT1   equ  BUTCH+$24        ; i2s FIFO data
39 I2SDAT2   equ  BUTCH+$28        ; i2s FIFO data
40 2C = ?
41
42 ;
43 ; Butch's hardware registers
44 ;
45 ;BUTCH     equ  $DFFF00         ;base of Butch=interrupt control register, R/W
46 ;
47 ;  When written (Long):
48 ;
49 ;  bit0 - set to enable interrupts
50 ;  bit1 - enable CD data FIFO half full interrupt
51 ;  bit2 - enable CD subcode frame-time interrupt (@ 2x spped = 7ms.)
52 ;  bit3 - enable pre-set subcode time-match found interrupt
53 ;  bit4 - CD module command transmit buffer empty interrupt
54 ;  bit5 - CD module command receive buffer full
55 ;  bit6 - CIRC failure interrupt
56 ;
57 ;  bit7-31  reserved, set to 0
58 ;
59 ;  When read (Long):
60 ;
61 ;  bit0-8 reserved
62 ;
63 ;  bit9  - CD data FIFO half-full flag pending
64 ;  bit10 - Frame pending
65 ;  bit11 - Subcode data pending
66 ;  bit12 - Command to CD drive pending (trans buffer empty if 1)
67 ;  bit13 - Response from CD drive pending (rec buffer full if 1)
68 ;  bit14 - CD uncorrectable data error pending
69 ;
70 ;   Offsets from BUTCH
71 ;
72 O_DSCNTRL   equ  4              ; DSA control register, R/W
73 O_DS_DATA   equ  $A             ; DSA TX/RX data, R/W
74 ;
75 O_I2CNTRL   equ  $10            ; i2s bus control register, R/W
76 ;
77 ;  When read:
78 ;
79 ;  b0 - I2S data from drive is ON if 1
80 ;  b1 - I2S path to Jerry is ON if 1
81 ;  b2 - reserved
82 ;  b3 - host bus width is 16 if 1, else 32
83 ;  b4 - FIFO state is not empty if 1
84 ;
85 O_SBCNTRL   equ  $14            ; CD subcode control register, R/W
86 O_SUBDATA   equ  $18            ; Subcode data register A
87 O_SUBDATB   equ  $1C            ; Subcode data register B
88 O_SB_TIME   equ  $20            ; Subcode time and compare enable (D24)
89 O_FIFODAT   equ  $24            ; i2s FIFO data
90 O_I2SDAT2   equ  $28            ; i2s FIFO data (old)
91 */
92
93 /*
94 Commands sent through DS_DATA:
95
96 $01nn - ? Play track nn ? Seek to track nn ?
97 $0200 - Stop CD
98 $03nn - Read session nn TOC (short)
99 $0400 - Pause CD
100 $0500 - Unpause CD
101 $10nn - Goto (min?)
102 $11nn - Goto (sec?)
103 $12nn - Goto (frm?)
104 $14nn - Read session nn TOC (full)
105 $15nn - Set CD mode
106 $18nn - Spin up CD to session nn
107 $5000 - ?
108 $5100 - Mute CD (audio mode only)
109 $51FF - Unmute CD (audio mode only)
110 $5400 - Read # of sessions on CD
111 $70nn - Set oversampling mode
112
113 Commands send through serial bus:
114
115 $100 - ? Acknowledge ?
116 $130 - ? (Seems to always prefix the $14n commands)
117 $140 - Returns ACK (1) (Write to NVRAM?)
118 $141 - Returns ACK (1)
119 $142 - Returns ACK (1)
120 $143 - Returns ACK (1)
121 $144 - Returns ACK (1)
122 $145 - Returns ACK (1)
123 $180 - Returns 16-bit value (NVRAM?)
124 $181 - Returns 16-bit value
125 $182 - Returns 16-bit value
126 $183 - Returns 16-bit value
127 $184 - Returns 16-bit value
128 $185 - Returns 16-bit value
129 */
130
131 // Private function prototypes
132
133 static void CDROMBusWrite(uint16_t);
134 static uint16_t CDROMBusRead(void);
135
136 #define BUTCH           0x00                            // base of Butch == interrupt control register, R/W
137 #define DSCNTRL         BUTCH + 0x04            // DSA control register, R/W
138 #define DS_DATA         BUTCH + 0x0A            // DSA TX/RX data, R/W
139 #define I2CNTRL         BUTCH + 0x10            // i2s bus control register, R/W
140 #define SBCNTRL         BUTCH + 0x14            // CD subcode control register, R/W
141 #define SUBDATA         BUTCH + 0x18            // Subcode data register A
142 #define SUBDATB         BUTCH + 0x1C            // Subcode data register B
143 #define SB_TIME         BUTCH + 0x20            // Subcode time and compare enable (D24)
144 #define FIFO_DATA       BUTCH + 0x24            // i2s FIFO data
145 #define I2SDAT2         BUTCH + 0x28            // i2s FIFO data (old)
146 #define UNKNOWN         BUTCH + 0x2C            // Seems to be some sort of I2S interface
147
148 const char * BReg[12] = { "BUTCH", "DSCNTRL", "DS_DATA", "???", "I2CNTRL", "SBCNTRL", "SUBDATA", "SUBDATB",
149         "SB_TIME", "FIFO_DATA", "I2SDAT2", "UNKNOWN" };
150 //extern const char * whoName[9];
151
152
153 static uint8_t cdRam[0x100];
154 static uint16_t cdCmd = 0, cdPtr = 0;
155 static bool haveCDGoodness;
156 static uint32_t min, sec, frm, block;
157 static uint8_t cdBuf[2352 + 96];
158 static uint32_t cdBufPtr = 2352;
159 //Also need to set up (save/restore) the CD's NVRAM
160
161
162 //extern bool GetRawTOC(void);
163 void CDROMInit(void)
164 {
165         haveCDGoodness = CDIntfInit();
166
167 //GetRawTOC();
168 /*uint8_t buf[2448];
169 uint32_t sec = 18667 - 150;
170 memset(buf, 0, 2448);
171 if (!CDIntfReadBlock(sec, buf))
172 {
173         WriteLog("CDROM: Attempt to read with subchannel data failed!\n");
174         return;
175 }
176
177 //24x98+96
178 //96=4x24=4x4x6
179 WriteLog("\nCDROM: Read sector %u...\n\n", sec);
180 for(int i=0; i<98; i++)
181 {
182         WriteLog("%04X: ", i*24);
183         for(int j=0; j<24; j++)
184         {
185                 WriteLog("%02X ", buf[j + (i*24)]);
186         }
187         WriteLog("\n");
188 }
189 WriteLog("\nRaw P-W subchannel data:\n\n");
190 for(int i=0; i<6; i++)
191 {
192         WriteLog("%02X: ", i*16);
193         for(int j=0; j<16; j++)
194         {
195                 WriteLog("%02X ", buf[2352 + j + (i*16)]);
196         }
197         WriteLog("\n");
198 }
199 WriteLog("\nP subchannel data: ");
200 for(int i=0; i<96; i+=8)
201 {
202         uint8_t b = 0;
203         for(int j=0; j<8; j++)
204                 b |= ((buf[2352 + i + j] & 0x80) >> 7) << (7 - j);
205
206         WriteLog("%02X ", b);
207 }
208 WriteLog("\nQ subchannel data: ");
209 for(int i=0; i<96; i+=8)
210 {
211         uint8_t b = 0;
212         for(int j=0; j<8; j++)
213                 b |= ((buf[2352 + i + j] & 0x40) >> 6) << (7 - j);
214
215         WriteLog("%02X ", b);
216 }
217 WriteLog("\n\n");//*/
218 }
219
220 void CDROMReset(void)
221 {
222         memset(cdRam, 0x00, 0x100);
223         cdCmd = 0;
224 }
225
226 void CDROMDone(void)
227 {
228         CDIntfDone();
229 }
230
231
232 //
233 // This approach is probably wrong, but let's do it for now.
234 // What's needed is a complete overhaul of the interrupt system so that
235 // interrupts are handled as they're generated--instead of the current
236 // scheme where they're handled on scanline boundaries.
237 //
238 void BUTCHExec(uint32_t cycles)
239 {
240 #if 1
241 // We're chickening out for now...
242 return;
243 #else
244 //      extern uint8_t * jerry_ram_8;                                   // Hmm.
245
246         // For now, we just do the FIFO interrupt. Timing is also likely to be WRONG as well.
247         uint32_t cdState = GET32(cdRam, BUTCH);
248
249         if (!(cdState & 0x01))                                          // No BUTCH interrupts enabled
250                 return;
251
252         if (!(cdState & 0x22))
253                 return;                                                                 // For now, we only handle FIFO/buffer full interrupts...
254
255         // From what I can make out, it seems that each FIFO is 32 bytes long
256
257 //      DSPSetIRQLine(DSPIRQ_EXT, ASSERT_LINE);
258 //I'm *sure* this is wrong--prolly need to generate DSP IRQs as well!
259         if (jerry_ram_8[0x23] & 0x3F)                           // Only generate an IRQ if enabled!
260                 GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
261 #endif
262 }
263
264
265 //
266 // CD-ROM memory access functions
267 //
268
269 uint8_t CDROMReadByte(uint32_t offset, uint32_t who/*=UNKNOWN*/)
270 {
271 #ifdef CDROM_LOG
272         if ((offset & 0xFF) < 12 * 4)
273                 WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]);
274         WriteLog("CDROM: %s reading byte $%02X from $%08X [68K PC=$%08X]\n", whoName[who], offset, cdRam[offset & 0xFF], m68k_get_reg(NULL, M68K_REG_PC));
275 #endif
276         return cdRam[offset & 0xFF];
277 }
278
279 static uint8_t trackNum = 1, minTrack, maxTrack;
280 //static uint8_t minutes[16] = {  0,  0,  2,  5,  7, 10, 12, 15, 17, 20, 22, 25, 27, 30, 32, 35 };
281 //static uint8_t seconds[16] = {  0,  0, 30,  0, 30,  0, 30,  0, 30,  0, 30,  0, 30,  0, 30,  0 };
282 //static uint8_t frames[16]  = {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 };
283 //static uint16_t sd = 0;
284 uint16_t CDROMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
285 {
286         offset &= 0xFF;
287
288         uint16_t data = 0x0000;
289
290         if (offset == BUTCH)
291                 data = 0x0000;
292         else if (offset == BUTCH + 2)
293 // We need to fix this so it's not as brain-dead as it is now--i.e., make it so that when
294 // a command is sent to the CDROM, we control here whether or not it succeeded or whether
295 // the command is still being carried out, etc.
296
297 // bit12 - Command to CD drive pending (trans buffer empty if 1)
298 // bit13 - Response from CD drive pending (rec buffer full if 1)
299 //              data = (haveCDGoodness ? 0x3000 : 0x0000);      // DSA RX Interrupt pending bit (0 = pending)
300 //This only returns ACKs for interrupts that are set:
301 //This doesn't work for the initial code that writes $180000 to BUTCH. !!! FIX !!!
302                 data = (haveCDGoodness ? cdRam[BUTCH + 3] << 8 : 0x0000);
303 //      else if (offset == SUBDATA + 2)
304 //              data = sd++ | 0x0010;                                           // Have no idea what this is...
305         else if (offset == DS_DATA && haveCDGoodness)
306         {
307                 if ((cdCmd & 0xFF00) == 0x0100)                         // ???
308                 {
309 //Not sure how to acknowledge the ???...
310 //                      data = 0x0400;//?? 0x0200;
311                         cdPtr++;
312                         switch (cdPtr)
313                         {
314                         case 1:
315                                 data = 0x0000;
316                                 break;
317                         case 2:
318                                 data = 0x0100;
319                                 break;
320                         case 3:
321                                 data = 0x0200;
322                                 break;
323                         case 4:
324                                 data = 0x0300;
325                                 break;
326                         case 5:
327                                 data = 0x0400;
328                         }//*/
329                         WriteLog("CDROM: Reading DS_DATA (???), cdCmd=$%04X\n", cdCmd);
330                 }
331                 else if ((cdCmd & 0xFF00) == 0x0200)                    // Stop CD
332                 {
333 //Not sure how to acknowledge the stop...
334                         data = 0x0400;//?? 0x0200;
335 /*                      cdPtr++;
336                         switch (cdPtr)
337                         {
338                         case 1:
339                                 data = 0x00FF;
340                                 break;
341                         case 2:
342                                 data = 0x01FF;
343                                 break;
344                         case 3:
345                                 data = 0x02FF;
346                                 break;
347                         case 4:
348                                 data = 0x03FF;
349                                 break;
350                         case 5:
351                                 data = 0x0400;
352                         }//*/
353                         WriteLog("CDROM: Reading DS_DATA (stop), cdCmd=$%04X\n", cdCmd);
354                 }
355                 else if ((cdCmd & 0xFF00) == 0x0300)            // Read session TOC (overview?)
356                 {
357
358 /*
359 TOC: [Sess] [adrCtl] [?] [point] [?] [?] [?] [?] [pmin] [psec] [pframe]
360 TOC: 1 10 00 a0 00:00:00 00 01:00:00
361 TOC: 1 10 00 a1 00:00:00 00 01:00:00
362 TOC: 1 10 00 a2 00:00:00 00 03:42:42
363 TOC: 1 10 00  1 00:00:00 00 00:02:00   <-- Track #1
364 TOC: 1 50 00 b0 06:12:42 02 79:59:74
365 TOC: 1 50 00 c0 128:00:32 00 97:18:06
366 TOC: 2 10 00 a0 00:00:00 00 02:00:00
367 TOC: 2 10 00 a1 00:00:00 00 11:00:00
368 TOC: 2 10 00 a2 00:00:00 00 54:32:18
369 TOC: 2 10 00  2 00:00:00 00 06:14:42   <-- Track #2
370 TOC: 2 10 00  3 00:00:00 00 06:24:42   <-- Track #3
371 TOC: 2 10 00  4 00:00:00 00 17:42:00   <-- Track #4
372 TOC: 2 10 00  5 00:00:00 00 22:26:15   <-- Track #5
373 TOC: 2 10 00  6 00:00:00 00 29:50:16   <-- Track #6
374 TOC: 2 10 00  7 00:00:00 00 36:01:49   <-- Track #7
375 TOC: 2 10 00  8 00:00:00 00 40:37:59   <-- Track #8
376 TOC: 2 10 00  9 00:00:00 00 45:13:70   <-- Track #9
377 TOC: 2 10 00  a 00:00:00 00 49:50:06   <-- Track #10
378 TOC: 2 10 00  b 00:00:00 00 54:26:17   <-- Track #11
379 */
380
381 //Should do something like so:
382 //                      data = GetSessionInfo(cdCmd & 0xFF, cdPtr);
383                         data = CDIntfGetSessionInfo(cdCmd & 0xFF, cdPtr);
384                         if (data == 0xFF)       // Failed...
385                         {
386                                 data = 0x0400;
387                                 WriteLog("CDROM: Requested invalid session #%u (or failed to load TOC, or bad cdPtr value)\n", cdCmd & 0xFF);
388                         }
389                         else
390                         {
391                                 data |= (0x20 | cdPtr++) << 8;
392                                 WriteLog("CDROM: Reading DS_DATA (session #%u TOC byte #%u): $%04X\n", cdCmd & 0xFF, cdPtr, data);
393                         }
394
395 /*                      bool isValidSession = ((cdCmd & 0xFF) == 0 ? true : false);//Hardcoded... !!! FIX !!!
396 //NOTE: This should return error condition if the requested session doesn't exist! ($0400?)
397                         if (isValidSession)
398                         {
399                                 cdPtr++;
400                                 switch (cdPtr)
401                                 {
402                                 case 1:
403                                         data = 0x2001;  // Min track for this session?
404                                         break;
405                                 case 2:
406                                         data = 0x210A;  // Max track for this session?
407                                         break;
408                                 case 3:
409                                         data = 0x2219;  // Max lead-out time, absolute minutes
410                                         break;
411                                 case 4:
412                                         data = 0x2319;  // Max lead-out time, absolute seconds
413                                         break;
414                                 case 5:
415                                         data = 0x2419;  // Max lead-out time, absolute frames
416                                         break;
417                                 default:
418                                         data = 0xFFFF;
419
420 //;    +0 - unused, reserved (0)
421 //;    +1 - unused, reserved (0)
422 //;    +2 - minimum track number
423 //;    +3 - maximum track number
424 //;    +4 - total number of sessions
425 //;    +5 - start of last lead-out time, absolute minutes
426 //;    +6 - start of last lead-out time, absolute seconds
427 //;    +7 - start of last lead-out time, absolute frames
428
429                                 }
430                                 WriteLog("CDROM: Reading DS_DATA (session #%u TOC byte #%u): $%04X\n", cdCmd & 0xFF, cdPtr, data);
431                         }
432                         else
433                         {
434                                 data = 0x0400;
435                                 WriteLog("CDROM: Requested invalid session #%u\n", cdCmd & 0xFF);
436                         }*/
437                 }
438                 // Seek to m, s, or f position
439                 else if ((cdCmd & 0xFF00) == 0x1000 || (cdCmd & 0xFF00) == 0x1100 || (cdCmd & 0xFF00) == 0x1200)
440                         data = 0x0100;  // Success, though this doesn't take error handling into account.
441                         // Ideally, we would also set the bits in BUTCH to let the processor know that
442                         // this is ready to be read... !!! FIX !!!
443                 else if ((cdCmd & 0xFF00) == 0x1400)            // Read "full" session TOC
444                 {
445 //Need to be a bit more tricky here, since it's reading the "session" TOC instead of the
446 //full TOC--so we need to check for the min/max tracks for each session here... [DONE]
447
448                         if (trackNum > maxTrack)
449                         {
450                                 data = 0x400;
451 WriteLog("CDROM: Requested invalid track #%u for session #%u\n", trackNum, cdCmd & 0xFF);
452                         }
453                         else
454                         {
455                                 if (cdPtr < 0x62)
456                                         data = (cdPtr << 8) | trackNum;
457                                 else if (cdPtr < 0x65)
458                                         data = (cdPtr << 8) | CDIntfGetTrackInfo(trackNum, (cdPtr - 2) & 0x0F);
459
460 WriteLog("CDROM: Reading DS_DATA (session #%u, full TOC byte #%u): $%04X\n", cdCmd & 0xFF, (cdPtr+1) & 0x0F, data);
461
462                                 cdPtr++;
463                                 if (cdPtr == 0x65)
464                                         cdPtr = 0x60, trackNum++;
465                         }
466
467                         // Note that it seems to return track info in sets of 4 (or is it 5?)
468 /*
469 ;    +0 - track # (must be non-zero)
470 ;    +1 - absolute minutes (0..99), start of track
471 ;    +2 - absolute seconds (0..59), start of track
472 ;    +3 - absolute frames, (0..74), start of track
473 ;    +4 - session # (0..99)
474 ;    +5 - track duration minutes
475 ;    +6 - track duration seconds
476 ;    +7 - track duration frames
477 */
478                         // Seems to be the following format: $60xx -> Track #xx
479                         //                                   $61xx -> min?   (trk?)
480                         //                                   $62xx -> sec?   (min?)
481                         //                                   $63xx -> frame? (sec?)
482                         //                                   $64xx -> ?      (frame?)
483 /*                      cdPtr++;
484                         switch (cdPtr)
485                         {
486                         case 1:
487                                 data = 0x6000 | trackNum;       // Track #
488                                 break;
489                         case 2:
490                                 data = 0x6100 | trackNum;       // Track # (again?)
491                                 break;
492                         case 3:
493                                 data = 0x6200 | minutes[trackNum];      // Minutes
494                                 break;
495                         case 4:
496                                 data = 0x6300 | seconds[trackNum];      // Seconds
497                                 break;
498                         case 5:
499                                 data = 0x6400 | frames[trackNum];               // Frames
500                                 trackNum++;
501                                 cdPtr = 0;
502                         }//*/
503                 }
504                 else if ((cdCmd & 0xFF00) == 0x1500)            // Read CD mode
505                 {
506                         data = cdCmd | 0x0200;  // ?? not sure ?? [Seems OK]
507                         WriteLog("CDROM: Reading DS_DATA (mode), cdCmd=$%04X\n", cdCmd);
508                 }
509                 else if ((cdCmd & 0xFF00) == 0x1800)            // Spin up session #
510                 {
511                         data = cdCmd;
512                         WriteLog("CDROM: Reading DS_DATA (spin up session), cdCmd=$%04X\n", cdCmd);
513                 }
514                 else if ((cdCmd & 0xFF00) == 0x5400)            // Read # of sessions
515                 {
516                         data = cdCmd | 0x00;    // !!! Hardcoded !!! FIX !!!
517                         WriteLog("CDROM: Reading DS_DATA (# of sessions), cdCmd=$%04X\n", cdCmd);
518                 }
519                 else if ((cdCmd & 0xFF00) == 0x7000)            // Read oversampling
520                 {
521 //NOTE: This setting will probably affect the # of DSP interrupts that need to happen. !!! FIX !!!
522                         data = cdCmd;
523                         WriteLog("CDROM: Reading DS_DATA (oversampling), cdCmd=$%04X\n", cdCmd);
524                 }
525                 else
526                 {
527                         data = 0x0400;
528                         WriteLog("CDROM: Reading DS_DATA, unhandled cdCmd=$%04X\n", cdCmd);
529                 }
530         }
531         else if (offset == DS_DATA && !haveCDGoodness)
532                 data = 0x0400;                                                          // No CD interface present, so return error
533         else if (offset >= FIFO_DATA && offset <= FIFO_DATA + 3)
534         {
535         }
536         else if (offset >= FIFO_DATA + 4 && offset <= FIFO_DATA + 7)
537         {
538         }
539         else
540                 data = GET16(cdRam, offset);
541
542 //Returning $00000008 seems to cause it to use the starfield. Dunno why.
543 // It looks like it's getting the CD_mode this way...
544 //Temp, for testing...
545 //Very interesting...! Seems to control sumthin' or other...
546 /*if (offset == 0x2C || offset == 0x2E)
547         data = 0xFFFF;//*/
548 /*if (offset == 0x2C)
549         data = 0x0000;
550 if (offset == 0x2E)
551         data = 0;//0x0008;//*/
552         if (offset == UNKNOWN + 2)
553                 data = CDROMBusRead();
554
555 #ifdef CDROM_LOG
556         if ((offset & 0xFF) < 11 * 4)
557                 WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]);
558         if (offset != UNKNOWN && offset != UNKNOWN + 2)
559                 WriteLog("CDROM: %s reading word $%04X from $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
560 #endif
561         return data;
562 }
563
564 void CDROMWriteByte(uint32_t offset, uint8_t data, uint32_t who/*=UNKNOWN*/)
565 {
566         offset &= 0xFF;
567         cdRam[offset] = data;
568
569 #ifdef CDROM_LOG
570         if ((offset & 0xFF) < 12 * 4)
571                 WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]);
572         WriteLog("CDROM: %s writing byte $%02X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
573 #endif
574 }
575
576 void CDROMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
577 {
578         offset &= 0xFF;
579         SET16(cdRam, offset, data);
580
581         // Command register
582 //Lesse what this does... Seems to work OK...!
583         if (offset == DS_DATA)
584         {
585                 cdCmd = data;
586                 if ((data & 0xFF00) == 0x0200)                          // Stop CD
587                 {
588                         cdPtr = 0;
589                         WriteLog("CDROM: Stopping CD\n", data & 0xFF);
590                 }
591                 else if ((data & 0xFF00) == 0x0300)                     // Read session TOC (short? overview?)
592                 {
593                         cdPtr = 0;
594                         WriteLog("CDROM: Reading TOC for session #%u\n", data & 0xFF);
595                 }
596 //Not sure how these three acknowledge...
597                 else if ((data & 0xFF00) == 0x1000)                     // Seek to minute position
598                 {
599                         min = data & 0x00FF;
600                 }
601                 else if ((data & 0xFF00) == 0x1100)                     // Seek to second position
602                 {
603                         sec = data & 0x00FF;
604                 }
605                 else if ((data & 0xFF00) == 0x1200)                     // Seek to frame position
606                 {
607                         frm = data & 0x00FF;
608                         block = (((min * 60) + sec) * 75) + frm;
609                         cdBufPtr = 2352;                                                // Ensure that SSI read will do so immediately
610                         WriteLog("CDROM: Seeking to %u:%02u:%02u [block #%u]\n", min, sec, frm, block);
611                 }
612                 else if ((data & 0xFF00) == 0x1400)                     // Read "full" TOC for session
613                 {
614                         cdPtr = 0x60,
615                         minTrack = CDIntfGetSessionInfo(data & 0xFF, 0),
616                         maxTrack = CDIntfGetSessionInfo(data & 0xFF, 1);
617                         trackNum = minTrack;
618                         WriteLog("CDROM: Reading \"full\" TOC for session #%u (min=%u, max=%u)\n", data & 0xFF, minTrack, maxTrack);
619                 }
620                 else if ((data & 0xFF00) == 0x1500)                     // Set CDROM mode
621                 {
622                         // Mode setting is as follows: bit 0 set -> single speed, bit 1 set -> double,
623                         // bit 3 set -> multisession CD, bit 3 unset -> audio CD
624                         WriteLog("CDROM: Setting mode $%02X\n", data & 0xFF);
625                 }
626                 else if ((data & 0xFF00) == 0x1800)                     // Spin up session #
627                 {
628                         WriteLog("CDROM: Spinning up session #%u\n", data & 0xFF);
629                 }
630                 else if ((data & 0xFF00) == 0x5400)                     // Read # of sessions
631                 {
632                         WriteLog("CDROM: Reading # of sessions\n", data & 0xFF);
633                 }
634                 else if ((data & 0xFF00) == 0x7000)                     // Set oversampling rate
635                 {
636                         // 1 = none, 2 = 2x, 3 = 4x, 4 = 8x
637                         uint32_t rates[5] = { 0, 1, 2, 4, 8 };
638                         WriteLog("CDROM: Setting oversample rate to %uX\n", rates[(data & 0xFF)]);
639                 }
640                 else
641                         WriteLog("CDROM: Unknown command $%04X\n", data);
642         }//*/
643
644         if (offset == UNKNOWN + 2)
645                 CDROMBusWrite(data);
646
647 #ifdef CDROM_LOG
648         if ((offset & 0xFF) < 11 * 4)
649                 WriteLog("[%s] ", BReg[(offset & 0xFF) / 4]);
650         if (offset != UNKNOWN && offset != UNKNOWN + 2)
651                 WriteLog("CDROM: %s writing word $%04X at $%08X [68K PC=$%08X]\n", whoName[who], data, offset, m68k_get_reg(NULL, M68K_REG_PC));
652 #endif
653 }
654
655 //
656 // State machine for sending/receiving data along a serial bus
657 //
658
659 enum ButchState { ST_INIT, ST_RISING, ST_FALLING };
660 static ButchState currentState = ST_INIT;
661 static uint16_t counter = 0;
662 static bool cmdTx = false;
663 static uint16_t busCmd;
664 static uint16_t rxData, txData;
665 static uint16_t rxDataBit;
666 static bool firstTime = false;
667
668 static void CDROMBusWrite(uint16_t data)
669 {
670 //This is kinda lame. What we should do is check for a 0->1 transition on either bits 0 or 1...
671 //!!! FIX !!!
672
673 #ifdef CDROM_LOG
674         if (data & 0xFFF0)
675                 WriteLog("CDROM: BusWrite write on unknown line: $%04X\n", data);
676 #endif
677
678         switch (currentState)
679         {
680         case ST_INIT:
681                 currentState = ST_RISING;
682                 break;
683         case ST_RISING:
684                 if (data & 0x0001)                                                      // Command coming
685                 {
686                         cmdTx = true;
687                         counter = 0;
688                         busCmd = 0;
689                 }
690                 else
691                 {
692                         if (cmdTx)
693                         {
694                                 busCmd <<= 1;                                           // Make room for next bit
695                                 busCmd |= (data & 0x04);                        // & put it in
696                                 counter++;
697
698                                 if (counter == 9)
699                                 {
700                                         busCmd >>= 2;                                   // Because we ORed bit 2, we need to shift right by 2
701                                         cmdTx = false;
702
703 //What it looks like:
704 //It seems that the $18x series reads from NVRAM while the
705 //$130, $14x, $100 series writes values to NVRAM...
706                                         if (busCmd == 0x180)
707                                                 rxData = 0x0024;//1234;
708                                         else if (busCmd == 0x181)
709                                                 rxData = 0x0004;//5678;
710                                         else if (busCmd == 0x182)
711                                                 rxData = 0x0071;//9ABC;
712                                         else if (busCmd == 0x183)
713                                                 rxData = 0xFF67;//DEF0;
714                                         else if (busCmd == 0x184)
715                                                 rxData = 0xFFFF;//892F;
716                                         else if (busCmd == 0x185)
717                                                 rxData = 0xFFFF;//8000;
718                                         else
719                                                 rxData = 0x0001;
720 //                                              rxData = 0x8349;//8000;//0F67;
721
722                                         counter = 0;
723                                         firstTime = true;
724                                         txData = 0;
725 #ifdef CDROM_LOG
726                                         WriteLog("CDROM: *** BusWrite got command $%04X\n", busCmd);
727 #endif
728                                 }
729                         }
730                         else
731                         {
732                                 txData = (txData << 1) | ((data & 0x04) >> 2);
733 //WriteLog("[%s]", data & 0x04 ? "1" : "0");
734
735                                 rxDataBit = (rxData & 0x8000) >> 12;
736                                 rxData <<= 1;
737                                 counter++;
738 #ifdef CDROM_LOG
739                                 if (counter == 16)
740                                         WriteLog("CDROM: *** BusWrite got extra command $%04X\n", txData);
741 #endif
742                         }
743                 }
744
745                 currentState = ST_FALLING;
746                 break;
747         case ST_FALLING:
748                 currentState = ST_INIT;
749                 break;
750         }
751 }
752
753 static uint16_t CDROMBusRead(void)
754 {
755 // It seems the counter == 0 simply waits for a single bit acknowledge-- !!! FIX !!!
756 // Or does it? Hmm. It still "pumps" 16 bits through above, so how is this special?
757 // Seems to be because it sits and looks at it as if it will change. Dunno!
758 #ifdef CDROM_LOG
759         if ((counter & 0x0F) == 0)
760         {
761                 if (counter == 0 && rxDataBit == 0)
762                 {
763                         if (firstTime)
764                         {
765                                 firstTime = false;
766                                 WriteLog("0...\n");
767                         }
768                 }
769                 else
770                         WriteLog("%s\n", rxDataBit ? "1" : "0");
771         }
772         else
773                 WriteLog("%s", rxDataBit ? "1" : "0");
774 #endif
775
776         return rxDataBit;
777 }
778
779 //
780 // This simulates a read from BUTCH over the SSI to JERRY. Uses real reading!
781 //
782 //temp, until I can fix my CD image... Argh!
783 static uint8_t cdBuf2[2532 + 96], cdBuf3[2532 + 96];
784 uint16_t GetWordFromButchSSI(uint32_t offset, uint32_t who/*= UNKNOWN*/)
785 {
786         bool go = ((offset & 0x0F) == 0x0A || (offset & 0x0F) == 0x0E ? true : false);
787
788         if (!go)
789                 return 0x000;
790
791 // The problem comes in here. Really, we should generate the IRQ once we've stuffed
792 // our values into the DAC L/RRXD ports...
793 // But then again, the whole IRQ system needs an overhaul in order to make it more
794 // cycle accurate WRT to the various CPUs. Right now, it's catch-as-catch-can, which
795 // means that IRQs get serviced on scanline boundaries instead of when they occur.
796         cdBufPtr += 2;
797
798         if (cdBufPtr >= 2352)
799         {
800 WriteLog("CDROM: %s reading block #%u...\n", whoName[who], block);
801                 //No error checking. !!! FIX !!!
802 //NOTE: We have to subtract out the 1st track start as well (in cdintf_foo.cpp)!
803 //              CDIntfReadBlock(block - 150, cdBuf);
804
805 //Crappy kludge for shitty shit. Lesse if it works!
806                 CDIntfReadBlock(block - 150, cdBuf2);
807                 CDIntfReadBlock(block - 149, cdBuf3);
808                 for(int i=0; i<2352-4; i+=4)
809                 {
810                         cdBuf[i+0] = cdBuf2[i+4];
811                         cdBuf[i+1] = cdBuf2[i+5];
812                         cdBuf[i+2] = cdBuf2[i+2];
813                         cdBuf[i+3] = cdBuf2[i+3];
814                 }
815                 cdBuf[2348] = cdBuf3[0];
816                 cdBuf[2349] = cdBuf3[1];
817                 cdBuf[2350] = cdBuf2[2350];
818                 cdBuf[2351] = cdBuf2[2351];//*/
819
820                 block++, cdBufPtr = 0;
821         }
822
823 /*extern bool doDSPDis;
824 if (block == 244968)
825         doDSPDis = true;//*/
826
827 WriteLog("[%04X:%01X]", GET16(cdBuf, cdBufPtr), offset & 0x0F);
828 if (cdBufPtr % 32 == 30)
829         WriteLog("\n");
830
831 //      return GET16(cdBuf, cdBufPtr);
832 //This probably isn't endian safe...
833 // But then again... It seems that even though the data on the CD is organized as
834 // LL LH RL RH the way it expects to see the data is RH RL LH LL.
835 // D'oh! It doesn't matter *how* the data comes in, since it puts each sample into
836 // its own left or right side queue, i.e. it reads them 32 bits at a time and puts
837 // them into their L/R channel queues. It does seem, though, that it expects the
838 // right channel to be the upper 16 bits and the left to be the lower 16.
839         return (cdBuf[cdBufPtr + 1] << 8) | cdBuf[cdBufPtr + 0];
840 }
841
842 bool ButchIsReadyToSend(void)
843 {
844 #ifdef LOG_CDROM_VERBOSE
845 WriteLog("Butch is%s ready to send...\n", cdRam[I2CNTRL + 3] & 0x02 ? "" : " not");
846 #endif
847         return (cdRam[I2CNTRL + 3] & 0x02 ? true : false);
848 }
849
850 //
851 // This simulates a read from BUTCH over the SSI to JERRY. Uses real reading!
852 //
853 void SetSSIWordsXmittedFromButch(void)
854 {
855
856 // The problem comes in here. Really, we should generate the IRQ once we've stuffed
857 // our values into the DAC L/RRXD ports...
858 // But then again, the whole IRQ system needs an overhaul in order to make it more
859 // cycle accurate WRT to the various CPUs. Right now, it's catch-as-catch-can, which
860 // means that IRQs get serviced on scanline boundaries instead of when they occur.
861
862 // NOTE: The CD BIOS uses the following SMODE:
863 //       DAC: M68K writing to SMODE. Bits: WSEN FALLING  [68K PC=00050D8C]
864         cdBufPtr += 4;
865
866         if (cdBufPtr >= 2352)
867         {
868 WriteLog("CDROM: Reading block #%u...\n", block);
869                 //No error checking. !!! FIX !!!
870 //NOTE: We have to subtract out the 1st track start as well (in cdintf_foo.cpp)!
871 //              CDIntfReadBlock(block - 150, cdBuf);
872
873 //Crappy kludge for shitty shit. Lesse if it works!
874 //It does! That means my CD is WRONG! FUCK!
875
876 // But, then again, according to Belboz at AA the two zeroes in front *ARE* necessary...
877 // So that means my CD is OK, just this method is wrong!
878 // It all depends on whether or not the interrupt occurs on the RISING or FALLING edge
879 // of the word strobe... !!! FIX !!!
880
881 // When WS rises, left channel was done transmitting. When WS falls, right channel is done.
882 //              CDIntfReadBlock(block - 150, cdBuf2);
883 //              CDIntfReadBlock(block - 149, cdBuf3);
884                 CDIntfReadBlock(block, cdBuf2);
885                 CDIntfReadBlock(block + 1, cdBuf3);
886                 memcpy(cdBuf, cdBuf2 + 2, 2350);
887                 cdBuf[2350] = cdBuf3[0];
888                 cdBuf[2351] = cdBuf3[1];//*/
889
890                 block++, cdBufPtr = 0;
891
892 /*extern bool doDSPDis;
893 static int foo = 0;
894 if (block == 244968)
895 {
896         foo++;
897 WriteLog("\n***** foo = %u, block = %u *****\n\n", foo, block);
898         if (foo == 2)
899                 doDSPDis = true;
900 }//*/
901         }
902
903
904 WriteLog("[%02X%02X %02X%02X]", cdBuf[cdBufPtr+1], cdBuf[cdBufPtr+0], cdBuf[cdBufPtr+3], cdBuf[cdBufPtr+2]);
905 if (cdBufPtr % 32 == 28)
906         WriteLog("\n");
907
908 //This probably isn't endian safe...
909 // But then again... It seems that even though the data on the CD is organized as
910 // LL LH RL RH the way it expects to see the data is RH RL LH LL.
911 // D'oh! It doesn't matter *how* the data comes in, since it puts each sample into
912 // its own left or right side queue, i.e. it reads them 32 bits at a time and puts
913 // them into their L/R channel queues. It does seem, though, that it expects the
914 // right channel to be the upper 16 bits and the left to be the lower 16.
915
916 // This behavior is strictly a function of *where* the WS creates an IRQ. If the data
917 // is shifted by two zeroes (00 00 in front of the data file) then this *is* the
918 // correct behavior, since the left channel will be xmitted followed by the right
919
920 // Now we have definitive proof: The MYST CD shows a word offset. So that means we have
921 // to figure out how to make that work here *without* having to load 2 sectors, offset, etc.
922 // !!! FIX !!!
923         lrxd = (cdBuf[cdBufPtr + 3] << 8) | cdBuf[cdBufPtr + 2],
924         rrxd = (cdBuf[cdBufPtr + 1] << 8) | cdBuf[cdBufPtr + 0];
925 }
926
927 /*
928 [18667]
929 TOC for MYST
930
931 CDINTF: Disc summary
932         # of sessions: 2, # of tracks: 10
933         Session info:
934         1: min track= 1, max track= 1, lead out= 1:36:67
935         2: min track= 2, max track=10, lead out=55:24:71
936         Track info:
937          1: start= 0:02:00
938          2: start= 4:08:67
939          3: start= 4:16:65
940          4: start= 4:29:19
941          5: start=29:31:03
942          6: start=33:38:50
943          7: start=41:38:60
944          8: start=44:52:18
945          9: start=51:51:22
946         10: start=55:18:73
947
948 CDROM: Read sector 18517 (18667 - 150)...
949
950 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
951 0018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
952 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
953 0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
954 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
955 0078: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
956 0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
957 00A8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
958 00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
959 00D8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
960 00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
961 0108: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
962 0120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
963 0138: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
964 0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
965 0168: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
966 0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
967 0198: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
968 01B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
969 01C8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
970 01E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
971 01F8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
972 0210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
973 0228: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
974 0240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
975 0258: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
976 0270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
977 0288: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
978 02A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
979 02B8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
980 02D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
981 02E8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
982 0300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
983 0318: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
984 0330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
985 0348: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
986 0360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
987 0378: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
988 0390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
989 03A8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
990 03C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
991 03D8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
992 03F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
993 0408: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
994 0420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
995 0438: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
996 0450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
997 0468: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
998 0480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
999 0498: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1000 04B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1001 04C8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1002 04E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1003 04F8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1004 0510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1005 0528: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1006 0540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1007 0558: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1008 0570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1009 0588: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1010 05A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1011 05B8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1012 05D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1013 05E8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1014 0600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1015 0618: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1016 0630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1017 0648: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1018 0660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1019 0678: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1020 0690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1021 06A8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1022 06C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1023 06D8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1024 06F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1025 0708: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1026 0720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1027 0738: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1028 0750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1029 0768: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1030 0780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1031 0798: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1032 07B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1033 07C8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[54 41 49 52]54 41
1034 07E0: 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41
1035 07F8: 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41 49 52 54 41
1036 0810: 49 52 54 41 49 52[54 41 49 52]54 41 52 41 20 49 50 41 52 50 56 4F 44 45
1037 0828: 44 20 54 41 20 41 45 48 44 41 52 45 41 20 52 54 20 49[00 00 00 50]01 00
1038 0840: 80 83 FC 23 07 00 07 00 F0 00 0C 21 FC 23 07 00 07 00 F1 00 0C A1 FC 33
1039 0858: FF FF F0 00 4E 00 7C 2E 1F 00 FC FF 00 61 08 00 F9 4E 00 00 00 51 E7 48
1040 0870: 00 FE 39 30 F1 00 02 40 40 02 10 00 00 67 1C 00 79 42 01 00 8C D3 3C 34
1041 0888: 37 03 3C 30 81 05 3C 3C 0A 01 3C 38 F1 00 00 60 1A 00 FC 33 01 00 01 00
1042 08A0: 8C D3 3C 34 4B 03 3C 30 65 05 3C 3C 42 01 3C 38 1F 01 C0 33 01 00 88 D3
1043 08B8: C4 33 01 00 8A D3 00 32 41 E2 41 94 7C D4 04 00 7C 92 01 00 41 00 00 04
1044 08D0: C1 33 01 00 82 D3 C1 33 F0 00 3C 00 C2 33 01 00 80 D3 C2 33 F0 00 38 00
1045 08E8: C2 33 F0 00 3A 00 06 3A 44 9A C5 33 01 00 84 D3 44 DC C6 33 01 00 86 D3
1046 0900: F9 33 01 00 84 D3 F0 00 46 00 FC 33 FF FF F0 00 48 00 FC 23 00 00 00 00
1047 0918: F0 00 2A 00 FC 33 00 00 F0 00 58 00 DF 4C 7F 00 75 4E 00 00 00 00 00 00
1048
1049 Raw P-W subchannel data:
1050
1051 00: 80 80 C0 80 80 80 80 C0 80 80 80 80 80 80 C0 80
1052 10: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
1053 20: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 C0
1054 30: 80 80 80 80 80 80 80 80 80 80 80 80 80 C0 80 80
1055 40: 80 80 80 80 C0 80 80 80 80 C0 C0 80 80 C0 C0 80
1056 50: C0 80 80 C0 C0 C0 80 80 C0 80 80 80 C0 80 80 80
1057
1058 P subchannel data: FF FF FF FF FF FF FF FF FF FF FF FF
1059 Q subchannel data: 21 02 00 00 00 01 00 04 08 66 9C 88
1060
1061 Run address: $5000, Length: $18380
1062 */
1063
1064
1065 /*
1066 CD_read function from the CD BIOS: Note that it seems to direct the EXT1 interrupt
1067 to the GPU--so that would mean *any* interrupt that BUTCH generates would be routed
1068 to the GPU...
1069
1070 read:
1071                 btst.l  #31,d0
1072                 bne.w   .play
1073                 subq.l  #4,a0           ; Make up for ISR pre-increment
1074                 move.l  d0,-(sp)
1075                 move.l  BUTCH,d0
1076                 and.l   #$ffff0000,d0
1077                 move.l  d0,BUTCH        ; NO INTERRUPTS!!!!!!!!!!!
1078                 move.l  (sp)+,d0
1079 ;               move.l  #0,BUTCH
1080
1081                 move.w  #$101,J_INT
1082
1083                 move.l  d1,-(sp)
1084                 move.l  I2CNTRL,d1      ;Read I2S Control Register
1085                 bclr    #2,d1           ; Stop data
1086                 move.l  d1,I2CNTRL
1087                 move.l  (sp)+,d1
1088
1089                 move.l  PTRLOC,a2
1090                 move.l  a0,(a2)+
1091                 move.l  a1,(a2)+
1092                 move.l  #0,(a2)+
1093
1094                 btst.b  #7,INITTYPE
1095                 beq     .not_bad
1096                 move.l  PTRLOC,a0
1097                 asl.l   #5,d2
1098
1099                 move.l  d2,-(sp)
1100
1101                 or.l    #$089a3c1a,d2           ; These instructions include the bclr
1102                 move.l  d2,188(a0)
1103
1104                 move.l  (sp)+,d2
1105
1106                 swap    d2
1107                 or.l    #$3c1a1838,d2           ; These instructions include the bclr
1108                 move.l  d2,196(a0)
1109
1110                 move.l  #16,(a2)+
1111                 move.l  d1,(a2)
1112
1113 .not_bad:
1114
1115                 move.w  DS_DATA,d1                      ; Clear any pending DSARX states
1116                 move.l  I2CNTRL,d1                      ; Clear any pending errors
1117
1118 ; Drain the FIFO so that we don't get overloaded
1119
1120 .dump:
1121                 move.l  FIFO_DATA,d1
1122                 move.l  I2CNTRL,d1
1123                 btst    #4,d1
1124                 bne.b   .dump
1125
1126 .butch_go:
1127                 move.l  BUTCH,d1
1128                 and.l   #$FFFF0000,d1
1129                 or.l    #%000100001,d1                   ;Enable DSARX interrupt
1130                 move.l  d1,BUTCH
1131 ;               move.l  #%000100001,BUTCH                ;Enable DSARX interrupt
1132
1133 ; Do a play @
1134
1135 .play:  move.l  d0,d1           ; mess with copy in d1
1136                 lsr.l   #8,d1           ; shift the byte over
1137                 lsr.w   #8,d1
1138                 or.w    #$1000,d1       ; format it for goto
1139                 move.w  d1,DS_DATA      ; DSA tx
1140         bsr.b   DSA_tx
1141
1142                 move.l  d0,d1           ; mess with copy in d1
1143                 lsr.w   #8,d1
1144                 or.w    #$1100,d1       ; format it for goto
1145                 move.w  d1,DS_DATA      ; DSA tx
1146         bsr.b   DSA_tx
1147
1148                 move.l  d0,d1           ; mess with copy in d1
1149                 and.w   #$00FF,d1       ; mask for minutes
1150                 or.w    #$1200,d1       ; format it for goto
1151                 move.w  d1,DS_DATA      ; DSA tx
1152         bsr.b   DSA_tx
1153
1154                 rts
1155
1156
1157 ****************************
1158 * Here's the GPU interrupt *
1159 ****************************
1160
1161 JERRY_ISR:
1162         movei   #G_FLAGS,r30
1163         load    (r30),r29               ;read the flags
1164
1165         movei   #BUTCH,r24
1166
1167 make_ptr:
1168         move    pc,Ptrloc
1169         movei   #(make_ptr-PTRPOS),TEMP
1170         sub     TEMP,Ptrloc
1171
1172 HERE:
1173         move    pc,r25
1174         movei   #(EXIT_ISR-HERE),r27
1175         add     r27,r25
1176
1177 ; Is this a DSARX interrupt?
1178
1179         load    (r24),r27               ;check for DSARX int pending
1180         btst    #13,r27
1181         jr      z,fifo_read                     ; This should ALWAYS fall thru the first time
1182
1183 ; Set the match bit, to allow data
1184 ;       moveq   #3,r26                  ; enable FIFO only
1185 ; Don't just jam a value
1186 ; Clear the DSARX and set FIFO
1187         bclr    #5,r27
1188         bset    #1,r27
1189         store   r27,(r24)
1190         addq    #$10,r24
1191         load    (r24),r27
1192         bset    #2,r27
1193         store   r27,(r24)               ; Disable SUBCODE match
1194
1195 ; Now we clear the DSARX interrupt in Butch
1196
1197         subq    #12,r24                 ; does what the above says
1198         load    (r24),r26               ;Clears DSA pending interrupt
1199         addq    #6,r24
1200         loadw   (r24),r27               ; Read DSA response
1201         btst    #10,r27                 ; Check for error
1202         jr      nz,error
1203         or      r26,r26
1204         jump    (r25)
1205 ;       nop
1206
1207 fifo_read:
1208 ; Check for ERROR!!!!!!!!!!!!!!!!!!!!!
1209         btst    #14,r27
1210         jr      z,noerror
1211         bset    #31,r27
1212 error:
1213         addq    #$10,r24
1214         load    (r24),TEMP
1215         or      TEMP,TEMP
1216         subq    #$10,r24
1217         load    (Ptrloc),TEMP
1218         addq    #8,Ptrloc
1219         store   TEMP,(Ptrloc)
1220         subq    #8,Ptrloc
1221 noerror:
1222         load    (Ptrloc),Dataptr        ;get pointer
1223
1224 ; Check to see if we should stop
1225         addq    #4,Ptrloc
1226         load    (Ptrloc),TEMP
1227         subq    #4,Ptrloc
1228         cmp     Dataptr,TEMP
1229         jr      pl,notend
1230 ;       nop
1231         bclr    #0,r27
1232         store   r27,(r24)
1233
1234 notend:
1235         movei   #FIFO_DATA,CDdata
1236         move    CDdata,r25
1237         addq    #4,CDdata
1238 loptop:
1239         load    (CDdata),TEMP
1240         load    (r25),r30
1241         load    (CDdata),r21
1242         load    (r25),r22
1243         load    (CDdata),r24
1244         load    (r25),r20
1245         load    (CDdata),r19
1246         load    (r25),r18
1247         addq    #4,Dataptr
1248         store   TEMP,(Dataptr)
1249         addqt   #4,Dataptr
1250         store   r30,(Dataptr)
1251         addqt   #4,Dataptr
1252         store   r21,(Dataptr)
1253         addqt   #4,Dataptr
1254         store   r22,(Dataptr)
1255         addqt   #4,Dataptr
1256         store   r24,(Dataptr)
1257         addqt   #4,Dataptr
1258         store   r20,(Dataptr)
1259         addqt   #4,Dataptr
1260         store   r19,(Dataptr)
1261         addqt   #4,Dataptr
1262         store   r18,(Dataptr)
1263
1264         store   Dataptr,(Ptrloc)
1265
1266 exit_isr:
1267         movei   #J_INT,r24      ; Acknowledge in Jerry
1268         moveq   #1,TEMP
1269         bset    #8,TEMP
1270         storew  TEMP,(r24)
1271
1272 .if FLAG
1273 ; Stack r18
1274         load    (r31),r18
1275         addq    #4,r31
1276
1277 ; Stack r19
1278         load    (r31),r19
1279         addq    #4,r31
1280
1281 ; Stack r20
1282         load    (r31),r20
1283         addq    #4,r31
1284
1285 ; Stack r21
1286         load    (r31),r21
1287         addq    #4,r31
1288
1289 ; Stack r22
1290         load    (r31),r22
1291         addq    #4,r31
1292
1293 ; Stack r23
1294         load    (r31),r23
1295         addq    #4,r31
1296
1297 ; Stack r26
1298         load    (r31),r26
1299         addq    #4,r31
1300
1301 ; Stack r27
1302         load    (r31),r27
1303         addq    #4,r31
1304
1305 ; Stack r24
1306         load    (r31),r24
1307         addq    #4,r31
1308
1309 ; Stack r25
1310         load    (r31),r25
1311         addq    #4,r31
1312 .endif
1313
1314         movei   #G_FLAGS,r30
1315
1316 ;r29 already has flags
1317         bclr    #3,r29          ;IMASK
1318         bset    #10,r29         ;Clear DSP int bit in TOM
1319
1320         load    (r31),r28       ;Load return address
1321
1322
1323         addq    #2,r28          ;Fix it up
1324         addq    #4,r31
1325         jump    (r28)           ;Return
1326         store   r29,(r30)       ;Restore broken flags
1327
1328
1329         align long
1330
1331 stackbot:
1332         ds.l    20
1333 STACK:
1334
1335
1336 */
1337