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