Difference between revisions of "SMPC"

From Yabause
Jump to: navigation, search
m (Small formatting change)
(Describe the 3-line handshake protocol, rework NiGHTS pad section accordingly)
 
Line 1,208: Line 1,208:
  
 
A small delay is needed between changing the state of PDR1 and reading the new button data. The pad I have seems to need no delay, but perhaps 3rd party controllers using slower logic may need more time before they return new data after switching the input source.
 
A small delay is needed between changing the state of PDR1 and reading the new button data. The pad I have seems to need no delay, but perhaps 3rd party controllers using slower logic may need more time before they return new data after switching the input source.
 +
 +
===Three-line Handshake===
 +
 +
Some peripherals use what Sega call a "3-line handshake" protocol for data transfer. In this protocol, TH and TR are outputs, and TL and D3-D0 are inputs. TH acts like an active low chip select for the connected controller, and TR acts like a data toggle. TL acts like an acknowledge and data is returned on D3-D0. The data on D3-D0 is valid when TL equals TR. When TL does not equal TR, the value of D3-D0 is undefined.
 +
 +
Assuming DDR1=0x60, PDR1=0x00, IOSEL=0x00, here's how to identify a 3-line handshake device:
 +
 +
{| border="1"
 +
!Write to PDRx
 +
!Read from PDRx
 +
|-
 +
|60
 +
|D1 : 0, D0 : 1
 +
|-
 +
|20
 +
|D1 : 0, D0 : 1
 +
|}
 +
 +
To read the device, start by setting TH and TR to 1. Then set both TH and TR to 0, and wait until TL becomes 0. The first nibble of data is now available on D3-D0. Next, set TR to 1 and wait until TL becomes 1, then read the next nibble. Repeat this until all the data is read. Once finished, set TH and TR to 1.
 +
 +
The first returned nibble is the device ID, the next nibble indicates the number of data bytes following. Note that this may not be true of all devices.
  
 
===NiGHTS Analog Pad===
 
===NiGHTS Analog Pad===
Line 1,217: Line 1,238:
 
====Analog mode====
 
====Analog mode====
  
The pad has some hardware that does the A-D conversion of the analog inputs and sends the data in nibble sized units through the I/O port. I'll call this hardware a state machine, though it could be something more complex like a microcontroller. (one of the chips is labeled 8751, which is the product number of a popular 8-bit MCU Sega has used in the past)
+
The pad has some hardware that does the A-D conversion of the analog inputs and sends the data in nibble sized units through the I/O port using the 3-line handshake protocol as described above.
  
Pins TH and TR are outputs, which are used to initialize the state machine and change states. Pin TL and D3-D0 are inputs, which give the machine's state and data values.
+
This table lists the values returned by the controller when idle:
 
+
The state machine is initialized by setting TH and TR to '1'. States are stepped through by leaving TH at '0' and setting TR to '0' then '1'.
+
 
