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
9 #include "jaguar.h" // For GET32/SET32 macros
11 #include "cdintf.h" // System agnostic CD interface functions
14 //#define CDROM_LOG // For CDROM logging, obviously
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
31 ; Butch's hardware registers
33 ;BUTCH equ $DFFF00 ;base of Butch=interrupt control register, R/W
35 ; When written (Long):
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
45 ; bit7-31 reserved, set to 0
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
60 O_DSCNTRL equ 4 ; DSA control register, R/W
61 O_DS_DATA equ $A ; DSA TX/RX data, R/W
63 O_I2CNTRL equ $10 ; i2s bus control register, R/W
67 ; b0 - I2S data from drive is ON if 1
68 ; b1 - I2S path to Jerry is ON if 1
70 ; b3 - host bus width is 16 if 1, else 32
71 ; b4 - FIFO state is not empty if 1
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)
82 Commands sent through DS_DATA:
84 $01nn - ? Play track nn ? Seek to track nn ?
86 $03nn - Read session nn TOC (short)
92 $14nn - Read session nn TOC (full)
94 $18nn - Spin up CD to session nn
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
101 Commands send through serial bus:
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
119 // Private function prototypes
121 static void CDROMBusWrite(uint16);
122 static uint16 CDROMBusRead(void);
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
136 char * BReg[12] = { "BUTCH", "DSCNTRL", "DS_DATA", "???", "I2CNTRL", "SBCNTRL", "SUBDATA", "SUBDATB",
137 "SB_TIME", "FIFO_DATA", "I2SDAT2", "UNKNOWN" };
138 extern char * whoName[9];
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
150 //extern bool GetRawTOC(void);
153 haveCDGoodness = CDIntfInit();
157 uint32 sec = 18667 - 150;
158 memset(buf, 0, 2448);
159 if (!CDIntfReadBlock(sec, buf))
161 WriteLog("CDROM: Attempt to read with subchannel data failed!\n");
167 WriteLog("\nCDROM: Read sector %u...\n\n", sec);
168 for(int i=0; i<98; i++)
170 WriteLog("%04X: ", i*24);
171 for(int j=0; j<24; j++)
173 WriteLog("%02X ", buf[j + (i*24)]);
177 WriteLog("\nRaw P-W subchannel data:\n\n");
178 for(int i=0; i<6; i++)
180 WriteLog("%02X: ", i*16);
181 for(int j=0; j<16; j++)
183 WriteLog("%02X ", buf[2352 + j + (i*16)]);
187 WriteLog("\nP subchannel data: ");
188 for(int i=0; i<96; i+=8)
191 for(int j=0; j<8; j++)
192 b |= ((buf[2352 + i + j] & 0x80) >> 7) << (7 - j);
194 WriteLog("%02X ", b);
196 WriteLog("\nQ subchannel data: ");
197 for(int i=0; i<96; i+=8)
200 for(int j=0; j<8; j++)
201 b |= ((buf[2352 + i + j] & 0x40) >> 6) << (7 - j);
203 WriteLog("%02X ", b);
205 WriteLog("\n\n");//*/
208 void CDROMReset(void)
210 memset(cdRam, 0x00, 0x100);
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.
226 void BUTCHExec(uint32 cycles)
229 // We're chickening out for now...
232 extern uint8 * jerry_ram_8; // Hmm.
234 // For now, we just do the FIFO interrupt. Timing is also likely to be WRONG as well.
235 uint32 cdState = GET32(cdRam, BUTCH);
237 if (!(cdState & 0x01)) // No BUTCH interrupts enabled
240 if (!(cdState & 0x22))
241 return; // For now, we only handle FIFO/buffer full interrupts...
243 // From what I can make out, it seems that each FIFO is 32 bytes long
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);
254 // CD-ROM memory access functions
257 uint8 CDROMReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
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));
264 return cdRam[offset & 0xFF];
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*/)
276 uint16 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.
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)
295 if ((cdCmd & 0xFF00) == 0x0100) // ???
297 //Not sure how to acknowledge the ???...
298 // data = 0x0400;//?? 0x0200;
317 WriteLog("CDROM: Reading DS_DATA (???), cdCmd=$%04X\n", cdCmd);
319 else if ((cdCmd & 0xFF00) == 0x0200) // Stop CD
321 //Not sure how to acknowledge the stop...
322 data = 0x0400;//?? 0x0200;
341 WriteLog("CDROM: Reading DS_DATA (stop), cdCmd=$%04X\n", cdCmd);
343 else if ((cdCmd & 0xFF00) == 0x0300) // Read session TOC (overview?)
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
369 //Should do something like so:
370 // data = GetSessionInfo(cdCmd & 0xFF, cdPtr);
371 data = CDIntfGetSessionInfo(cdCmd & 0xFF, cdPtr);
372 if (data == 0xFF) // Failed...
375 WriteLog("CDROM: Requested invalid session #%u (or failed to load TOC, or bad cdPtr value)\n", cdCmd & 0xFF);
379 data |= (0x20 | cdPtr++) << 8;
380 WriteLog("CDROM: Reading DS_DATA (session #%u TOC byte #%u): $%04X\n", cdCmd & 0xFF, cdPtr, data);
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?)
391 data = 0x2001; // Min track for this session?
394 data = 0x210A; // Max track for this session?
397 data = 0x2219; // Max lead-out time, absolute minutes
400 data = 0x2319; // Max lead-out time, absolute seconds
403 data = 0x2419; // Max lead-out time, absolute frames
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
418 WriteLog("CDROM: Reading DS_DATA (session #%u TOC byte #%u): $%04X\n", cdCmd & 0xFF, cdPtr, data);
423 WriteLog("CDROM: Requested invalid session #%u\n", cdCmd & 0xFF);
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
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]
436 if (trackNum > maxTrack)
439 WriteLog("CDROM: Requested invalid track #%u for session #%u\n", trackNum, cdCmd & 0xFF);
444 data = (cdPtr << 8) | trackNum;
445 else if (cdPtr < 0x65)
446 data = (cdPtr << 8) | CDIntfGetTrackInfo(trackNum, (cdPtr - 2) & 0x0F);
448 WriteLog("CDROM: Reading DS_DATA (session #%u, full TOC byte #%u): $%04X\n", cdCmd & 0xFF, (cdPtr+1) & 0x0F, data);
452 cdPtr = 0x60, trackNum++;
455 // Note that it seems to return track info in sets of 4 (or is it 5?)
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
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?)
475 data = 0x6000 | trackNum; // Track #
478 data = 0x6100 | trackNum; // Track # (again?)
481 data = 0x6200 | minutes[trackNum]; // Minutes
484 data = 0x6300 | seconds[trackNum]; // Seconds
487 data = 0x6400 | frames[trackNum]; // Frames
492 else if ((cdCmd & 0xFF00) == 0x1500) // Read CD mode
494 data = cdCmd | 0x0200; // ?? not sure ?? [Seems OK]
495 WriteLog("CDROM: Reading DS_DATA (mode), cdCmd=$%04X\n", cdCmd);
497 else if ((cdCmd & 0xFF00) == 0x1800) // Spin up session #
500 WriteLog("CDROM: Reading DS_DATA (spin up session), cdCmd=$%04X\n", cdCmd);
502 else if ((cdCmd & 0xFF00) == 0x5400) // Read # of sessions
504 data = cdCmd | 0x00; // !!! Hardcoded !!! FIX !!!
505 WriteLog("CDROM: Reading DS_DATA (# of sessions), cdCmd=$%04X\n", cdCmd);
507 else if ((cdCmd & 0xFF00) == 0x7000) // Read oversampling
509 //NOTE: This setting will probably affect the # of DSP interrupts that need to happen. !!! FIX !!!
511 WriteLog("CDROM: Reading DS_DATA (oversampling), cdCmd=$%04X\n", cdCmd);
516 WriteLog("CDROM: Reading DS_DATA, unhandled cdCmd=$%04X\n", cdCmd);
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)
524 else if (offset >= FIFO_DATA + 4 && offset <= FIFO_DATA + 7)
528 data = GET16(cdRam, offset);
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)
536 /*if (offset == 0x2C)
539 data = 0;//0x0008;//*/
540 if (offset == UNKNOWN + 2)
541 data = CDROMBusRead();
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));
552 void CDROMWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
555 cdRam[offset] = data;
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));
564 void CDROMWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
567 SET16(cdRam, offset, data);
570 //Lesse what this does... Seems to work OK...!
571 if (offset == DS_DATA)
574 if ((data & 0xFF00) == 0x0200) // Stop CD
577 WriteLog("CDROM: Stopping CD\n", data & 0xFF);
579 else if ((data & 0xFF00) == 0x0300) // Read session TOC (short? overview?)
582 WriteLog("CDROM: Reading TOC for session #%u\n", data & 0xFF);
584 //Not sure how these three acknowledge...
585 else if ((data & 0xFF00) == 0x1000) // Seek to minute position
589 else if ((data & 0xFF00) == 0x1100) // Seek to second position
593 else if ((data & 0xFF00) == 0x1200) // Seek to frame position
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);
600 else if ((data & 0xFF00) == 0x1400) // Read "full" TOC for session
603 minTrack = CDIntfGetSessionInfo(data & 0xFF, 0),
604 maxTrack = CDIntfGetSessionInfo(data & 0xFF, 1);
606 WriteLog("CDROM: Reading \"full\" TOC for session #%u (min=%u, max=%u)\n", data & 0xFF, minTrack, maxTrack);
608 else if ((data & 0xFF00) == 0x1500) // Set CDROM mode
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);
614 else if ((data & 0xFF00) == 0x1800) // Spin up session #
616 WriteLog("CDROM: Spinning up session #%u\n", data & 0xFF);
618 else if ((data & 0xFF00) == 0x5400) // Read # of sessions
620 WriteLog("CDROM: Reading # of sessions\n", data & 0xFF);
622 else if ((data & 0xFF00) == 0x7000) // Set oversampling rate
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)]);
629 WriteLog("CDROM: Unknown command $%04X\n", data);
632 if (offset == UNKNOWN + 2)
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));
644 // State machine for sending/receiving data along a serial bus
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;
656 static void CDROMBusWrite(uint16 data)
658 //This is kinda lame. What we should do is check for a 0->1 transition on either bits 0 or 1...
663 WriteLog("CDROM: BusWrite write on unknown line: $%04X\n", data);
666 switch (currentState)
669 currentState = ST_RISING;
672 if (data & 0x0001) // Command coming
682 busCmd <<= 1; // Make room for next bit
683 busCmd |= (data & 0x04); // & put it in
688 busCmd >>= 2; // Because we ORed bit 2, we need to shift right by 2
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...
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;
708 // rxData = 0x8349;//8000;//0F67;
714 WriteLog("CDROM: *** BusWrite got command $%04X\n", busCmd);
720 txData = (txData << 1) | ((data & 0x04) >> 2);
721 //WriteLog("[%s]", data & 0x04 ? "1" : "0");
723 rxDataBit = (rxData & 0x8000) >> 12;
728 WriteLog("CDROM: *** BusWrite got extra command $%04X\n", txData);
733 currentState = ST_FALLING;
736 currentState = ST_INIT;
741 static uint16 CDROMBusRead(void)
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!
747 if ((counter & 0x0F) == 0)
749 if (counter == 0 && rxDataBit == 0)
758 WriteLog("%s\n", rxDataBit ? "1" : "0");
761 WriteLog("%s", rxDataBit ? "1" : "0");
768 // This simulates a read from BUTCH over the SSI to JERRY. Uses real reading!
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*/)
774 bool go = ((offset & 0x0F) == 0x0A || (offset & 0x0F) == 0x0E ? true : false);
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.
786 if (cdBufPtr >= 2352)
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);
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)
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];
803 cdBuf[2348] = cdBuf3[0];
804 cdBuf[2349] = cdBuf3[1];
805 cdBuf[2350] = cdBuf2[2350];
806 cdBuf[2351] = cdBuf2[2351];//*/
808 block++, cdBufPtr = 0;
811 /*extern bool doDSPDis;
815 WriteLog("[%04X:%01X]", GET16(cdBuf, cdBufPtr), offset & 0x0F);
816 if (cdBufPtr % 32 == 30)
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];
830 bool ButchIsReadyToSend(void)
832 WriteLog("Butch is%s ready to send...\n", cdRam[I2CNTRL + 3] & 0x02 ? "" : " not");
834 return (cdRam[I2CNTRL + 3] & 0x02 ? true : false);
838 // This simulates a read from BUTCH over the SSI to JERRY. Uses real reading!
840 void SetSSIWordsXmittedFromButch(void)
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.
849 // NOTE: The CD BIOS uses the following SMODE:
850 // DAC: M68K writing to SMODE. Bits: WSEN FALLING [68K PC=00050D8C]
853 if (cdBufPtr >= 2352)
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);
860 //Crappy kludge for shitty shit. Lesse if it works!
861 //It does! That means my CD is WRONG! FUCK!
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 !!!
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];//*/
877 block++, cdBufPtr = 0;
879 /*extern bool doDSPDis;
884 WriteLog("\n***** foo = %u, block = %u *****\n\n", foo, block);
891 WriteLog("[%02X%02X %02X%02X]", cdBuf[cdBufPtr+1], cdBuf[cdBufPtr+0], cdBuf[cdBufPtr+3], cdBuf[cdBufPtr+2]);
892 if (cdBufPtr % 32 == 28)
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.
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
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.
910 lrxd = (cdBuf[cdBufPtr + 3] << 8) | cdBuf[cdBufPtr + 2],
911 rrxd = (cdBuf[cdBufPtr + 1] << 8) | cdBuf[cdBufPtr + 0];
919 # of sessions: 2, # of tracks: 10
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
935 CDROM: Read sector 18517 (18667 - 150)...
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
1036 Raw P-W subchannel data:
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
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
1048 Run address: $5000, Length: $18380
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
1060 subq.l #4,a0 ; Make up for ISR pre-increment
1064 move.l d0,BUTCH ; NO INTERRUPTS!!!!!!!!!!!
1071 move.l I2CNTRL,d1 ;Read I2S Control Register
1072 bclr #2,d1 ; Stop data
1088 or.l #$089a3c1a,d2 ; These instructions include the bclr
1094 or.l #$3c1a1838,d2 ; These instructions include the bclr
1102 move.w DS_DATA,d1 ; Clear any pending DSARX states
1103 move.l I2CNTRL,d1 ; Clear any pending errors
1105 ; Drain the FIFO so that we don't get overloaded
1116 or.l #%000100001,d1 ;Enable DSARX interrupt
1118 ; move.l #%000100001,BUTCH ;Enable DSARX interrupt
1122 .play: move.l d0,d1 ; mess with copy in d1
1123 lsr.l #8,d1 ; shift the byte over
1125 or.w #$1000,d1 ; format it for goto
1126 move.w d1,DS_DATA ; DSA tx
1129 move.l d0,d1 ; mess with copy in d1
1131 or.w #$1100,d1 ; format it for goto
1132 move.w d1,DS_DATA ; DSA tx
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
1144 ****************************
1145 * Here's the GPU interrupt *
1146 ****************************
1150 load (r30),r29 ;read the flags
1156 movei #(make_ptr-PTRPOS),TEMP
1161 movei #(EXIT_ISR-HERE),r27
1164 ; Is this a DSARX interrupt?
1166 load (r24),r27 ;check for DSARX int pending
1168 jr z,fifo_read ; This should ALWAYS fall thru the first time
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
1180 store r27,(r24) ; Disable SUBCODE match
1182 ; Now we clear the DSARX interrupt in Butch
1184 subq #12,r24 ; does what the above says
1185 load (r24),r26 ;Clears DSA pending interrupt
1187 loadw (r24),r27 ; Read DSA response
1188 btst #10,r27 ; Check for error
1195 ; Check for ERROR!!!!!!!!!!!!!!!!!!!!!
1209 load (Ptrloc),Dataptr ;get pointer
1211 ; Check to see if we should stop
1222 movei #FIFO_DATA,CDdata
1235 store TEMP,(Dataptr)
1251 store Dataptr,(Ptrloc)
1254 movei #J_INT,r24 ; Acknowledge in Jerry
1303 ;r29 already has flags
1305 bset #10,r29 ;Clear DSP int bit in TOM
1307 load (r31),r28 ;Load return address
1310 addq #2,r28 ;Fix it up
1313 store r29,(r30) ;Restore broken flags