93LC56 Questions 
Author Message

Joined: 2014-09-27 09:46
Posts: 100
 93LC56 Questions
Recently byuu emulated the 93LC56 EPROM to get the MBC7 on GBC to work properly. He did at least one Twitter thread on the topic, reproduced here:
Quote:
The 93LC46/56/66 EEPROM manual states that the '56 has an extra dummy bit on the address segment. It does not. It does, however, have the extra dummy bit on reads it mentions later on, which is not included in the clock cycle counts here.


Out of curiosity, I've looked at the read timing waveforms datasheet for said EPROM, which I've copied here:
Image

And I've also looked at the code byuu provided, linked here. The last line of the first function caught my attention:
Code:
 output.length = 1 + width;  //there is an extra zero dummy bit on reads
.

Perhaps I'm misunderstanding something, but I don't see how there's a cycle for the dummy data bit. Yes, the dummy data bit does exist; it is mentioned in "2.4 Read", and it is not part of cycle timings. But if this waveform timing is correct, then the dummy bit is emitted on the same cycle that the final address bit is shifted in. Therefore, I don't see how the dummy read bit can be part of cycle read timings.

The listed cycle counts make sense if there is either a cycle dedicated strictly to a dummy address bit or one to a dummy data bit. So, no problem right? Assuming the dummy data bit/a0 overlap in the waveform is accurate, the cycle timing is the linked code correct, it's just that the cycle for the dummy bit is due to the address line, not the data line. However, it bothers me that the timing waveforms include the "0" for the dummy data bit overlapped with "a0", but don't mention a dummy bit on the address line at all. Do we know for sure through testing that there is no address dummy bit? (i.e. does the MBC expose this implementation detail of how to talk to the EPROM?).

If we know for sure there is no address dummy bit, then it seems to me that the actual timing for the EPROMs is one cycle too long. This assumes the timing waveform is accurate as shown of course, but based on the twitter thread, this seems reasonable.

Anyone got an 93LC56 to check plus a logic analyzer to test the following?:
  1. There exists a dummy address bit.
  2. The dummy read bit occurs on the same cycle as the last address bit is clocked in.

If not, maybe I'll buy one and do tests of my own. Of course, even if I'm understanding correctly, it's doesn't seem like a one cycle difference actually is a problem here :P. I just got confused, and my confusion was sufficient enough to ask.


2018-09-07 07:00
User avatar

Joined: 2014-09-27 10:02
Posts: 320
 Re: 93LC56 Questions
You misunderstood the datasheet.

I think the confusion stems from the fact that the input bits are sampled on the rising edge, while the output bits should be sampled on the falling edge (or before the propagation delay on the next rising edge). It is there, because these eeproms are actually microwire -- which just happens to be compatible with SPI mode 0 if the host doesn't require a data hold time exceeding the propagation delay on the DO line.

So the first output cycle is indeed a dummy zero bit, because the first falling edge after the address is fully transmitted occurs right after it.

Image

You have to account for in if your host uses just regular SPI to read the data. This is code that reads a 93xxX6 EEPROM on a break-out-board I assembled on my desk:

Code:
void uW_seeprom_readX8(struct uW_seeprom* ee, uint16_t addr, size_t n, uint8_t* b) {
   
   /* dummy 0 bit */
   uint16_t op = _93XX_OP(ee->type, _93XX_OP_READ, addr, ee->org) << 1u;
   uint8_t buf[0x02u];
   
   buf[0] = (op >> 8) & 0xFFu;
   buf[1] = op & 0xFFu;
   
   ee->cs_port->out |= ee->cs_mask;
   spiSend(2, buf);
   spiWait();
   spiReceive(n, b);
   spiWait();
   ee->cs_port->out &= ~(ee->cs_mask);
   
}


First off, the start bit, operation and address are aligned to 8-bit boundaries for most SPI operations. To skip the dummy bit, I shift everything up one clock cycle, so the dummy bit is actually the last bit in the address phase and then I read out straight octets of data. This code works for 93xx46 thru 93xx86 (with different shift offsets that are abstracted in type) and was successfully tested on multiple occasions on a 93AA76.