+
Assuming DDR1=0x60, PDR1=0x00, IOSEL=0x00, here's a description of how to poll the controller:
+
  
 
{| border="1"
 
{| border="1"
!Write to PDRx
+
!Nibble
 
!Read from PDRx
 
!Read from PDRx
 
!Description
 
!Description
!Notes
 
 
|-
 
|-
|60
+
|1
|11
+
|1
|Probably indicates 'idle' state. Initializes transfer.
+
|Device ID?
|Leading 00 write after 60 is necessary to get 01 value below, otherwise a state is missed and some values fluctuate.
+
 
|-
 
|-
|00
+
|2
|11
+
|6
|Probably indicates 'idle' state
+
|Data bytes?
|N/A
+
 
|-
 
|-
|00
+
|3
|01
+
|F
|ID? (01 for analog mode, 00 for digital mode)
+
|Direction keys: right, left, down, up
|N/A
+
 
|-
 
|-
|20
+
|4
|16
+
|F
|ID? (16 for analog mode, 12 for digital mode)
+
|N/A
+
|-
+
|00
+
|0F
+
|Direction keys: right, left, down up
+
|N/A
+
|-
+
|20
+
|1F
+
 
|Buttons: Start, A, C, B
 
|Buttons: Start, A, C, B
|N/A
 
 
|-
 
|-
|00
+
|5
|0F
+
|F
 
|Buttons: Right shoulder, X, Y, Z
 
|Buttons: Right shoulder, X, Y, Z
|N/A
 
 
|-
 
|-
|20
+
|6
|1F
+
|F
 
|Buttons: Left shoulder, 1, 1, 1
 
|Buttons: Left shoulder, 1, 1, 1
|N/A
 
 
|-
 
|-
|00
+
|7
|08
+
|8
 
|Analog pad X axis MSB
 
|Analog pad X axis MSB
|N/A
 
 
|-
 
|-
|20
+
|8
|10
+
|0
 
|Analog pad X axis LSB
 
|Analog pad X axis LSB
|N/A
 
 
|-
 
|-
|00
+
|9
|08
+
|8
 
|Analog pad Y axis MSB
 
|Analog pad Y axis MSB
|N/A
 
 
|-
 
|-
|20
+
|A
|10
+
|0
 
|Analog pad Y axis LSB
 
|Analog pad Y axis LSB
|N/A
 
 
|-
 
|-
|00
+
|B
|00
+
|0
 
|Right shoulder MSB
 
|Right shoulder MSB
|N/A
 
 
|-
 
|-
|20
+
|C
|10
+
|0
 
|Right shoulder LSB
 
|Right shoulder LSB
|N/A
 
 
|-
 
|-
|00
+
|D
|00
+
|0
 
|Left shoulder MSB
 
|Left shoulder MSB
|N/A
 
 
|-
 
|-
|20
+
|E
|10
+
|0
 
|Left shoulder LSB
 
|Left shoulder LSB
|N/A
 
 
|-
 
|-
|00
+
|F
|00
+
|0
|No data (indicates end of transfer?)
+
|No data
|N/A
+
 
|-
 
|-
|20
+
|10..n
|11
+
|1
|Probably indicates 'idle' state
+
|The controller stops sending data, TL stays at 1
|N/A
+
|-
+
|00
+
|11
+
|Probably indicates 'idle' state
+
|* Any further 20/00 writes return 11, no more data returned.
+
|-
+
|60
+
|11
+
|Probably indicates 'idle' state. Ends transfer
+
|N/A
+
 
|}
 
|}
 
The data in the above table shows the value read from PDR with bits 7,6,5 removed. Bit 4 is TL, which is an output from the state machine and toggles between 1 and 0 to show the current state. The lower four bits are D3-D0 which is the actual data being returned.
 
  
 
The digital buttons return '0' when pressed and '1' when released.
 
The digital buttons return '0' when pressed and '1' when released.
  
The two shoulder buttons return an unsigned value of $00 (not pressed) to $FF (fully pressed)
+
The two shoulder buttons return an unsigned value of $00 (not pressed) to $FF (fully pressed). The digital shoulder button bits return '0' when the analog value goes above around $90, and remain at that value until the analog value drops to below around $56.
  
 
The analog pad axis return $80,$80 at the center, $00 at the topmost or leftmost positions, and $FF at the bottommost or rightmost positions.
 
The analog pad axis return $80,$80 at the center, $00 at the topmost or leftmost positions, and $FF at the bottommost or rightmost positions.
  
 
The analog pad is in a circular shape, so some settings (such as $00,$FF for all the way left and down) are impossible to get.
 
The analog pad is in a circular shape, so some settings (such as $00,$FF for all the way left and down) are impossible to get.
 
A delay between writing and then reading PDR is absolutely required. About ten NOPs seems to be enough. If you do not delay, then the data returned is almost random. (probably a corruption of various return values from the wrong states being sent at the wrong time)
 
  
 
====Digital mode====
 
====Digital mode====
  
In this mode the analog thumb pad is disabled, and the shoulder buttons return digital values only. The pad is programmed the same was as before, and here's another table:
+
In this mode the analog thumb pad is disabled, and the shoulder buttons return digital values only. The pad is programmed the same way as before, and here's another table:
  
 
{| border="1"
 
{| border="1"
!Write to PDRx
+
!Nibble
 
!Read from PDRx
 
!Read from PDRx
 
!Description
 
!Description
!Notes
 
 
|-
 
|-
|60
+
|1
|11
+
|0
|Probably indicates 'idle' state. Initializes transfer.
+
|Device ID?
|Leading 00 write after 60 is necessary to get 00 value below, otherwise a state is missed and some values fluctuate.
+
 
|-
 
|-
|00
+
|2
|11
+
|2
|Probably indicates 'idle' state
+
|Data bytes?
|N/A
+
 
|-
 
|-
|00
+
|3
|00
+
|F
|ID? (01 for analog mode, 00 for digital mode)
+
|Direction keys: right, left, down, up
|N/A
+
 
|-
 
|-
|20
+
|4
|12
+
|F
|ID? (16 for analog mode, 12 for digital mode)
+
|N/A
+
|-
+
|00
+
|0F
+
|Direction keys: right, left, down up
+
|N/A
+
|-
+
|20
+
|1F
+
 
|Buttons: Start, A, C, B
 
|Buttons: Start, A, C, B
|N/A
 
 
|-
 
|-
|00
+
|5
|0F
+
|F
 
|Buttons: Right shoulder, X, Y, Z
 
|Buttons: Right shoulder, X, Y, Z
|N/A
 
 
|-
 
|-
|20
+
|6
|1F
+
|F
 
|Buttons: Left shoulder, 1, 1, 1
 
|Buttons: Left shoulder, 1, 1, 1
|N/A
 
 
|-
 
|-
|00
+
|7..n
|11
+
|1
|Probably indicates 'idle' state
+
|The controller stops sending data, TL stays at 1
|Any further 20/00 writes return 11, no more data returned.
+
|-
+
|60
+
|11
+
|Probably indicates 'idle' state. Ends transfer
+
|N/A
+
 
|}
 
|}
  
