Not Rocket Science

Why do PC Engine CD-ROM² games have a second data track?

If you look at the layout of a PC Engine CD-ROM² game, you will probably find a disc that has two data tracks:

PC Engine CD Layout

I thought this was pretty unusual - as someone mostly familiar with home computers and later CD-based consoles, I usually expect a single data track as Track 1 and optional Audio tracks afterwards.

Why does the CD start with an audio track?

Seeing the data track be Track 2 does make sense to me given how early in the "CD as data storage" lifecycle it was: Track 1 is an audio track warning people to not play the Disc in a CD Player because playing a data track is very unpleasant and can (allegedly) damage equipment.

The first data track

Track 2 is the data track that contains the actual game data. The CD-ROM² system card actually finds the first data track on the CD, and then loads data into RAM based on the IPL header - so in theory, the first data track could be Track 3 or Track 38 or whatever. The BIOS calls cd_contnts and then cd_dinfo on every track until it finds a data track, then proceeds to load the IPL from the first two sectors of that track.

This all makes sense so far, but what about the second data track that's usually at the very end of the CD? I looked at dozens of games, and it's usually either completely or mostly identical to the original data track.

I've heard some people say that it's for performance, and other say that it's for reduncancy. Turns out that it's for reduncancy.

cd_base, recbase1, and reduncancy

The System Card offers a method called cd_base which is used to set the base address from which all other functions (cd_read, cd_exec, cd_seek, etc.) are relative to. This methods can take a logical block address (LBA), a timestamp (Minutes, Seconds, Frames), or a Track Number and it then updates recbase0 and/or recbase1 with the LBA.

The system card automatically sets recbase0 = recbase1 = LBA of first data track, and games usually assign recbase1 to the second data track themselves. Often, they also set recbase0 to the first data track again, even though it's redundant - not sure why, not all games do it, so I wonder if it's just mixed guidance from NEC/Hudson Soft back in the early days of the system.

; recbase0 - usually redundant because the System Card already set it
LDA #$80       ; _BH = CD-TNO mode
STA _bh
LDA #$02       ; _AL = TNO 2, expressed as BCD
STA _al
LDA #$01       ; _CL = Set mode: Set first
STA _cl
JSR $E006      ; recbase0 = LBA of Track 2

; recbase1 - set by the System Card initially to Track 2, same as recbase0
LDA #$80       ; _BH = CD-TNO mode
STA _bh
LDA #$28       ; _AL = TNO 28, expressed as BCD
STA _al
LDA #$02       ; _CL = Set mode: Set second
STA _cl
JSR $E006      ; recbase1 = LBA of Track 28

When you call cd_read, you give it an LBA that's relative to the start of the data track, e.g., LBA 1234 means "the 1234th sector within the data track". cd_read then adds recbase0 to 1234 to get the actual LBA on the disc and starts reading from there.

So, when is recbase1 used? When a read fails. The PC Engine CD-ROM drive is a SCSI drive, and most methods construct a SCSI Command Data Block (CDB) which contains an LBA, then dispatch it to the drive, and wait for the result. There is a helper method inside the System Card to do the "recbase0 + 1234" LBA math, and this helper method looks for a retry? variable in memory (Address $2273).

If the drive fails to read sixteen times, the system card sets that retry? variable and if it's set, the LBA helper method uses recbase1 instead of recbase0. (On the System Card 3.0, this helper sits at memory address $F104).

Whenever you call cd_read etc., it resets the retry? variable back to 0 and tries to read from the original data track again, and after 16 failures it switches to the second data track.

Performance

I heard some people say that putting a second data track on the outside of the disc improves performance because data on the outside can be read faster. I do not believe this to be true per-se: The PC Engine CD-ROM drive is CLV, so performance should be the same all over the disc.

However, there are some games where the second data track is considerably different than the first, one such example is Snatcher. It still contains mostly the same content, but also a lot of unique content.

This might actually be related to seek times across the disc when playing redbook audio: The Mednafen emulator models a worst-case seek time of 800 ms, so it definitely makes sense to avoid seeking between Track 2 and audio track 23 constantly and instead use Track 24 for shorter head movements.

Most games did not do that, and there was no first-class support in the System Card to make this trivial, but it's not that hard: Figure out the LBA to Track 24, then add it to the LBA of your file in Track 2. The cd_read etc. methods don't actually verify that the LBA passed into them is part of the data track - they just add recbase0 to it and tell the drive to go there, which can be anywhere on the disc.

Of course, in this case a retry might have disastrous consequences (and Snatcher does NOT seem to set recbase1=recbase0 as a guard), but let's be honest: If your disc is so badly damaged that the second data track is needed at all, you're probably in for a bad time.

Bonus finding: Pregaps

If you look at the structure of the disc, you will also notice a 3 second pregap for each data track, and a 2 second pregap for the audio track following the data track. Turns out that this is part of the Yellow Book CD-ROM standard. Because CD-ROM drives read data and audio tracks differently, they need to be given some time to "switch modes", hence the standard requires:

That's why Track 2 (data following audio) and Track 3 (audio following data) have a pregap, to be standards compliant.

Conclusion

Developer documentation for the System Card 1.0 was found on archive.org.

Post Tags
PC Engine