Memory Base 128 Author : MooZ Version : 0.1 Description: ------------ The NEC Memory Base 128 (mb128 for short) is an external PC-Engine RAM backup unit that plugs between the joypad port and the joypad itself. It can stores up to 128 KB, which is 64 times more than the standard Backup Units (Tennokoe 2 or Duo internal BRAM). Just like the Tennokoe 2, the mb128 needs to be powered by external batteries (4 AA) in order to retain data. It is built around the MSM6389C from OKI Semiconductor, a 1048576 x 1bit solid-state data register. This means that data is transfered 1 bit at a time. Note that Koei released a similar device (if not a clone), the Save Kun. Basic operations: ----------------- As the mb128 is plugged into the joyport, communication is done through the joypad control port ($1000). Without further ado, here is how to send a bit to the mb128. At this point the bit may not be stored. There is a bit of protocol to respect before getting anything written on the MSM6389C (more on this later). In the following routine the A register holds the bit (0 or 1) to be sent. If you have ever looked at a joypad routine, you will recognize the classic pha/pla/nop delay used in many games and in MagicKit. mb128_send_bit: and #$01 sta joyport pha pla nop ora #$02 sta joyport pha pla pha pla pha pla and #$01 sta joyport pha pla nop rts If you are not familiar with assembly languages, the mb128_send_bit routine can be translated into the following timing diagram where . means a cycle of delay, b is the bit to send (either 0 or 1). There are 2 lines. The one labeled w is for the data written to joyport. The r line is for the data read from the joyport. Only 4 bits can be read or write through the joyport. w: {000b}{.........}{001b}{.....................}{000b}{.........} r: A byte is transfered by sending each bit starting from bit 0 to bit 7. This can easily be done by repeatedly shifting the value to the right and sending the carry flag to the mb128. This can be translated in the following C-like pseudocode. mb128_send_byte: for(i=0; i<8; i++) { mb128_send_bit( a & 1 ); a = a >> 1; } Reading a bit is performed in a similar fashion. The assembly routine looks like this : mb128_read_bit: stz joyport pha pla nop lda #$02 sta joyport pha pla nop lda joyport stz joyport pha pla and #$01 rts The associated timing diagram : w: {0000}{.........}{0010}{.........} {0000}{.........} r: {abcd} Reading a byte is done just like its counterpart. A byte is read by performing 8 consecutive bit read and pushing the bit using left shift. mb128_read_byte: a = 0; for(i=0; i<8; i++) { a = (a << 1) | mb128_read_bit(); } Detection & boot: ----------------- The following sequence let you detect the presence of a mb128. mb128_detect: mb128_send_byte( 0xA8 ); mb128_send_bit( 0 ); res = joyport << 4; mb128_send_bit(1); res = res | (joyport & 0x0F); A mb128 is plugged to the joyport if res is equal to 4. Some games make 3 attempts before calling it quits At startup just after detection, a special sequence is performed. It can be viewed as a boot/reset sequence. mb128_boot: mb128_send_bit( 1 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_send_byte( 0x00 ); mb128_send_byte( 0x01 ); mb128_send_byte( 0x00 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_read_bit(); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); Once mb128_detect and mb128_boot are performed, you can safely read or write data to the mb128 storage. Sector read/write: ------------------ All games studied store or retrieve data by blocs of 512 bytes. A bloc is called a sector. The first thing to do is to tell the mb128 which sector is being processed. As the mb128 can stored up to 128KB, there are 256 (0x100) available sectors. The sequence sent is similar to the one sent for a boot sequence (mb128_boot). mb128_sector_addr: mb128_send_bit( 1 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_send_byte( sector_id ); mb128_send_byte( 0x00 ); mb128_send_byte( 0x10 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); mb128_send_bit( 0 ); Once the sector address is set byte can be read or written using mb128_read or mb128_write. A standard multi-sector read routine looks like this : mb128_read_sectors: for( b=0; b