EDIT: The assertion that the dummy address bits aren't there in X8 organization is wrong as well. I have yet to see such a blatant mistake in an EEPROM datasheet. Both DMG-A40 and DMG-A47 use the 93LC56/93LC66 in X16 organization, so byuu's assertion might stem from game code just not bothering to use the lower 8 bits or something (I don't know, did take a look at these games in a disassembler yet).

Regards,

Tauwasser


2018-09-07 18:02
User avatar

Joined: 2014-09-25 13:52
Posts: 8242
 Re: 93LC56 Questions
It may have to do with the concept of data being sampled on different edges of the clock signal between inputs and outputs. I've never even heard of such a thing.

But with the way it's implemented in higan, and looking at all the writes from Kirby Tilt 'n' Tumble, it does not appear to have the extra address bit, and adding it in breaks Kirby.

I frankly spent *way* too much time on that EEPROM already, so I have almost no desire to go back and work on it further now.

_________________
What the hell's going on? Can someone tell me please?
Why I'm switching faster than the channels on TV.
I'm black, then I'm white. No, something isn't right.
My enemy's invisible, I don't know how to fight.


2018-09-07 22:07
User avatar

Joined: 2014-09-27 10:02
Posts: 320
 Re: 93LC56 Questions
byuu wrote:
It may have to do with the concept of data being sampled on different edges of the clock signal between inputs and outputs. I've never even heard of such a thing.


And yet you make sweeping claims about datasheets for standard parts being wrong :-/

This clocking setup is pretty standard, because for synchronous single-data-rate logic, everything starts to happen at the rising edge. Inputs are sampled, evaluated and then the corresponding outputs change. That takes time (propagation delay). So if you sample 180° inverted, at the negative clock edge, you will be guaranteed stable data if the circuit does not employ multi-cycle combinational logic, i.e. paths that take longer than half the clock period to settle.
The same principle applies to dual-data-rate (DDR) logic, just that the data bus is going at twice the rate of the clock at 90° (data bus switches in the middle of the high resp. low clock phase), so there will always be stable data at both clock edges.

Anyway, I checked out your code a bit. First off, I'm reminded that the MBC7 documentation is sparse and all over the place, so you probably had nothing to work off of for the GPIO logic.
This is the code that sets up the different data and address lengths:

Code:
auto Cartridge::MBC7::EEPROM::load(Markup::Node document) -> void {
  for(auto& byte : data) byte = 0xff;
  size = 4096;  //EEPROM size is in bits
  width = 16;   //16-bit configuration

  if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=EEPROM,content=Save)"]}) {
    if(memory.size == 128) size = 1024;  //manifest size is in bytes
    if(memory.size == 256) size = 2048;
    if(memory.size == 512) size = 4096;

    if(auto fp = platform->open(cartridge.pathID(), memory.name(), File::Read, File::Optional)) {
      fp->read(data, min(fp->size(), sizeof(data)));
    }
  }

  command.length = 3;
  if(size == 1024) address.length = width == 8 ? 6 : 7; <--- 93LC46: wrong way around; should be 6 bits on width == 16, else 7
  if(size == 2048) address.length = width == 8 ? 7 : 8; <--- 93LC56: wrong way around; should be 8 bits on width == 16, else 9
  if(size == 4096) address.length = width == 8 ? 8 : 9; <--- 93LC66: wrong way around; should be 8 bits on width == 16, else 9
  input.length = width;
  output.length = 1 + width;  //there is an extra zero dummy bit on reads
}


Turns out, because of the inverted comparison, you were using 8 bits all along for 93LC56 in X16 organization, which is what Kirby's Tilt 'n' Tumble. So the dummy address bit is there :)

I'm fairly certain there is another bug in Cartridge::MBC7::EEPROM::readIO, because the MBC should be able to read back data.bit(1) just fine (that's EEPROM DI, MBC7 out, EEPROM in). Also, busy signalling is only done after CS was de- and then re-asserted, not right away after, because the deassertion of CS is what actually triggers the execution of commands.

Another problem is that you never flush command, input or output in Cartridge::MBC7::EEPROM::writeIO when CS is deasserted during a command. It might not be obvious from the datasheet, but CS is used for framing control (as is super common with serial eeproms). That's the line "If CS is low, the internal control logic is held in a Reset status." that's supposed to tell you that, in case you're wondering.
If CS is asserted, start condition detected, any number of bits clocked in and -- in case of commands that can be busy -- the command isn't executed and then CS is deasserted, the next time CS is asserted, the control logic will start from the beginning and not from the point where the host left off, i.e. a new start condition, command etc. is required.

Clocking in more than the required number of bits per command will actually cancel the execution of that command. This goes along with the missing wait for deasserted CS on most commands. For instance, going through the motions of a write command (every 0/1/A/D/X represents a clocked-in bit):

Code:
CS 01111...11...110
DI 0101A...AD...DXX
                 ^
                 |
                 \--- additional clock cycle that clocks in one bit too many cancels write command


EDIT: You also don't mask the upper don't-care address bits, so games that expect 93LC56 are in for a nasty surprise when they set the upper address bit and expect the data they've written back when it was reset.


