After the recent discussion on the PCE's CD booting, and my continuing discussion with TheOldMan, I thought that I'd document something that I've not seen mentioned before.
Anyone that has looked at making a PCE CD has already discovered the "IPL Information Data Block" that must be put in the 2nd sector on the CD, and who's data values tell Hudson's IPL (the code that must be put in the 1st sector on the CD) exactly where to load your game program and what address to call to run it.
Now while you can just let PCEAS handle creating a CD image for you ... you can also just do it yourself if you want complete control over the CD layout.
As a reminder, here is the "IPL Information Data Block" in PCEAS format, together with the PCEAS/HuC default values ...
org $3000
; IPL INFORMATION DATA BLOCK
db $00 ; $00 IPLBLK_H (ISO Sector 2)
db $00 ; $01 IPLBLK_M
db $02 ; $02 IPLBLK_L
db $10 ; $03 IPLBLN (Size $8000)
db $00 ; $04 IPLSTA_L (Load $4000)
db $40 ; $05 IPLSTA_H
db $70 ; $06 IPLJMP_L (Exec $4070)
db $40 ; $07 IPLJMP_H
db $00 ; $08 IPLMPR2 (bank $80)
db $01 ; $09 IPLMPR3 (bank $81)
db $02 ; $0A IPLMPR4 (bank $82)
db $03 ; $0B IPLMPR5 (bank $83)
db $00 ; $0C IPLMPR6 (bank $80)
db $60 ; $0D OPENMODE
; bit 0 - Load VRAM : 0 = Off
; bit 1 - Load ADPCM : 0 = Off
; bit 5 - BG Display : 1 = Off
; bit 6 - Play ADPCM : 1 = Off
; bit 7 - Loop ADPCM : 0 = Off
db $00 ; $0E GRPBLK_H
db $00 ; $0F GRPBLK_M
db $00 ; $10 GRPBLK_L
db $00 ; $11 GRPBLN
db $00 ; $12 GRPADR_L
db $00 ; $13 GRPADR_H
db $00 ; $14 ADPBLK_H
db $00 ; $15 ADPBLK_M
db $00 ; $16 ADPBLK_L
db $00 ; $17 ADPBLN
db $00 ; $18 ADPRATE
db $00 ; $19 reserved
db $00 ; $1A reserved
db $00 ; $1B reserved
db $00 ; $1C reserved
db $00 ; $1D reserved
db $00 ; $1E reserved
db $00 ; $1F reserved
db $50,$43,$20,$45 ; |PC E|
db $6e,$67,$69,$6e ; |ngin|
db $65,$20,$43,$44 ; |e CD|
db $2d,$52,$4f,$4d ; |-ROM|
db $20,$53,$59,$53 ; | SYS|
db $54,$45,$4d,$00 ; |TEM.|
db $43,$6f,$70,$79 ; |Copy|
db $72,$69,$67,$68 ; |righ|
db $74,$20,$48,$55 ; |t HU|
db $44,$53,$4f,$4e ; |DSON|
db $20,$53,$4f,$46 ; | SOF|
db $54,$20,$2f,$20 ; |T / |
db $4e,$45,$43,$20 ; |NEC |
db $48,$6f,$6d,$65 ; |Home|
db $20,$45,$6c,$65 ; | Ele|
db $63,$74,$72,$6f ; |ctro|
db $6e,$69,$63,$73 ; |nics|
db $2c,$4c,$74,$64 ; |,Ltd|
db $2e,$00 ; |..|
; Game Name (16 bytes)
db " "
; Game Code (6 bytes)
db " "**************
The "IPL Information Data Block" is 128 bytes long, which leaves 1920 bytes of unused space in the 2nd sector on the CD.
This space is normally wasted, but TheOldMan has found that he can put some program code in there that's "hidden" from HuC, and execute it before his HuC program starts up.
He can do this because he's found that Hudson's IPL code always loads that block into memory at $3000.
So just by setting the IPLJMP address to $3080 instead of PCEAS's default $4070, he can run his own code before jumping to the normal PCEAS/HuC startup at $4070.
Since PCEAS is designed to always load the user's program at $4000, and execute it at $4070, then this technique doesn't cause any problems.
While this is a neat trick, I'm 100% sure that the leftover space had a different purpose ... one that I've not seen mentioned before.
That is as a way for a developer to create their own IPL code that gets control of the system as-soon-as-possible after boot.
If you set the IPLBLN value to $00, which means that you don't want the IPL to load any game code at all, then you can set IPLJMP to $0080 (NOT $3080), and the IPL will jump to the 1920 bytes of code that you've put in the 2nd sector.
That's not a
lot of code space ... but it is enough to create your own IPL program that then loads up your game code however and from wherever you wish.
Some obvious things that you could do with this are to create a startup logo that animates while the main game code is loading, or to immediately jump to a totally different boot loader if you find that you are running on a System Card 2.0 instead of a System Card 3.0.
It could also be used to create a complicated loading system that would be hard to crack/copy ... although that idea had more value in the 1980s and 1990s, before Mednafen and other emulators were written.
**************
Because Hudson make you specify an IPLJMP address that is relative to the start of the sector, rather than just setting it to $3080, then I'm pretty sure that they didn't want developers to always rely on that sector getting loaded at $3000.
Console manufacturers tend not to like developers relying on the undocumented "internal behavior" of the manufacturer's system, and so I'm guessing that if you took advantage of this capability, then you would not be allowed to just assume that you code would run at $3080.
Luckily, it is easy to copy your code from whatever address the sector is loaded at, to a fixed location in memory and then just run it from there.
Here is a small example startup that would do that (copying the code to $2680 to run there) ...
org $3080
bsr *+2
pla
dec a
sta <_al
plx
stx <_ah
ldy #$12
sta [_ax],y
txa
iny
sta [_ax],y
tii $0000,$2680,$0780
jmp $2680+$1b
code_at_269b: nopOf course, 25 years later on, we know that Hudson never did create a different IPL, and that the 2nd sector is always-and-forever going to be loaded at $3000 ... so we don't need to bother with the code above. But it was interesting to write it, just to see what it might look like.