SI Registers Detailed

From en64 wiki
Jump to: navigation, search

Taken from Lac's hw-dox.

SI (serial interface)

The SI is very similar to the PI for obvious reasons. It is used mainly for accessing the pifram... which will be dicussed in the next section.

SI DMA transfer

  1. Wait for previous dma transfer to finish (see next explanation)
  1. Write the physical dram address of the dma transfer to SI_DRAM_ADDR_REG
  1. Write PIF_RAM_START to the SI_PIF_ADDR_RD64B_REG or the SI_PIF_ADDR_WR64B_REG, depending on what you wish to do (read or write). This will cause a 64B read or write between pif_ram and rdram.


NOTE: The SI addr must be 2 byte aligned, and the rdram address must 8-byte aligned. Once again make sure you write back the cache lines and invalidate the cache lines if needed, or you will run into trouble.

SI DMA wait

  1. Read SI_STATUS_REG then AND it with 0x3, if its true... then wait until it is not true.

NOTE: Look at RCP.H for more information on the SI_STATUS_REG and the SI in general.

PIF Usage

  • New in v0.7*

In previous versions of this document I regret to say that when I explained how the pif command structure works I really goofed up. A lot of the information was based on speculation and was not tested enough to be proven. In this version I explain a totally different understanding of how the pif command processing is done by the pif chip. So if you are going off the information from previous dox, I seriously suggest you read this section again. It is much more detailed and logical now.

If you have done research and peeked at the RCP.h file you should already know some things about the pif. The SI is used to send commands to the pif ram that tell the pif what to do. The SI is also used to read the results of those commands back. You can tell the pif to do alot of stuff. for instance... reading joysticks, reading mempacks, detecting joysticks, detecting mempacks, activating the rumblepack, detecting the rumble pack, reading cartridge eeprom... etc.

Below is a detailed view of pif command structure processing and an example of using them to perform some operations.

   At First, this is how pif ram should be visualized:

   |{Diagram 1.0}|

   [64byte block] at 0xbfc007c0 (1fc007c0)
   {         
    00 00 00 00 : 00 00 00 00 - 8 bytes 
    00 00 00 00 : 00 00 00 00 - 8 bytes
    00 00 00 00 : 00 00 00 00 - 8 bytes
    00 00 00 00 : 00 00 00 00 - 8 bytes
    00 00 00 00 : 00 00 00 00 - 8 bytes
    00 00 00 00 : 00 00 00 00 - 8 bytes
    00 00 00 00 : 00 00 00 00 - 8 bytes
    00 00 00 00 : 00 00 00 00 - 8 bytes
   }                       ^^pif status/control byte

   Commands are processed from any byte in pifram. ie: The pif chip steps thru each byte to load commands.

   Each command has a structure like so:

   byte 1 (t) = x number of bytes to send to pif chip  
   byte 2 (r) = x number of bytes to recieve from pif chip
   byte 3 (c) = Command type

Command Processing

The pif chip constantly looks at the last byte of pifram and uses it sort of as a semaphore to decide what to do with pifram. This last byte I will refer to as the status byte or the control byte. If the pif chip sees the control byte has been set to 01 (bit 0) it will know there are commands waiting to be processed in pifram. After it has decided this, it goes through each byte of pifram in a scanning process in order to execute commands. The Scanning process is described below:

   while(not end of pifram)
            t = get byte
            if t >= 0 then
                     r get byte
                     send next t number of bytes to pif chip
                     do pif chip command execution
                     if executed then
                        get r bytes from pif chip
                     end if
                     increment channel
            else if t==fe then
                     exit while loop
            end if

   end while

