|
Post by dshadoff on May 11, 2019 19:58:10 GMT
A couple more tidbits...
1) PCE Mouse doesn't work with a 3.3V-level circuitry. The switches and multiplexing do, but position-tracking seems to have serious issues.
2) I measured power consumption of the MB128, expecting to see a couple of milliamps at most, since the controllers are below 1mA, and the PCE Mouse is about 6mA. It turns out that the MB128 - even though it has batteries inside - consumes over 15mA when connected to the PC Engine !
Since MB128 + mulit-tap + PCE Mouse is a valid configuration (as suggested here and in the Vasteel 2 bootup screen), this brings the total consumption through the joypad port *using official equipment* to over 22mA. So that makes my job a bit easier...
|
|
|
Post by dshadoff on May 13, 2019 5:41:57 GMT
I found one source of the random read glitches in my MB128.
It turns out that Arduino uses some interrupts - though they don't seem to have a list of them anywhere... things like updating the millisecond timer counter, and another when that overflows, and perhaps something for serial IO.
So it seems that the most sensitive code path, plus interrupt(s) was probably dropping a bit. Since it's polling the lines, I knew that timing was going to be tight in the first place.
So, I disable interrupts as soon as the MB128 recognizes the detect sequence, and re-enable them when it goes back to idle state, and now my test program works fine with the CPU at 120MHz.
But I must have some kind of a bug or I'm missing some protocol information... While Emerald Dragon's "save to MB128" seems to write something into "Bank 00", it immediately seems to forget anything is in there, pretending like the unit is still empty (although the real MB128 will save as many copies to as many banks as you desire).
|
|
|
Post by dshadoff on May 14, 2019 1:42:46 GMT
One more step closer... I added a bit of instrumentation to my program, and dumped the sequence of transactions.
Since I'm going to be referring to my MB128 copy several times in this post, I'll call it "SYMB128" for easy reference.
First, I noticed that SYMB128 would "stall out" after Emerald Dragon would read the first 1024 bytes (directory page - first 2 sectors) - the read would complete, system would return to idle state, an 0xA8 sync character would be sent and recognized, then *poof* protocol error. As it turns out, Emerald Dragon was doing something I believed to be improper - switching the value of the data line more than once between clock signals.
In this situation, SYMB128 was programmed to return to the idle state (interpreting this behavior as "the game is scanning joypads"), but this happened after a 0xA8, before the read/write command, so it clearly wasn't intending to scan joypads.
So I removed the error check, and found that I got further in the program - it now not only formats correctly and recognizes that there are no entries, it also is able to save the BRAM data into a free sector; unfortunately, it doesn't update the directory secotr, and for some reason it keeps re-reading the directory sectors several times, which is a bit unsettling.
I'm wondering whether there is some unexpected interaction with any of the joypad data lines during read: Only D0 is used to transfer data, and so far, we've only seen D2 used once at identification time.
...Not sure why it's re-reading, but it seems this device is getting closer to reality...
|
|
|
Post by dshadoff on May 14, 2019 3:26:35 GMT
I'm about to try to design my first PCB soon. I'm quite excited! Was the turnaround quite quick? And did they make the mistakes, or was it in the design? All mistakes are my own. One was that I used a footprint from an external library for the mini-DIN jack; it confused me because the connections did not match the labels. After what I thought was deep study, I decided all it needed was to mirror the footprint and all would be well; as it turns out, it didn’t need to be mirrored (this is equivalent to mounting it on the underside). The jumper was also my fault. It really depends on how large your board is; if you’re using free EAGLE, you’re limited to 80x100mm, which is fine if you send it to seeed studios, who will make simple double-sided boards of this size for 10 units for $5US with a turnaround of 3-4 days, but if you want them back quickly you’ll need to splurge about$25 for DHL. Oshpark’s expedited service is also fast, but much more expensive - though if you have a very small board, you may find it acceptable. Normal turnaround for them is closer to 2-3 weeks. I used SMD parts, and sort of regret doing that because I don’t have a reflow oven or tools. It’s not as easy as it looks with a hand soldering iron. Dave OK, I've finished the design for round 2 of the board, and just sent it off to another PC Board place. This time, I fixed the problems from the first one, used different level-shifters, and made the breadboard area bigger. Since I now have a (cheap) reflow oven, I'm a lot less worried about the surface-mount chips (I placed them a lot closer together this time), and maybe next time I'll try using TSSOP chips... In case anybody is interested, I found another PC board place that seems faster and cheaper than the others: JLCPCB.com As long as you're just doing simple boards like me, they look fast and cheap: - 24-hour turnaround - $2 for 5 boards ($5 for 10) - They'll do SMT stencils for $6 if you need them - Shipping (i.e. DHL) from China looks to be at cost (~$25 for express) - They'll take $20 off the first order - which means my whole order for 10 boards (83mm x 83mm), a surface-mount stencil, and express shipping to Canada was $17. I know that the guy who makes the TinyPico ESP32 microcontroller board uses JLCPCB, so I'm pretty sure I won't have any issues with the quality. Another possibility is PCBWay.com - they do lots of esoteric things like microvias and 10-layer boards - and still have 24-hour turnaround $5 boards (although they apparently make their money on shipping - they charge double what JLCPCB does)
|
|
|
Post by elmer on May 14, 2019 5:21:36 GMT
First, I noticed that SYMB128 would "stall out" after Emerald Dragon would read the first 1024 bytes (directory page - first 2 sectors) - the read would complete, system would return to idle state, an 0xA8 sync character would be sent and recognized, then *poof* protocol error. As it turns out, Emerald Dragon was doing something I believed to be improper - switching the value of the data line more than once between clock signals. In this situation, SYMB128 was programmed to return to the idle state (interpreting this behavior as "the game is scanning joypads"), but this happened after a 0xA8, before the read/write command, so it clearly wasn't intending to scan joypads. Hmmm ... very interesting! Looking at Emerald Dragon's code, I can't see any indication of why it would be changing those data lines in the middle of a read-bit/write-bit cycle ... unless they really did forget to disable interrupts, and it is actually being interrupted and going into a joystick read. There isn't anything in Mooz's disassemble of the Emerald Dragon code that disables interrupts, so it's going to have to be at a higher level if it's there. The other thing is that right after sending the $A8, the Emerald Dragon code is calling a routine to read the port for the detection value $40/$04 (depending upon your nibble order). That routine is a bit different to the normal code, and it reads the joypad value the next cycle *after* dropping the joypad's CLR bit ... which is not a good idea!
|
|
|
Post by dshadoff on May 14, 2019 10:52:38 GMT
Very interesting ! At the moment, I'm not so concerned about responding too slowly to an 0xA8, since the device is receiving (and acting on) commands such as: - write sector #0 (format) - read sector #0 - read a bit - write bytes to sector #2 ...and doesn't seem to be returning to idle at odd periods (at least as far as I can see)
However, I'm not sure if the SYMB128 is sending all the right data back to the host, because of the apparent re-reads of the first 1024 bytes (which, by the way, match those on a fresh unit just after formatting).
Perhaps what I'll do next is to execute the same operations on a real MB128, but 'splice off' the data and clock lines, and watch SYMB128 to see if the same commands are sent to the real unit (but shadowing on SYMB128). In this way, I should (I hope) be able to see which function is somehow getting an unexpected response from SYMB128 - and then it should be a matter of identifying from the Emerald Dragon code what is actually expected. You never know... it could be watching one of the data lines which we think are unused.
I guess another way would be for me to try to write a MB128 adapter for Mednafen, but that would be a lot more work...
|
|
|
Post by dshadoff on May 14, 2019 12:25:59 GMT
The other thing is that right after sending the $A8, the Emerald Dragon code is calling a routine to read the port for the detection value $40/$04 (depending upon your nibble order). That routine is a bit different to the normal code, and it reads the joypad value the next cycle *after* dropping the joypad's CLR bit ... which is not a good idea! Actually, I think you may have found it. SYMB128 in its current form won’t be able to respond to this quickly enough (at least not consistently), and Emerald Dragon could interpret this as a failure. When I get home tonight, I will patch the code at that point to resequence the instructions to repair the bug, and retest. I think you may have also discovered the reason why some people have found Emerald Dragon’s MB128 code to be unreliable.
|
|
|
Post by elmer on May 14, 2019 22:57:09 GMT
Actually, I think you may have found it. SYMB128 in its current form won’t be able to respond to this quickly enough (at least not consistently), and Emerald Dragon could interpret this as a failure. Hmmmm ... I just had a thought that would explain why Emerald Dragon's code would generally work in practice, and why a change-in-behavior that I accidentally added while optimizing my MB128 code still ended up working, even though it shouldn't have if the MB128 were operating the way that I've been thinking. You originally speculated that the MB128 changed bit5 on every cycle of the CLR, and then I pointed out that the detection sequence was looking for a specific $40 value after reading the SEL-hi and SEL-lo nibbles, which made it seem like it was responding like the 754HC157 on a normal joypad. Here's another explanation that would fit what we're seeing, including why the Emerald Dragon code works. What if bit5 on the input is just a copy of the last bit that you sent to the MB128? That would explain why the detection sequence is looking for a %0000 after sending a '0' bit, and %0100 after sending a '1'bit. If bit5 is set as soon as you clock the CLR line, and not changed when the CLR line is dropped, then that explains why the Emerald Dragon code actually works, and it explains why my optimization-change/bug didn't actually break anything. It would also be very easy for you to implement that way in your SYMB128. What do you think?
|
|
|
Post by dshadoff on May 15, 2019 0:15:35 GMT
Here's another explanation that would fit what we're seeing, including why the Emerald Dragon code works. What if bit5 on the input is just a copy of the last bit that you sent to the MB128? That would explain why the detection sequence is looking for a %0000 after sending a '0' bit, and %0100 after sending a '1'bit. If bit5 is set as soon as you clock the CLR line, and not changed when the CLR line is dropped, then that explains why the Emerald Dragon code actually works, and it explains why my optimization-change/bug didn't actually break anything. It would also be very easy for you to implement that way in your SYMB128. What do you think? It's funny you should say that. I bought a pretty cool little PC-based oscilloscope - an ADALM2000 - recently, and one of its features is being a logic state analyzer. (At $100, it's very cost effective !) I hooked it up over the weekend, to try to grab the protocol for a sector write- I was thinking that this raw data might be able to solve any remaining issues... I *did* see some 'funny' behavior on one of the lines - and I'm pretty sure it was the D2 line (otherwise known as 'MB128 identify bit') - but the protocol stream was a bit too much information to try to absorb all at once. That signal was moving up and down when I had expected it to remain in a constant state during a read. So it is very plausible. And I also had your very thought - that it might be echoing back the input bits, delayed by one cycle. But not all the time - just at certain points in the protocol. If I have time tonight, I will look at this again with that specific intent. I want to check the patched version of Emerald Dragon first. By the way, I have two things you might be interested in, from that scope: First, is a 'normal' joypad scan - the send #$01 / #$03 / #$01 to the $1000 port. It's interesting how the signal is a bit contorted and narrower after transmission; this is why it's important to have the delays. Second, is a logic analyzer grab from the MB128 sync '0xA8' code. You can read the outgoing bitsream from the "SPI: MOSI bits" (ignore the byte-sized one; I haven't been able to align that). Note: I only had it sampling at 0.5uS intervals, so you probably won't see any propagation delay. You will notice that D2 doesn't echo the incoming bit on the preamble to the read command (but I'd have to hunting to find out where it does).
|
|
|
Post by dshadoff on May 15, 2019 2:37:40 GMT
Well, test #1 didn't succeed - fixing the delay between the write to, and subsequent read from, the joypad port. I don't think I'll have enough time to do the logic analyzer until the weekend though.
In any case, it seems to: - read the directory (twice though) - write the backup data to a 'free' sector ...but then it doesn't update the directory again - my expectation is that it should immediately write the directory, but instead it reads it.
Perhaps this weekend, I will look at the disassembly a bit, or force Mednafen to believe that there's a MB128 in order to find out what the code path might be thinking (as well as look at the tail end of a short write through the logic state analyzer).
|
|
|
Post by elmer on May 15, 2019 2:53:22 GMT
In any case, it seems to: - read the directory (twice though) I don't know what was in the mind of Emerald Dragon's developers, but as I have been writing my code, and trying to understand all of the retries in both the Emerald Dragon and Private EyeDol code, the best explanation that I can come up with is that the developers were trying to protect themselves from single-bit hardware errors in the joypad connection itself. These wouldn't really matter in the normal function of regular joypad-reading, where an intermittent connection would just read '1', i.e. button-not-pressed, but they could totally screw up a data transfer to/from the MB128, particularly if it missed a couple of cycles on the CLR bit. The best solution that I could come up with was to read the directory/file twice and make sure that the data was the same ... and similarly when writing ... write it, and then read it back in and compare the two. That's *before* even looking at the checksum value for the data that's stored in the directory. Another advantage of the double read-after-read and read-after-write, is that you have a chance detect a problem and to unjam the MB128 if it just missed a couple of bits and is still waiting to read/write a few bits when the PCE already thinks that the transfer should have finished.
|
|
|
Post by dshadoff on May 15, 2019 4:26:40 GMT
I agree; I just want to determine at what point it believes that something went wrong (by taking a different branch, and giving up on updating the directory for example). At that point, I can try to understand what actually took place (or failed to take place).
|
|
|
Post by dshadoff on May 18, 2019 23:11:24 GMT
I tried a couple of other games with SYMB128 in its current form.
1) A.III didn't complain about any problems, but it did have long pauses, as though some kind of timeout was taking place. 2) Private Eye Dol didn't complain, and didn't seem to have any sort of problem whatsoever.
It's interesting to note that when performing a "copy all" operation, Private Eye Dol simply copies the BRAM wholesale - every byte, "HUBM" header and all - without interpreting anything (and then updates the first two sectors which are the index). It also copies 1 sector (512 bytes) at a time - write, then read back to verify.
...Whereas, Emerald Dragon tries its best not to waste space, by stripping off the "HUBM" header (and possibly some pointer/size information), and writes the exact size of the data to the MB128 (i.e. 1843 bytes). It also interacts with larger-than-512-byte transactions.
This is why Emerald Dragon and Private Eye Dol saves are not compatible.
|
|
|
Post by dshadoff on May 19, 2019 5:31:13 GMT
OK, I got a protocol dump of Emerald Dragon at the point where when I agree to SAVE the backup memory to a fresh bank in MB128. ...And it's confusing the heck out of me.
After I hit the key, there's no '0xA8' string, but the MB128 wakes up somehow. Could be due to a micro-blip of the clock line, roughly 330 nanoseconds long - about 5 times shorter than usual.
From this point, the PC Engine doesn't actually change the DATA_OUT bit, but simply clocks the signal for a huge number of times (estimated by using bit rate sample, multiplied by burst lengths) - roughly 4096 bits. Could be considered a read from sector 0, but with 0 length (or an assumed one), which is just weird. MB128 rereturn a bit of data, but I can't figure out where it's coming from, and then just sends a bunch of zeroes.
Oh, and the IDENT line doesn't seem to be doing anything odd here - seems to be dormant like the other two joypad key lines.
|
|
|
Post by dshadoff on May 20, 2019 19:12:35 GMT
I ran some more tests, and concluded that I had a bad capture, and that my capture device, an ADALM2000, was dropping sections of data when in streaming mode @ 3MHz. to be honest, the Scopy software has some problems scrolling around in the capture buffer when trying to zoom in and out, so I'd have to say that it's not quite ready for prime time yet... but still a good educational vehicle, if you know what the rough edges are and can stay away from them.
I also got an Analog Discovery 2, and did some captures with that. Similar tool, totally different software. Easier to use, a little harder to read... but it looks like I may be able to define my own protocols on this, and it doesn't seem to be dropping any samples.
I have learned the following, based on naming the lines as follows: CLK = clock (also known as CLR for joypad use) DOUT = data outbound from PCE (also known as strobe for joypad use) DIN (DO) NA1 (D1) IDENT (D2) NA2 (D3)
- First of all, during normal use (no MB128), all signals have pullup resistors to make them high as default. - When CLK goes high, the 74HC157 returns zeroes for all of the lines, so keep this in mind for any up-down values. This doesn't just happen for the joypad.
We already basically know the stream of data going to the MB128 from the PCE, based on the work that MooZ, elmer and myself have been doing for reverse-engineering the existing code. Here, I'll try to explain the responses I've seen on the device.
First, the easy lines - because they're effectively disconnected:
1) NA1 & NA2: - These return HIGH except when CLK is HIGH; in that situation, they return LOW. This is effectively the same as feeding the joypad values straight through (though I didn't try watching the trace when a corresponding button is pressed).
2) DIN: DURING READ DATA, this returns the data value corresponding to the memory being read DURING WRITE DATA, this is set high. DURING COMMAND_HEADER, this acts the same way as NA1/NA2: returns HIGH, except when CLK is HIGH; then it returns LOW DURING COMMAND_TRAILER: - on WRITE, first trailing bit is a '1' - DIN stays high while CLK is high, but transitions to LOW when CLK transitions to LOW. This is the only transition I saw where the change happens on the downward transtiion. - on WRITE, second through fifth trailing bit, and on all three trailing bits on READ, it is high except when CLK is HIGH (then it's LOW, like on the joypad reads)
3) IDENT: On the most significant bit of the 0xA8, this starts echoing whatever DOUT sends. For the MSB of the 0xA8, and for the next '0' and '1' identification bits sent, IDENT reflects the value of DOUT, irrespective of the value of CLK. For all other situations while the MB128 is controlling the joypad port, IDENT = DOUT & (!CLK). In other words, IDENT = DOUT but becomes affected by the state of CLK like most other lines - if CLK goes high, IDENT goes low. NOTE: At the end of a WRITE stage, after the PCE has sent the last data bit, and before the PCE has sent the trailing '1' and '0' bits, IDENT goes low and stays low.
Now, I'll see if it's possible to make my SYMB128 reflect this complexity as a microcontroller... it should be a lot easier on an FPGA though.
|
|