2018-09-08 00:31
User avatar

Joined: 2014-09-25 13:52
Posts: 8242
 Re: 93LC56 Questions
Tauwasser wrote:
And yet you make sweeping claims about datasheets for standard parts being wrong :-/


I appreciate the help clarifying, but could you try to not be a dick about it like AWJ, please?

I don't think I've offended the author of a 20-year old PDF file in my random tweet about it. But sure, I made a mistake. I was flustered after a marathon 12-hour coding session trying to get Kirby to actually work.

I have to say though, this chip is an absolute nightmare. Never in my 15 years of emudev has such a seemingly simple memory chip given me so much trouble ._.

_________________
What the hell's going on? Can someone tell me please?
Why I'm switching faster than the channels on TV.
I'm black, then I'm white. No, something isn't right.
My enemy's invisible, I don't know how to fight.


2018-09-08 01:31
User avatar

Joined: 2014-09-27 09:30
Posts: 1096
 Re: 93LC56 Questions
byuu wrote:
15 years of emudev
Time flies when you're having fun.

_________________
http://helmet.kafuka.org


2018-09-08 15:53
User avatar

Joined: 2014-09-25 13:52
Posts: 8242
 Re: 93LC56 Questions
Put out a public correction on the address bit thing:
https://twitter.com/byuu_san/status/1039332498629640192

Quote:
you probably had nothing to work off of for the GPIO logic


Correct. Unfortunately, I'm not able to understand endrift's coding style, so that didn't help me.

All I had was: http://ww1.microchip.com/downloads/en/d ... 21712B.pdf
And your note that the I/O port is: d7=CS, d6=CLK, d1=DI, d0=DO.
I'm not familiar with this talk about 180-degrees and 90-degrees stuff, how DDR works, etc.
The PDF says both reads and writes clock on the rising CS edge, so I just went with that.

Implementing d1=DI required rewriting the code, and I went ahead and remerged the command+address+input(data) shift registers to a single input shift register.

I also handled the start bit separately, and so that should address the input shift register always being flushed properly. And I'm doing the power flush state thing on CS lowering instead of CS rising now.

The address is actually masked off (address << (width==16) & size-1), and with the corrected bit lengths, it'll be fine, don't worry.

Clocking in extra bits ... well ... the commands start as soon as they get enough bits, so if it's a kind of abortive thing ... then it'll probably be a partially completed command. That's just awful =(

_________________
What the hell's going on? Can someone tell me please?
Why I'm switching faster than the channels on TV.
I'm black, then I'm white. No, something isn't right.
My enemy's invisible, I don't know how to fight.


2018-09-11 04:38
User avatar

Joined: 2014-09-27 09:56
Posts: 1674
 Re: 93LC56 Questions
byuu wrote:
I'm not familiar with this talk about 180-degrees and 90-degrees stuff, how DDR works, etc.


Talking about degrees in this context refers to a phase shift, represented as an offset in polar coordinates relative to some reference (i.e. another signal, typically the system clock). It might seem weird, but it comes from the fact that AC signals are represented as sine waves, and the math is a lot easier in polar coordinates. When you're dealing with synchronous digital signals, you really only care about multiples of 90 degrees. At 0 and 180 degrees, the edges occur at the same time, but in opposite directions. At 90 and 270, the edge of one signal occurs exactly halfway between the edges of the other.

Image

As for DDR, Tauwasser already mentioned the fact that it's very common for data to be latched on one clock edge and sampled on the opposite edge. DDR is a method for transferring data on both clock edges instead, but it's a lot more complicated to implement, and more expensive as a result. QDR utilizes two clock signals, offset by 90 degrees, and then performs DDR transfers on both edges of both clocks.

_________________
byuu wrote:
Surely I can unite the vi vs emacs crowd like I have the ZSNES vs Snes9X crowd :)



higan WIP builds available here


2018-09-11 05:01

Joined: 2014-09-27 09:46
Posts: 100
 Re: 93LC56 Questions
byuu wrote:
Put out a public correction on the address bit thing:
https://twitter.com/byuu_san/status/1039332498629640192


Clearly, I have high latency responding, but thanks for the public correction :). I mainly made the thread b/c I didn't understand your initial tweet on the topic. From experience, if someone asserts "X" about some topic "Y", and I don't think "X" is correct, usually it's because I don't understand "Y" as well as I think I do, and the other party sees something that I don't*.

That said, I didn't want to cause any arguments by asking/getting response. Would you be upset if I made other posts like this in the future if I get confused by your tweets?

*Well, I was still wrong in this case, but for a different reason :).


2018-09-25 00:09