The t value is very important to the processing. If it is a negative value then it does basically nothing but read the next byte into t again.If it is a positive value or zero we know it needs to do something. It now gets the next byte from pifram and puts it into r. r is used later to tell how much data to get back from pifram. Next it sends all the bytes needed for the command to the pif chip... t being the x number of bytes to send. The pif chip now has all the data it needs to _attempt_ to execute a command. If we sent 0 bytes to the pif chip it will not execute a command and we will receive no bytes from the pif chip in r. But the channel counter (I will explain channels later) will increment even if no command was really executed. A t value of 0 is basically a null command. When the pif chip executes certain commands it expects certain limits on values for t and r. Usually these values are fixed. If the values are not what it expects it will attempt to process the command. If it could not process the command it will let you know by setting the r value in pifram with an error value I will describe later. It is a good idea to realize that bits 6 and 7 of the r value are not to be used by the pif command. These are actually the error bits. ie: MASK r &= ~0xC0


   |{Diagram 1.0b}|


           Command Types:
        
         | Command |       Description        |t |r |
         +---------+--------------------------+-----+
         |   00    |   request info (status)  |01|03|
         |   01    |   read button values     |01|04|
         |   02    |   read from mempack slot |03|21|
         |   03    |   write to mempack slot  |23|01|
         |   04    |   read eeprom            |02|08|
         |   05    |   write eeprom           |10|01|
         |   ff    |   reset                  |01|03|
              NOTE: values are in hex

==Channels==

The pif commands operate on certain channels in the n64. The channels can also be refered to as ports. The n64 has 6 channels to my knowledge. The first 4 channels (channels 0-3) are the joystick ports. The last two channels (4 and 5) I am pretty sure are in the cartridge port. Carts that have eeprom have it at either channel 4 or 5 or both. There are some carts that have two eeprom chips in them, and I believe channel 5 is used for the 2nd eeprom in these carts... Although I have not tested this theory.

<pre>
   To get a better understanding of how all this works, here is an example on how to build a command for reading a joystick:

   * Init the joysticks for reading

   |{Diagram 1.1}|

     Send the pif command block to pifram using the SI DMA

     -----------------------------++------------------------------
     such a block to read 4 joys: ||  such a block to read 1 joy:
      [64byte block]              ||   [64byte block]
      {      command  data        ||   {
     joy1  ff 010401 - ffffffff   ||  joy1  ff 010401 - ffffffff
     joy2  ff 010401 - ffffffff   ||        ff ffffff - ffffffff
     joy3  ff 010401 - ffffffff   ||        ff ffffff - ffffffff
     joy4  ff 010401 - ffffffff   ||        ff ffffff - ffffffff
           fe 000000 - 00000000   ||        fe 000000 - 00000000  
           00 000000 - 00000000   ||        00 000000 - 00000000
           00 000000 - 00000000   ||        00 000000 - 00000000
           00 000000 - 00000001   ||        00 000000 - 00000001
      }                           ||    }
     -----------------------------++------------------------------

      After sending this the joystick values will now be updated in pif RAM

