While implementing mapper 16 I was using Disch's mapper documents as a guide. I find these documents infinitely useful and enjoy his humor when it comes to some of the more ridiculous mappers. I was reading through mapper 16 and it struck me that I'd seen those patterns for accessing the EEPROM elsewhere in my life. This might be new information or it might have been discovered/discussed/closed already and Disch just never updated his mapper docs -- or I failed to download an update? Anyway...I think it's worth noting and perhaps even updating Disch's mapper 16 document.
The EEPROM protocol is Inter-Integrated Circuit (I2C). I've written quite a damn few I2C drivers for various things. The most common being I2C SEEPROMs. I2C SEEPROMs have a very recognizeable 9-beat bit pattern with the first nibble of the first byte after a START condition being 1010, followed by a 3-bit device address, followed by a 0 [write] or 1 [read] command bit. The ninth bit is the ACK bit, where the device receiving the data drives the bus to acknowledge receipt.
I've implemented the I2C protocol for the SEEPROM in mapper 16 using the following method. It works well with Dragon Ball Z Gaiden and I'm going to try it with others shortly.
Writes to the 800D register and reads from anywhere in 6000-7FFF cause the two-wire I2C bus to transition in the various patterns required to drive the I2C protocol.
I2C requires a START condition before any activities. A START is a negative edge on SDA while SCK is high. This is generated [again, observations from Dragon Ball Z Gaiden -- I'll update this post if I find different sequences elsewhere] by the following writes to 800D:
Clearly, SDA goes low while SCK is high.
Transfers consist of 8 data beats and an ACK beat. The 8 data beats are exactly as Disch describes. To send a '1' bit to the SEEPROM the following writes to 800D are done:
Data is set high before the postive edge of SCK which is when the data is clocked into the SEEPROM.
Similarly to write a '0' bit:
A 0-bit is clocked into the SEEPROM on the positive edge of SCK.
The ninth beat or the ACK beat is different depending on whether the master [the 2A03] is writing a byte to the SEEPROM or reading a byte from the SEEPROM. If it's writing, it performs a read to make sure the SEEPROM drives SDA low to acknowledge the byte transfer. If it's reading, the 2A03 either drives the bit low to indicate it'll be reading more, or drives it high to indicate it's done reading.
Transfers are completed with a STOP, which is a positive edge on SDA while SCK is high.
Clearly, SDA goes high while SCK is high.
Reads from the SEEPROM are done by generating a SCK positive edge then reading from 6000-7FFF. It is typical for the SDA/SCK lines to be pulled high in I2C so SDA is sent to 1. Typically SDA would be looked at directly for the SEEPROM to drive it to 0 or leave it at 1 but in this case the read-out bit goes to D4.
The I2C SEEPROM protocol is clearly described in many datasheets for SEEPROMs. One example I used while writing my mapper 16 EEPROM implementation is this one.
Hope this information helps someone. It certainly made implementing the thing feel a heck of a lot less hacky to me. I'm not ready to push it yet but mapper 16 support will be in the next NESICIDE release.
The EEPROM protocol is Inter-Integrated Circuit (I2C). I've written quite a damn few I2C drivers for various things. The most common being I2C SEEPROMs. I2C SEEPROMs have a very recognizeable 9-beat bit pattern with the first nibble of the first byte after a START condition being 1010, followed by a 3-bit device address, followed by a 0 [write] or 1 [read] command bit. The ninth bit is the ACK bit, where the device receiving the data drives the bus to acknowledge receipt.
I've implemented the I2C protocol for the SEEPROM in mapper 16 using the following method. It works well with Dragon Ball Z Gaiden and I'm going to try it with others shortly.
Writes to the 800D register and reads from anywhere in 6000-7FFF cause the two-wire I2C bus to transition in the various patterns required to drive the I2C protocol.
Code:
800D:
D7 is unknown -- it changes seemingly when there's a READ coming up next? Perhaps for some kind of bus conflict prevention...any thoughts?
D6 is SDA or Serial DAta out. This is the bit that conveys the command/address/data patterns interpreted by the I2C SEEPROM.
D5 is SCK or Serial ClocK. This is the bit that drives the I2C protocol.
D4 [only in 6000-7FFF] is data read from the SEEPROM.
D7 is unknown -- it changes seemingly when there's a READ coming up next? Perhaps for some kind of bus conflict prevention...any thoughts?
D6 is SDA or Serial DAta out. This is the bit that conveys the command/address/data patterns interpreted by the I2C SEEPROM.
D5 is SCK or Serial ClocK. This is the bit that drives the I2C protocol.
D4 [only in 6000-7FFF] is data read from the SEEPROM.
I2C requires a START condition before any activities. A START is a negative edge on SDA while SCK is high. This is generated [again, observations from Dragon Ball Z Gaiden -- I'll update this post if I find different sequences elsewhere] by the following writes to 800D:
Code:
SCK SDA
40 0 1
60 1 1
20 1 0
40 0 1
60 1 1
20 1 0
Clearly, SDA goes low while SCK is high.
Transfers consist of 8 data beats and an ACK beat. The 8 data beats are exactly as Disch describes. To send a '1' bit to the SEEPROM the following writes to 800D are done:
Code:
SCK SDA
00 0 0
40 0 1
60 1 1
40 0 1
00 0 0
40 0 1
60 1 1
40 0 1
Data is set high before the postive edge of SCK which is when the data is clocked into the SEEPROM.
Similarly to write a '0' bit:
Code:
SCK SDA
00 0 0
20 1 0
00 0 0
00 0 0
20 1 0
00 0 0
A 0-bit is clocked into the SEEPROM on the positive edge of SCK.
The ninth beat or the ACK beat is different depending on whether the master [the 2A03] is writing a byte to the SEEPROM or reading a byte from the SEEPROM. If it's writing, it performs a read to make sure the SEEPROM drives SDA low to acknowledge the byte transfer. If it's reading, the 2A03 either drives the bit low to indicate it'll be reading more, or drives it high to indicate it's done reading.
Transfers are completed with a STOP, which is a positive edge on SDA while SCK is high.
Code:
SCK SDA
20 1 0
60 1 1
40 0 0
20 1 0
60 1 1
40 0 0
Clearly, SDA goes high while SCK is high.
Reads from the SEEPROM are done by generating a SCK positive edge then reading from 6000-7FFF. It is typical for the SDA/SCK lines to be pulled high in I2C so SDA is sent to 1. Typically SDA would be looked at directly for the SEEPROM to drive it to 0 or leave it at 1 but in this case the read-out bit goes to D4.
Code:
SCK SDA
40 0 1
60 1 1
E0 1 1 (I ignore D7...)
[READ D4 HERE]
40 0 1
40 0 1
60 1 1
E0 1 1 (I ignore D7...)
[READ D4 HERE]
40 0 1
The I2C SEEPROM protocol is clearly described in many datasheets for SEEPROMs. One example I used while writing my mapper 16 EEPROM implementation is this one.
Hope this information helps someone. It certainly made implementing the thing feel a heck of a lot less hacky to me. I'm not ready to push it yet but mapper 16 support will be in the next NESICIDE release.