Again, a delay between PDRx accesses is necessary in this mode as well.
+
When in digital mode, the pad does not return the same kind of data that the regular Saturn 6-button pads do, so it has to be read using the 3-line handshake protocol. So don't think of digital mode as being 100% compatible with a standard Saturn controller.
 
+
When in digital mode, the pad does not return the same kind of data that the regular Saturn 6-button pads do, so it has to be read by changing states. So don't think of digital mode as being 100% compatible with a standard Saturn controller.
+

Latest revision as of 16:56, 19 June 2011

The SMPC (System Management & Peripheral Control) is a Hitachi 4-bit MCU with built-in program ROM. The actual part number is HD404920FS, but the chip is branded with a Sega custom part number of 315-5744.

Tasks

The SMPC carries out the following tasks:

  • Turn on/off other parts of the system. (CPU's, custom chips, etc.)
  • Maintain internal timekeeping functions.
  • Change the system clock speed generated by the PLL.
  • Poll peripherals in the I/O ports.
  • Provide SH-2 interface to I/O ports for direct programming.


The SMPC is battery backed, and earlier models of the Saturn have a button in the battery compartment to force a SMPC reset.

Memory map

Address Name 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 What's there
0x20100001 IREG0 Input registers for command issuing. Whatever data the SMPC needs for processing command goes here.
0x20100003 IREG1 See IREG0
0x20100005 IREG2 See IREG0
0x20100007 IREG3 See IREG0
0x20100009 IREG4 See IREG0
0x2010000B IREG5 See IREG0
0x2010000D IREG6 See IREG0
0x2010001F COMREG The command that's supposed to be issued by the SMPC
0x20100021 OREG0 Ouput Register for the command. If it supports it, it'll output any return data here
0x20100023 OREG1 See OREG0
0x20100025 OREG2 See OREG0
0x20100027 OREG3 See OREG0
0x20100029 OREG4 See OREG0
0x2010002B OREG5 See OREG0
0x2010002D OREG6 See OREG0
0x2010002F OREG7 See OREG0
0x20100031 OREG8 See OREG0
0x20100033 OREG9 See OREG0
0x20100035 OREG10 See OREG0
0x20100037 OREG11 See OREG0
0x20100039 OREG12 See OREG0
0x2010003B OREG13 See OREG0
0x2010003D OREG14 See OREG0
0x2010003F OREG15 See OREG0
0x20100041 OREG16 See OREG0
0x20100043 OREG17 See OREG0
0x20100045 OREG18 See OREG0
0x20100047 OREG19 See OREG0
0x20100049 OREG20 See OREG0
0x2010004B OREG21 See OREG0
0x2010004D OREG22 See OREG0
0x2010004F OREG23 See OREG0
0x20100051 OREG24 See OREG0
0x20100053 OREG25 See OREG0
0x20100055 OREG26 See OREG0
0x20100057 OREG27 See OREG0
0x20100059 OREG28 See OREG0
0x2010005B OREG29 See OREG0
0x2010005D OREG30 See OREG0
0x2010005F OREG31 See OREG0
0x20100061 SR Status Register
0x20100063 SF Status Flag. Shows the status of the SMPC command. Normally you set this to 1 when issuing out a command, and then the SMPC clears it when it's finished.
0x20100075 PDR1 Port Data Register for Port 1.
0x20100077 PDR2 Port Data Register for Port 2.
0x20100079 DDR1 Data Direction Register for Port 1. Controls direction of each bit in PDR(they can either be read or write).
0x2010007B DDR2 Data Direction Register for Port 2. See DDR1.
0x2010007D IOSEL Input/Output Select Register. Use this to control whether the SMPC automatically polls the peripheral port or whether it's done manually through the DDR/PDR registers
0x2010007F EXLE External Latch Enable Register. Enables input from the VDP2 external latch or peripheral data bit 6 to trigger SCU Pad interrupt.


Commands

Command Value Description Input registers Output registers
MSHON 0x0 Resets and enables the SH-2 Master CPU. None OREG31
SSHON 0x2 Resets and enables the SH-2 Slave CPU. None OREG31
SSHOFF 0x3 Disables the SH-2 Slave CPU. None OREG31
SNDON 0x6 Resets and enables the Motorola C68K (sound) CPU. None OREG31
SNDOFF 0x7 Disables the Motorola C68K (sound) CPU. None OREG31
CDON 0x8 Resets and enables the CD Block. None OREG31
CDOFF 0x9 Disables the CD Block. None OREG31
NETLINKON 0xA Resets and enables Netlink execution. None OREG31
NETLINKOFF 0xB Disables Netlink execution. None OREG31
SYSRES 0xD Resets the System. None OREG31
CKCHG352 0xE Changes the system clockspeed None OREG31
CKCHG320 0xF Changes the system clockspeed None OREG31
INTBACK 0x10 Fetches the SMPC status and peripheral data. IREG0~IREG2 OREG0~OREG31
SETTIME 0x16 Sets the date and time for the RTC IREG0~IREG6 OREG31
SETSMEM 0x17 Sets the 4-byte battery-backed memory contained on the SMPC(which is used by the bios for language settings, etc. IREG0~IREG3 OREG31
NMIREQ 0x18 Sends an NMI request to the Master SH2 None OREG31
RESENAB 0x19 Enables NMI requests to be sent when the Reset button is pressed. None OREG31
RESDISA 0x1A Disables NMI requests to be sent when the Reset button is pressed. None OREG31

I/O Ports

The Saturn has two 7-bit I/O ports. Here's a diagram of the port itself and a list of pin assignments. The names on the left are the Sega Genesis style naming conventions.

Left            Right
 .-----------------.
| 1 2 3 4 5 6 7 8 9 |
+-=-=-=-=-=-=-=-=-=-+
Pin 1 - +5v
Pin 2 - D2         (Left)
Pin 3 - D3         (Right)
Pin 4 - D4         (TL)
Pin 5 - D5         (TR)
Pin 6 - D6         (TH)
Pin 7 - D0         (Up)
Pin 8 - D1         (Down)
Pin 9 - Ground


SMPC Control Mode

Finish me


SH-2 Direct Mode

The SMPC uses the following registers for I/O port control:

0x20100075 - PDR1 I/O port #1 pin output level (1=high, 0=low)
0x20100077 - PDR2 I/O port #2 pin output level (1=high, 0=low)
0x20100079 - DDR1 I/O port #1 pin direction (1=output, 0=input)
0x2010007B - DDR2 I/O port #2 pin direction (1=output, 0=input)

For each register, bits 6-0 correspond to TH,TR,TL,D3,D2,D1,D0. Bit 7 is unused and will latch whatever value was written to it.

Pins defined as an output through DDRx will return the value you set in PDRx. Pins defined as an input return whatever value was sent to that pin by the peripheral in use.

For an empty I/O port, each bit returns 1. (so $7F would be read from PDRx assuming the software hadn't set bit 7 beforehand)

0x2010007D - IOSEL
D1 - I/O port #2
D0 - I/O port #1

The lower two bits direct the SMPC to poll or ignore the corresponding I/O port. (0= poll, 1= ignore)

This doesn't stop you from doing direct I/O anyway, but is used to prevent a conflict since the SMPC will attempt to poll it at the same time.

Unused bits latch whatever value was last written.

Saturn Control Pad

The standard Saturn control pad can be read using direct I/O. To do this, set up the following registers like so:

DDR1   = 0x60      Port 1 - pins TH,TR as outputs, TL,D3-D0 are inputs
DDR2   = 0x60      Port 2 - pins TH,TR as outputs, TL,D3-D0 are inputs
IOSEL  = 0x03      Use direct I/O mode instead of SMPC polling

You can then get pad data by writing a 2-bit value to the TH,TR pins and reading the lower four bits of either input port. The values read back are the following:

When PDRx = 0x60

D4 : Always '1'
D3 : Left shoulder button (0=pressed, 1=released)
D2 : Always '1'
D1 : Always '0'
D0 : Always '0'

When PDRx = 0x40

D4 : Always '1'
D3 : Start button (0=pressed, 1=released)
D2 : Button A (0=pressed, 1=released)
D1 : Button C (0=pressed, 1=released)
D0 : Button B (0=pressed, 1=released)

When PDRx = 0x20

D4 : Always '1'
D3 : Right direction (0=pressed, 1=released)
D2 : Left direction (0=pressed, 1=released)
D1 : Down direction (0=pressed, 1=released)
D0 : Up direction (0=pressed, 1=released)

When PDRx = 0x00

D4 : Always '1'
D3 : Right shoulder button (0=pressed, 1=released)
D2 : Button X (0=pressed, 1=released)
D1 : Button Y (0=pressed, 1=released)
D0 : Button Z (0=pressed, 1=released)

A small delay is needed between changing the state of PDR1 and reading the new button data. The pad I have seems to need no delay, but perhaps 3rd party controllers using slower logic may need more time before they return new data after switching the input source.

Three-line Handshake

Some peripherals use what Sega call a "3-line handshake" protocol for data transfer. In this protocol, TH and TR are outputs, and TL and D3-D0 are inputs. TH acts like an active low chip select for the connected controller, and TR acts like a data toggle. TL acts like an acknowledge and data is returned on D3-D0. The data on D3-D0 is valid when TL equals TR. When TL does not equal TR, the value of D3-D0 is undefined.

Assuming DDR1=0x60, PDR1=0x00, IOSEL=0x00, here's how to identify a 3-line handshake device:

Write to PDRx Read from PDRx
60 D1 : 0, D0 : 1
20 D1 : 0, D0 : 1

To read the device, start by setting TH and TR to 1. Then set both TH and TR to 0, and wait until TL becomes 0. The first nibble of data is now available on D3-D0. Next, set TR to 1 and wait until TL becomes 1, then read the next nibble. Repeat this until all the data is read. Once finished, set TH and TR to 1.

The first returned nibble is the device ID, the next nibble indicates the number of data bytes following. Note that this may not be true of all devices.

NiGHTS Analog Pad

The controller that comes packaged with the NiGHTS video game has the same buttons as a standard controller, but also has an analog thumb pad, and the two shoulder buttons return analog as well as digital values.

A switch on the pad selects analog pad mode and digital pad mode, I'll describe how both work.

Analog mode

The pad has some hardware that does the A-D conversion of the analog inputs and sends the data in nibble sized units through the I/O port using the 3-line handshake protocol as described above.

This table lists the values returned by the controller when idle:

Nibble Read from PDRx Description
1 1 Device ID?
2 6 Data bytes?
3 F Direction keys: right, left, down, up
4 F Buttons: Start, A, C, B
5 F Buttons: Right shoulder, X, Y, Z
6 F Buttons: Left shoulder, 1, 1, 1
7 8 Analog pad X axis MSB
8 0 Analog pad X axis LSB
9 8 Analog pad Y axis MSB
A 0 Analog pad Y axis LSB
B 0 Right shoulder MSB
C 0 Right shoulder LSB
D 0 Left shoulder MSB
E 0 Left shoulder LSB
F 0 No data
10..n 1 The controller stops sending data, TL stays at 1

The digital buttons return '0' when pressed and '1' when released.

The two shoulder buttons return an unsigned value of $00 (not pressed) to $FF (fully pressed). The digital shoulder button bits return '0' when the analog value goes above around $90, and remain at that value until the analog value drops to below around $56.

The analog pad axis return $80,$80 at the center, $00 at the topmost or leftmost positions, and $FF at the bottommost or rightmost positions.

The analog pad is in a circular shape, so some settings (such as $00,$FF for all the way left and down) are impossible to get.

Digital mode

In this mode the analog thumb pad is disabled, and the shoulder buttons return digital values only. The pad is programmed the same way as before, and here's another table:

Nibble Read from PDRx Description
1 0 Device ID?
2 2 Data bytes?
3 F Direction keys: right, left, down, up
4 F Buttons: Start, A, C, B
5 F Buttons: Right shoulder, X, Y, Z
6 F Buttons: Left shoulder, 1, 1, 1
7..n 1 The controller stops sending data, TL stays at 1

When in digital mode, the pad does not return the same kind of data that the regular Saturn 6-button pads do, so it has to be read using the 3-line handshake protocol. So don't think of digital mode as being 100% compatible with a standard Saturn controller.