NOTE: the ffffffff is put into the data column just for filling the space that the pif chip will write the data to. You can put anything there because the pifchip will never try to process it, because it skips past all bytes it writes the r bytes to.


     0xff 
     |
     0xff is padding so that the joystick values end up in the 2nd column, this is done because it is convenient to align the data when reading the pifram back to rdram.  It is not necessary to align it, so this ff is not really needed. IE: 010401ff would work just fine, but the joystick values would start at the 4th byte rather than the 5th.

     0x010401 is the command that reads the joystick values.
     |
   t 0x01 says we are going to send 1 byte (the command type).
   r 0x04 says we are going to read 4 bytes (into the data column)
   c 0x01 is the command type (read button values).

      Here is the step by step process in which the pif chip processes this
      command block:
      NOTE: channel always starts out at 0.

      1. reads in ff into t
         tx < 0 so it does nothing
      2. reads in 01 into t
      3. reads in 04 into r
      4. send tx number of bytes to pif chip (just send the command 01)
      5. pif chip executes the command sucessfully and sends no error bytes
      6. pif chip sends r bytes back to pifram
      7. pif chip increments the channel.
      8. pif chip now skips over the r bytes it wrote and then
         basically returns to step 1
      9. once it hits fe or is at the end of pifram, it sets the control
         byte to 0 and exits.
         
    * end Init joysticks

    NICE INFO:

     The 0x01 (diagram 1.1) tells the pif there is a new command block to be
     processed.  Without this the command block will not be executed. You will
     notice that the reason for the one being there is actually that it is
     being written to the pif's status control. This may not be actually what
     it is called but it seems to serve a similar function.  This is the same
     byte you are writing to when you initialize the pif (see: * init pif).
     You will also notice that this byte will be set to 0x80 after holding
     down the reset button.  0x80 means the pif is busy. The value will be
     set to 0x00 after you let go of the reset button or .5 seconds passes
     (whichever comes first).
     After this .5 seconds a NMI will be generated which will reset the
     r4300 and the n64.  Also note that this byte is set to 0x00 once a
     command has been executed by the pif.  This is why when you read the pif
     ram after sending a command the last byte is no longer 1, but 0.  If it
     is still 1 after reading it back, then you know your command didnt
     execute.

    * Read Joysticks
        The joy values can be read from the spaces marked by 0xFFFFFFFF in the
        block above.  Of course you must first DMA from pif ram back to rdram.
        Or you can just read the data directly by making a pointer to
        0xbfc007c0 (start of the pif_ram), although I would not recommend that
        method.
        Here would be a sufficient C code to read in a controller's values:

        void siReadJoy(int cont,OSContPad *p)
        {                                     
         unsigned char pif_block[64];
         si_DMA_from_pif (pif_block); 
         memcpy (p,pif_block+((cont*8)+4),4);
        }

        The OSContPad structure is in the libultra header file OS.H

    * end Read Joysticks

    * Detecting if Joysticks are connected

      This is very easy and can be done after you send any command to read
      or write something to the controllers.  Whenever you try and execute a
      command on a channel and that device on the channel (like a joystick)
      is not present the pif will write an error value to the r byte of the
      command that the error occured in. For instance... lets say you did the
      example above and you tried to read controller values.  Well if you read
      the controller values for all four joystick channels you will notice that
      if you don't have a joystick physically plugged in to the port(s) you are
      reading from, then no values will appear.  Well I think this is an obvious
      result.  But also notice that the pif will put an error value into the r
      byte of the command.

      The Error values are as follows:

      0x00 - no error, operation successful.
      0x80 - error, device not present for specified command.
      0x40 - error, unable to send/recieve the number bytes for command type.

      ie: bits 6 and 7 of the r value are never used in commands. MASK: 0xC0

      This would be an example of the result of trying to read 4 controllers
      (like in above example) and only a joystick in port 3 is connected:

   |{Diagram 1.2}|

     -----------------------------------+
      [64byte block] read from pif ram  |
      {    command    data              |
     joy1  ff018401 - ffffffff          <--- 8 is the error code for device
     joy2  ff018401 - ffffffff          |    not present.
     joy3  ff010401 - 00000000          <--- read was successful on this 
     joy4  ff018401 - ffffffff          |    channel, no buttons being pressed
           fe000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
      }                                 |
     -----------------------------------+

      This would be an example of the result of trying to read 5 bytes for the
      read joystick command:  (all 4 joysticks are connected)

   |{Diagram 1.3}|

     -----------------------------------+
      [64byte block] sent to pif ram    |
      {    command    data              |
     joy1  ff010501 - ffffffff          <---
     joy2  ff010501 - ffffffff          <--- note we tried to read 5 instead
     joy3  ff010501 - ffffffff          <--- of 4.  The device only allows you
     joy4  ff010501 - ffffffff          <--- to read 4 bytes with that command
           fe000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000001          |
      }                                 |
     -----------------------------------+
     -----------------------------------+
      [64byte block] read from pif ram  |
      {    command    data              |
     joy1  ff014501 - 00000000          <--- (note that no buttons are being
     joy2  ff014501 - 00000000          <---  pressed on any controller)
     joy3  ff014501 - 00000000          <--- notice the 4. It is the error
     joy4  ff014501 - 00000000          <--- code for send/recieve.
           fe000000 - 00000000          |    
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
      }                                 |
     -----------------------------------+

      NOTE: Even though we tried to read an extra byte for the buttons values
            the button values will still appear... but the error code will
            still be generated because there is only 4 bytes to be read, not
            5.

    * end Detecting if Joysticks are connected 

    * Getting controller status

     0x010300 is the command used to get the controller status.
     |
     0x01 says we are going to send 1 byte (the command type).
     0x03 says we are going to read 3 bytes (into the data column)
     0x00 is the command type (get controller status).

     Here is an example of reading the status from 4 controllers.
     Only the first two controllers are actually plugged in.
     There is a pack in the 1st controller and there is no pack in the second
     controller.

   |{Diagram 1.4}|

     -----------------------------------+
      [64byte block] sent to pif ram    |
      {    command    data              |
     joy1  ff010300 - ffffffff          |
     joy2  ff010300 - ffffffff          |
     joy3  ff010300 - ffffffff          |
     joy4  ff010300 - ffffffff          |
           fe000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000001          |
      }                                 |
     -----------------------------------+
     -----------------------------------+
      [64byte block] read from pif ram  |
      {    command    data              |
     joy1  ff010300 - 050001ff          <--- notice only 3 bytes were read
     joy2  ff010300 - 050002ff          <--- that is why the last byte is 
     joy3  ff018300 - ffffffff          |    still ff                     
     joy4  ff018300 - ffffffff          |                          
           fe000000 - 00000000          |    
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
      }                                 |
     -----------------------------------+

    The first two bytes in the data column is the controller type.  I'm not
    exactly sure what use this is... do steering wheels have a different
    controller type? I don't know.
    The 3rd byte is useful.  Its for detecting if there is something plugged
    into the mempack slot on the controller.
    1 = something is plugged into the mempack slot
    2 = nothing plugged in
    4 = pad address crc from controller slot read/write (mempack slot)

    * end Getting controller status

    * Resetting the controllers

      WARNING: Some of this info could be wrong, I have yet to test fully.

      This command is performed by the osContReset() function in libultra.

      0x0103ff is the command for resetting
      |
    t 0x01 says we are going to send 1 byte (the command type).
    r 0x03 says we are going to read 3 bytes (into the data column)
    c 0xff is the command type (reset).

      As stated in the osContReset() man page... this command will reset all
      the joysticks and return the values to a neutral position.  I know this
      is needed for calibration.  For instance, if you turn on the n64 with
      the analog stick held in an off-center position then the values will
      be off-center until the controller is reset.  What is also nice about
      this command is that it can be used to not only reset the controllers
      but grab the status of the controllers at the same time.  This is why
      we are reading three bytes (just like in the example above). I am not
      sure what happens when you try this command on channels >= 4.
      See Diagram 1.4


    * End Resetting the controllers

                                   


    * reading/writing cart eeprom

      The cart eeprom is better know as the cart sram... its the little
      eeprom chip that is in alot of the 1st generation cartridges and some
      of the newer cartridges.  Although people call it sram, it really isn't.
      Its eeprom, which is accessed much differently that sram.  Reading and
      writing sram is described in the PI section of this document.
      Eeprom is also what is in the mempacks, which is described in the next
      section.  Cart eeprom is written to using pif commands. The way commands
      and data are formatted in pifram is no different than the way that they
      are done for accessing the controller ports.


      The first 4 bytes are zero because this is not a controller command and
      we will not be accessing the 4 joystick channels. IE: when the pif chip
      processes a command block, if it reads a 0 in t then it knows it will
      be executing a NOP command and incrementing the channel counter.

      -Probing the eeprom-

      The first thing you must do is test to see if the eeprom is there.
      Normally you could test if the eeprom is there by just attempting to
      write some bytes to it and reading them back.  Of course we do not want
      to do this because eeprom contains important save-game data we would not
      like to destroy just for a simple test.  So we will have to "probe" the
      eeprom to detect if its there.  You do this in a similar way that you
      get the status of the controllers.

      Here is an example pif block to send to the pif ram to probe for eeprom:

   |{Diagram 1.5}|

      The cartridge is assumed to have 512 bytes of eeprom in it.

      ----------------------------------+
      [64byte block] sent to pif ram    |
      {                                 |
           00000000 - ff010300          <-- this command should look familiar.
           ffffffff - fe000000          |   notice when sending any command   
           00000000 - 00000000          |   for eeprom we should have made
           00000000 - 00000000          |   sure 4 other channels have been 
           00000000 - 00000000          |   processed.
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000001          |
      }                                 |
      ----------------------------------+
      ----------------------------------+
      [64byte block] read from pif ram  |
      {                                 |
           00000000 - ff010300          |
           008000ff - fe000000          <-- this result shows that there is
           00000000 - 00000000          |   an eeprom present.
           00000000 - 00000000          |
           00000000 - 00000000          |    
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
      }                                 |
      ----------------------------------+

      The 3 byte status is read into the left column (3rd word).  
      the 0x8000 from that read tells us that there is eeprom there.  If the
      cartridge did not have any eeprom in it the buffer read from pif ram
      would of looked like:


   |{Diagram 1.6}|

      ----------------------------------+
      [64byte block] read from pif ram  |
      {                                 |
           00000000 - ff018300          <-- tells us there was no eeprom there
           ffffffff - fe000000          |   to probe. (error bits)
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |    
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
      }                                 |
      ----------------------------------+

    -Writing cart eeprom-

      The command for writing the cart eeprom is

     0x0a0105xx
     |
   t 0x0a says we are going to send 10 bytes to the pif (command+offset+data)
   r 0x01 says we are going to get 1 byte (the error byte)
   c 0x05 is the command type (write eeprom)
     xx is the offset to write to
     ^^ this value can differ depending on the size of the eeprom. The offset
      is the number of the 8-byte block to write to. ie: if you have 512 bytes
      of eeprom in the cart, then this value can be anywhere between 0x0 and
      0x40.

   |{Diagram 1.7}|

      The cartridge is assumed to have 512 bytes of eeprom in it.

      ----------------------------------+
      [64byte block] sent to pif ram    |
      {                                 |
           00000000 - 0a010521          <-- this command will write the next  
           deadbeef - a5b6c7d8          |   8 bytes to block 0x21 in eeprom.  
           ffffffff - fe000000          |   
           00000000 - 00000000          |   
           00000000 - 00000000          |    
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000001          |
      }                                 |
      ----------------------------------+
      ----------------------------------+
      [64byte block] read from pif ram  |
      {                                 |
           00000000 - 0a010521          |                                     
           deadbeef - a5b6c7d8          |                                     
           00ffffff - fe000000          <-- the 00 written notifies that the
           00000000 - 00000000          |   eeprom was written to.  This value
           00000000 - 00000000          |   is that 1 extra error byte that 
           00000000 - 00000000          |   the command specifies.
           00000000 - 00000000          |
           00000000 - 00000000          |
      }                                 |
      ----------------------------------+


    -Reading cart eeprom-

      The command for reading the cart eeprom is
     
     0x020804xx 
     |
   t 0x02 says we are going to send 2 bytes to the pif (command+offset)
   r 0x08 says we are going to get 8 bytes (1 block read from eeprom)
   c 0x04 is the command type (read eeprom)
     xx is the offset to read from
     ^^ this value can differ depending on the size of the eeprom. The offset
      is the number of the 8-byte block to read from. ie: if you have 512
      bytes of eeprom in the cart, then this value can be anywhere between
      0x0 and 0x40.

   |{Diagram 1.8}|

      The cartridge is assumed to have 512 bytes of eeprom in it.

      ----------------------------------+
      [64byte block] sent to pif ram    |
      {                                 |
           00000000 - 02080409          <-- this command will read 0x08 bytes 
           ffffffff - fe000000          |   from block 0x09 in eeprom.
           00000000 - 00000000          |   
           00000000 - 00000000          |   
           00000000 - 00000000          |    
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000001          |
      }                                 |
      ----------------------------------+
      ----------------------------------+
      [64byte block] read from pif ram  |
      {                                 |
           00000000 - 02080409          |                                     
           deadbeef - a5b6c7d8          <-- the eight bytes read are stored   
           00000000 - 00000000          |   here.
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
           00000000 - 00000000          |
      }                                 |
      ----------------------------------+

    * end reading/writing cart eeprom


    * reading/writing mempack port

      Important NOTE:   As far as I know... mempack eeprom can be only 32k in
                        size.  Every address beyond 32768 is out of the
                        mempack address range and is most likely data not
                        meant for mempack eeprom... but most likely meant for
                        the Rumblepack or some other peripheral that is
                        connected to the controller.


      The command for reading from the mempack is

    
     0x032102 xxxx 
     |
 t 0x03 says we are going to send 3 bytes to the pif (command+16bit_offset)
        NOTE: the offset also contains a 5-bit address CRC. The offset must
              be aligned on a 32 byte boundry, so the address crc is in the
              low 5 bits. Also the address must be shifted right 5 bits. The
              address is really similar to the cart eeprom address in that it
              is an address to a block, but in this case it is a 32 byte
              block.
 r 0x21 says we are going to get 33 bytes, that is one 32-byte-block read from
        the mempack slot + 1 byte for the data CRC (described later)
 c 0x02 is the command type (read mempack slot)
     xxxx is the offset to read from
        


      The command for write to the mempack is

     230103xxxx
     |
 t 0x23 says we are going to send 35 bytes to the pif
        (command + 2-bytes-offset + data)
        NOTE: the offset also contains a 5-bit address CRC. The offset must
              be aligned on a 32 byte boundry, so the address crc is in the
              low 5 bits. Also the address must be shifted right 5 bits. The
              address is really similar to the cart eeprom address in that it
              is an address to a block, but in this case it is a 32 byte
              block.
 r 0x01 says we are going to get 1 byte for the data CRC (described later)
 c 0x03 is the command type (read mempack slot)
     xxxx is the offset to read from

    * end reading/writing mempack port

    * mempack port checksum

      Whenever you write / read data you must include an address and data
      CRC. These are stored in two different locations in the command
      structure (see the two commands above).
      These CRC algorithms are described below.
      NOTE: this is the data CRC when something is plugged into the mempack
      port.  The data you get read or write to the mempack port obvious will
      need or have a data CRC... but when something is not plugged into the
      mempack port, then the CRC is calculated the same way except the final
      8-bit result is NOT'd. You might wonder why there would even be a CRC
      when reading from the mempack port and nothing is plugged in.  Well
      basically when nothing is plugged in, data is still read, but it is not
      valid data. This data is usually all 0's. The data CRC algo is still
      calculated but the result is of course NOT'd to let you know that the
      data is erronous.


