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