Peripheral ID
Many of the things you can plug into the Mega Drive have an "ID", which is a four bit number you can use to identify a peripheral before you use it. Most devices Sega released on Mega Drive and Saturn can be identified this way.
The peripheral ID is a side effect of the protocol used to talk with the device, so not everything has an ID. Peripherals without an ID need to be detected in their own unique way.
How to get the ID
To get the peripheral ID, first configure the I/O control port so that bit 6 is output and the rest are input (in other words, the same way as for setting up a controller). Then read the peripheral twice, once with bit 6 = 1 and once with bit 6 = 0. The values of bits 3-0 are used to determine the ID.
Remember to pause the Z80 while accessing the I/O port.
The peripheral ID consists of four bits (where each bit is obtained by ORing two bits read back from the data port). They're as follows:
Peripheral ID | Write this | Read back from port |
---|---|---|
ID bit 3 | $40 | bit 3 OR bit 2 |
ID bit 2 | $40 | bit 1 OR bit 0 |
ID bit 1 | $00 | bit 3 OR bit 2 |
ID bit 0 | $00 | bit 1 OR bit 0 |
The following routine shows how you could do it (using look-up tables to handle both ORs of each read, since it honestly makes the code simpler):
; Subroutine to get peripheral ID
; Pointer to data port in a0, result in d0
; d1 and a1 get trashed
GetPeripheralId:
; Make sure pin direction is
; set correctly for this
FastPauseZ80
move.b #$40, 6(a0)
; Get bits 3-2 of peripheral ID
move.b #$40, (a0)
nop
nop
lea @Table1(pc), a1
moveq #$0F, d1
and.b (a0), d1
move.b (a1,d1.w), d1
; Get bits 1-0 of peripheral ID
move.b #$00, (a0)
nop
nop
lea @Table2(pc), a1
moveq #$0F, d0
and.b (a0), d0
move.b (a1,d0.w), d0
; Leave peripheral alone
move.b #$40, (a0)
ResumeZ80
; Put bits together
or.b d1, d0
; Result is in d0
rts
; Look-up table to extract ID
; bits from the first read
@Table1:
dc.b %0000,%0100,%0100,%0100
dc.b %1000,%1100,%1100,%1100
dc.b %1000,%1100,%1100,%1100
dc.b %1000,%1100,%1100,%1100
; Look-up table to extract ID
; bits from the second read
@Table2:
dc.b %0000,%0001,%0001,%0001
dc.b %0010,%0011,%0011,%0011
dc.b %0010,%0011,%0011,%0011
dc.b %0010,%0011,%0011,%0011
Beware! Since we messed with the data port the peripheral now may need some time before returning correct data. This is true even for controllers (as this interferes with the 6-button controller sequence). If you retrieved the ID you'll want to save it and wait for the next frame before starting to use the peripheral. You'll know if it got unplugged when you try to use it and it returns incorrect data, anyway.
Known peripheral IDs
The following values are known to match existing peripherals:
ID | Peripheral |
---|---|
1111 ($0F ) | (undetectable) |
1101 ($0D ) | Mega Drive controller |
1100 ($0C ) | Mega Drive controller (see note) |
1011 ($0B ) | Saturn controller |
1010 ($0A ) | Printer |
0111 ($07 ) | Sega multitap |
0101 ($05 ) | Other Saturn peripherals |
0011 ($03 ) | Mouse |
0001 ($01 ) | Justifier |
0000 ($00 ) | Menacer |
The following peripherals can't be detected this way, and you need to try interacting with them directly and see if they return the expected data to tell if they're there:
- Master System controller
- Master System trackball
- Master System paddle
- EA multitap
- Ten Key Pad
- Activator
- Miracle Piano keyboard
- XBAND keyboard
Iwis says
The ID 1100
can happen if the console is reset in the middle
of trying to read a 6-button controller (in which case it may end up
returning the extra buttons and trip the check).