*******Data CRC routine (written in Pascal for pseudo-code purposes) ********

function ContDataCrc (data: PByteArray): byte;  { PByteArray is a byte pointer }
var
  temp,temp2   : byte;
  i,j          : Integer;
begin
      temp:=0;
      for i := 0 to 32
         do begin
              for j := 7 downto 0
              do begin
                   if ((temp and $80)<>0) then temp2 := $85 else temp2 := $00;
                   temp := temp shl 1;
                   if (i = 32)
                   then begin
                          temp := temp or 0;
                        end
                   else begin
                          if (((data[i]) and ($01 shl j))<>0)
                          then temp:=(temp or 1) else temp:=(temp or 0);
                        end;
                   temp := (temp xor temp2);
              end;
         end;

        ContDataCrc:=temp;
end;

      Address CRC routine:

*******Addr CRC routine (written in Pascal for pseudo-code purposes) ********

function PackAddrCRC (int16 addr): byte;
var
  t,t2   : byte;
  i,j    : Integer;
begin
        t:=0;
        for i := 0 to 15
          do begin
               if ((t and $10)<>0) then t2 := $15 else t2 := $00;
               t := t shl 1;
               if ((addr and $400)<>0) then t := (t or $1)
               addr := addr shl 1;
               t := t xor t2;
          end
        PackAddrCRC:=(t and $1f);
end;

    * end mempack port checksum


    * Rumblepak

      The Rumblepack, like the Mempack connects to the mempack port on the
      bottom off the n64 controller.  Therefore you read/write to the mempack
      port in order to gain access to the rumble pack.

      -Checking for connection-

      In order to check if what is plugged into the mempack port is a rumble
      pack or a mempack, you need to do the following:

      1. Use the controller command to get the status (see Diagram 1.4)
         This way you will at least know something is plugged into the port.
         Or you could just skip to step two and if the data crc you get back
         is NOT'd you will know nothing is plugged in.
      2. Using the mempack read command, read offset block 0x400.  This
         offset would be written as 0x8001 in the actual command.  Because,
         remember you are storing the address crc in the lower 5 bits.
      3. If the data you get is all 0x80's then you know a Rumblepack is
         there. If the data is 0x00's then its not a Rumblepack and is most
         likely a Mempack.

      -Rumbling-

      The Rumblepack rumbles based on two values... OFF and ON.  There is no
      intensity values involved in rumbling.  The whole idea is that the
      slower you turn it off and on, the higher the intensity rumble and vice
      versa.
      To turn the Rumblepack on you simply write a 32 byte block of 01's
      to offset 0x600. And to turn it off you write 00's instead. Its as
      simple as that... But remember you are using the standard mempack
      port writing commands so all the rules apply (CRC'ing etc...).

    * end Rumblepak

to format further later. 2lazy