|
Post by dshadoff on Apr 26, 2019 21:12:37 GMT
Very cool, I know what I’ll be doing this weekend !
|
|
|
Post by dshadoff on Apr 27, 2019 1:09:12 GMT
This is interesting... My notes said that a read command is (where xxxxxxxx = sector #):
100 xxxxxxxx 00000000 00010000 0 0 0 0
While I had felt certain that this was "too long" of a command for something so simple, I had considered it a "key" of sorts. And it makes perfect sense that there should be a 'length' parameter in there somehow.
So, according to your findings, this should be read as:
100 xxxxxxxx 000 00000000 10000000 0 = length of 512 ( = 1 sector)
This is indeed interesting. Well, what if I told you that the RAM chip is addressable to a finer granularity than 512-byte sectors ? Apparnetly, 10 bits of address information can be sent, according to the datasheet - this makes for an actual 128-byte sector. I feel confident that this would account for 2 of the '0' bits on one side of the sector address, but not certain which side. According to the datasheet, the address is sent LSB first. This implies that the command header is actually '1xx xxxxxxxx 000 (etc.)'
I may try this on the weekend with the Arduino-based MB128 reader.
|
|
|
Post by elmer on Apr 27, 2019 4:46:26 GMT
So, according to your findings, this should be read as: 100 xxxxxxxx 000 00000000 10000000 0 = length of 512 ( = 1 sector) This is indeed interesting. Yep, exactly! Well, except for the bit-transposition in there ... 100 xxxxxxxx 000 00000000 01000000 0 = length of 512 ( = 1 sector) I've tested loading 2048 bytes at once on my Duo/MB128, and it *seems* to be working fine ... i.e. the file's data checksum matches the one that is stored in the MB128's directory info. I've only got a couple of whole-BRAM save files on my MB128 at the moment, so I'll have to try to get some other files on there to test more, and to test your theory that we might be able to change the address on 128-byte boundaries.
|
|
|
Post by dshadoff on Apr 27, 2019 12:32:29 GMT
I don't think that I made a bit transposition error... your length would appear to be just 256 (7 zeroes after the 1).
But I have other interesting news - the two zeroes in the '100' at front of the command are as I mentioned above, partial address information. Through a quick test, I also determined that the MB128 seems to be reversing the bits of what we've been calling the "sector address" until now. I will explain...
The datasheet for the memory indicates that the address is supplied as A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 - so can reference 1024 distinct groups of 1024 bits (ie. 128-byte 'sectors'). The MB128 has had us believe that the sequence is actually A9 A8 A7 A6 A5 A4 A3 A2 (with an implied '00' for A1/A0), based on how they use sector addressing.
If there was no access across sectors - no offsetting, no reads beyond a sector - then the address lines could be any arbitrary sequence without needing to care about this apparent reversal - but the additional two bits had me interested.
So I ran a test, pumping a known pattern into the MB128 using the arduino:
1) I created a 128KB file, where the first three bytes of any 16-byte row indicate the offset inside the file. For example, the first row of the first sector is: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
The first row of the second sector is: 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00
And the last row of the file is: 01 FF F0 00 00 00 00 00 00 00 00 00 00 00 00 00
2) I loaded this, 512-byte 'sector' by 512-byte 'sector' into the MB128
3) Then I read it back, but by changing the first three bits from '100' to '101':
The first line which came back was: 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...and the sequence remained, exactly one after another, even across apparent 'sector boundaries'.
4) Then I changed the first three-bit sequence to '111': The first line which came back was: 00 01 80 00 00 00 00 00 00 00 00 00 00 00 00 00
Now, this is great news, but of course the puzzle then becomes: Why is the addressing sequence actually: A0 A1 A9 A8 A7 A6 A5 A4 A3 A2 ...And how can that possibly make sense ?
And my conclusion is that the MB128 internally reverses A2-A9, storing them in an internal shift register, and sending them on some of the following 8 bit-clocks. This helps us to understand a little bit more why there are so many (apparently excess) bits in the command sequence... because some of them are just driving a clock to internal logic. At least that is the current working theory.
IF MB128 didn't actively reverse the bit-sequence, I would see a discontinuous pattern at the sector border - in the middle of a 512-byte read when I use the offset to get down to 128-byte granularity.
Also, if Hudson/NEC went to this extent to reverse bits, they always intended for developers to think of 512-byte 'sectors', and reversed the bit-sequence because of how sector-boundaries need to be treated for larger-than-sector read/write blocks. They would have never intended anybody to use the additional address bits - so I don't believe that you'll see any reference in any code to reveal that non-zero values drive any functionality.
Sometime today, I will try reads of various sizes to see how small/large a read can be. But there is a special case which leads me to believe that there is a limit - and that is the 'MB128_BOOT' sequence, as Mooz has labelled it: 100 00000000 00000001 00000000 0 0 0 0 (read) 0 0 0
If we adjust the spacing, this appears to be exactly: 100 <sector 0> 000 00001000 00000000 0 (read) (trailing 3 bits after command)
-> This is (according to the length explanation) an attempt to read 8KB starting at the beginning of sector 0. But effectively there is no data returned (possibly the one bit); it simply 'resets' or 'self-checks' the device somehow. We're not sure exactly its purpose, but in Emerald Dragon every read/write was: <0xA8 sync sequence> <MB128 'boot' command> <sector read-write operation>
If we examine this 'boot' command, considering what I said earlier about the sector address actually being passed to the memory device as a mirror-image in the following 8 bits after it is sent from the PCE, the boot command is special in that the final bit of this 'mirror address' sequence is a '1', which might be the thing driving the special behaviour. But that would seem to indicate that the length is limited to 8191 bytes at a time.
Dave
|
|
|
Post by dshadoff on Apr 27, 2019 20:32:27 GMT
Well, this is VERY interesting ! I did some tests on varying the length parameter, and I'll re-label the bit-field:
R/W A7 A8 A16 A15 A14 A13 A12 A11 A10 A9 xxxxxxxx L12 L11 L10 L9 L8 L7 L6 L5 L13 L14 L15 L16
Where: - R/W = '1' for read, '0' for write
- "A7" is the least-significant address level, corresponding to a byte-offset of 128 bytes. Note that the sequence is reversed for A7-A8 as compared with A9-A16
- xxxxxxxx = bit-field with vague function; a '1' somewhere in here seems to imply 'boot' or 'reset'; these 8 bits seem to be related to the bit-reversal of A9-A16
- L5-L16 relate to length of read/write. "L5" represents a 32-byte block; "L16" relates to a 65536-byte block. Note that the sequence is reversed for L5-L12 as compared to L13-L16.
Taking a quick look at Private Eye Dol's address-transmission mechanism, it appears to be aware of the 2 least-significant bits of the address, but unaware that the following 8 bits are in reverse order (if I am reading it correctly). This would make it "not play nicely" with other games like Emerald Dragon. But I just started looking at that code, and will continue to look at it for a bit.
I have a quick note about MB128's getting "jammed" - when I tweaked the L13 bit (i.e. signifying 8192 bytes), and then read only 4096 bytes, it was stuck in a situation where it refused to be 'recognized' by the 0xA8 command, even after the power was removed... all it need was to exhaust the bitstream though - and this is probably why Private Eye Dol has a much higher retry count than Emerald Dragon.
Dave
|
|
|
Post by dshadoff on Apr 27, 2019 20:42:18 GMT
Well, this is VERY interesting ! I did some tests on varying the length parameter, and I'll re-label the bit-field: R/W A7 A8 A16 A15 A14 A13 A12 A11 A10 A9 xxxxxxxx L12 L11 L10 L9 L8 L7 L6 L5 L13 L14 L15 L16 Where: - R/W = '1' for read, '0' for write - "A7" is the least-significant address level, corresponding to a byte-offset of 128 bytes. Note that the sequence is reversed for A7-A8 as compared with A9-A16 - xxxxxxxx = bit-field with vague function; a '1' somewhere in here seems to imply 'boot' or 'reset'; these 8 bits seem to be related to the bit-reversal of A9-A16 - L5-L16 relate to length of read/write. "L5" represents a 32-byte block; "L16" relates to a 65536-byte block. Note that the sequence is reversed for L5-L12 as compared to L13-L16. Taking a quick look at Private Eye Dol's address-transmission mechanism, it appears to be aware of the 2 least-significant bits of the address, but unaware that the following 8 bits are in reverse order (if I am reading it correctly). This would make it "not play nicely" with other games like Emerald Dragon. But I just started looking at that code, and will continue to look at it for a bit. I have a quick note about MB128's getting "jammed" - when I tweaked the L13 bit (i.e. signifying 8192 bytes), and then read only 4096 bytes, it was stuck in a situation where it refused to be 'recognized' by the 0xA8 command, even after the power was removed... all it need was to exhaust the bitstream though - and this is probably why Private Eye Dol has a much higher retry count than Emerald Dragon. Dave OK, I just read a PM from elmer where he reminded me that the 'read/write byte' functions' shift sequence may be confusing me, and he was right. The above should read: R/W A7 A8 A9 A10 A11 A12 A13 A14 A15 A16 xxxxxxxx L5 L6 L7 L8 L9 L10 L11 L12 L13 L14 L15 L16 Where: - R/W = '1' for read, '0' for write - "A7" is the least-significant address level, corresponding to a byte-offset of 128 bytes. - xxxxxxxx = bit-field with vague function; a '1' in the first digit of this field seems to imply 'boot' or 'reset' - L5-L16 relate to length of read/write. "L5" represents a 32-byte block; "L16" relates to a 65536-byte block.
|
|
|
Post by elmer on Apr 27, 2019 21:19:18 GMT
You're getting closer, but you're still getting confused somewhere. You might want to take another look at Private EyeDol's code, and keep on comparing it to Emerald Dragon's code. I can confirm that the length is definitely in bytes, and not in 32-byte blocks. So, from my testing, the commands are ... a = 10-bit address in 128-byte increments, but usually sent as a byte a2..a9 in 512-byte "sector" increments. l = 17-bit length in terms of the number of bytes to read/write. ; ; MB128 COMMAND BITSTREAMS ... ; ; RESET ; ; 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ; ; READ DATA ; ; 1 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 0 0 0 l0 l1 l2 l3 l4 l5 l6 l7 l8 l9 l10 l11 l12 l13 l14 l15 l16 ; ; WRITE DATA ; ; 0 a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 0 0 0 l0 l1 l2 l3 l4 l5 l6 l7 l8 l9 l10 l11 l12 l13 l14 l15 l16 ;
This old thread on PCEFX (preserved here by Necromancer) "Memory Base 128 and Emerald Dragon - locks up and loses system save" has a few different people talking about Emerald Dragon locking-up their PCE while accessing the MB128. As you found, the lock-up, or "jammed" as you call it, is pretty-easy to replicate under test conditions ... just send an MB128 read command, and then don't read all of the data that you specified in the "length" parameter. The MB128 keeps on waiting for you to read the rest, and keeps the passthrough to the joypad locked-out so that you can't do anything except power-off the console. The simple short MB128 "wakeup" sequence (that Mooz calls mb128_detect) won't break out of the error condition. But the longer MB128 "reset" sequence (that Mooz calls mb128_boot, except that he's shortened the retry count too much), will actually break the MB128 out of waiting, and allow you to communicate again. I've tested this on my PCE, it works, and I can then go on and send new commands to the MB128 afterwards. I suspect that the reset bitstream itself is probably there to set the "reset" pin on the M6389 serial-memory chip in order to unlock it from whatever bad state that it's in. Anyway, if Emerald Dragon is sending that mb128_boot command with every read, then it's a pretty good indication that they knew that their code was unstable. You really shouldn't need to do that. Private EyeDol certainly doesn't do that ... it just uses the shorter "wakeup" sequence at the start of every command. Which is what I'm doing, and it works fine.
|
|
|
Post by dshadoff on Apr 27, 2019 21:40:14 GMT
Yes, you're right - after I re-read the PM, I decided to try to test other bits in the 'undefined bit field', and they are L0 - L4 as you mentioned. I just hadn't tried manipulating them until then (but it looks like you had).
...So, there are only 2 bits that we don't understand the meaning of - immediately after the address field comes the 'reset' bit, followed by the two 'unknown' bits (followed by the length field).
Not that it has any particular meaning, but... if I read after the following events, there will be a value in the first byte, followed by all '0xFF's afterward:
- reading past the end of the available data, the first byte after end will be "0xFD" - reading after sending the 'reset' command '1 0 0' in these three bits: 0xFA - reading after sending '0 1 0' in these three bits: 0xF4 - reading after sending '0 0 1' in these three bits: 0xD0
Best case, this could be a status register, or worst case it could be garbage and I'm just wishing it to mean something.
As these bits are shifted in from the left, the incoming bitfield sequence will be: 0xFD: 1 0 1 1 1 1 1 1 0xFA: 0 1 0 1 1 1 1 1 0xF4: 0 0 1 0 1 1 1 1 0xD0: 0 0 0 0 1 0 1 1
Hmmm... I don't think I'm going to explore this to the nth degree, but it *is* possible that those two bits specify smaller-than-byte returns from the data I am reading (the first byte just happens to be zeroes). So '0 0 1' could mean "half a byte", returning 4 bits of zeroes, then a '1 0' as a confirmation (followed by all zeroes afterward).
If true, this is indeed borne out by the "quarter of a byte" return, and the possibility that the "reset" command is actually just a "read a single bit" command - where the reset command actually reads a single bit as part of it...
Dave
|
|
|
Post by elmer on Apr 28, 2019 2:23:10 GMT
So, there are only 2 bits that we don't understand the meaning of - immediately after the address field comes the 'reset' bit, followed by the two 'unknown' bits (followed by the length field). ... Hmmm... I don't think I'm going to explore this to the nth degree, but it *is* possible that those two bits specify smaller-than-byte returns from the data I am reading (the first byte just happens to be zeroes). So '0 0 1' could mean "half a byte", returning 4 bits of zeroes, then a '1 0' as a confirmation (followed by all zeroes afterward). If true, this is indeed borne out by the "quarter of a byte" return, and the possibility that the "reset" command is actually just a "read a single bit" command - where the reset command actually reads a single bit as part of it... I really like this idea, it has a certain elegance and logic to it. We know that the MB128 must have a bit-counter in it in order to count up the bits in the individual bytes ... and it makes just as much sense for that bit-counter to be exposed in this way as it does for it to be hidden. It would definitely explain why there's a single-bit read in the mb128_boot reset routine ... just as there is in Private EyeDol code.
|
|
|
Post by dshadoff on Apr 28, 2019 17:49:30 GMT
It's confirmed, those last three bits define the number of *bits* to transfer, whereas the L0-L16 define the number of *bytes* to transfer. Since the memory device inside the MB128 is 1Mx1, the following explanation will only make sense when taken from the point-of-view of the PC Engine: - When writing a sub-byte-sized bitfield, the first bit in the datastream goes to the least-significant bit of the destination byte, without affecting other bits. - In other words, if the destination byte was originally '00', and you write a single-bit field of '1', the next time you read that memory into the PC Engine, it will contain 0x01. As you found, the lock-up, or "jammed" as you call it, is pretty-easy to replicate under test conditions ... just send an MB128 read command, and then don't read all of the data that you specified in the "length" parameter. The MB128 keeps on waiting for you to read the rest, and keeps the passthrough to the joypad locked-out so that you can't do anything except power-off the console. The simple short MB128 "wakeup" sequence (that Mooz calls mb128_detect) won't break out of the error condition. But the longer MB128 "reset" sequence (that Mooz calls mb128_boot, except that he's shortened the retry count too much), will actually break the MB128 out of waiting, and allow you to communicate again. I've tested this on my PCE, it works, and I can then go on and send new commands to the MB128 afterwards. I suspect that the reset bitstream itself is probably there to set the "reset" pin on the M6389 serial-memory chip in order to unlock it from whatever bad state that it's in. So, this is also quite interesting. Until now, I had not heard of the 'boot'/'reset' command being recognized by the MB128 as 'special'... on the other hand, MooZ's code would seem to only send this command *AFTER* the 0xA8 has been recognized. As MooZ's code is loosely based on Emerald Dragon's, I'm not sure whether this behavior was originally in Emerald Dragon, or introduced by his simplification process. If Emerald Dragon behaves the same way, this could explain why. In my state-machine implementation, this situation should not occur - there will be two cases where the command will abort: - if the 'data' line changes while the 'clock' line is high - if the 'data' line is seen as changing twice before the 'clock' line transitions high - since 'data' is the joypad strobe, this will definitely happen when regular joypad polling takes place. In either case (or when a transfer command has been depleted), the state returns to IDLE and the mock-MB128 gives up control. Having said this, I don't know if my state machine will adequately cope with any as-yet-unknown PC Engine requirements of the MB128. I have assumed until now, that joypad polling must be turned off when MB128 accesses are in motion (else the interaction could be corrupted). Dave
|
|
|
Post by elmer on Apr 28, 2019 21:34:43 GMT
It's confirmed, those last three bits define the number of *bits* to transfer, whereas the L0-L16 define the number of *bytes* to transfer. Excellent, thanks for confirming that! Until now, I had not heard of the 'boot'/'reset' command being recognized by the MB128 as 'special'... on the other hand, MooZ's code would seem to only send this command *AFTER* the 0xA8 has been recognized. As MooZ's code is loosely based on Emerald Dragon's, I'm not sure whether this behavior was originally in Emerald Dragon, or introduced by his simplification process. Yes, it would be nice to know what Emerald Dragon's behavior was. From my tests, the boot/reset command sequence should only be needed if the wakeup/detect sequence fails (in order to unjam the MB128). Even then, if your code is well-written, you should only ever *need* to do the reset once, during the game's bootup. As you mentioned ... no other joypad code should be running while the MB128 is being accessed. Private EyeDol protects all of its routines by disabling interrupts while they run. I don't know if there's anything special about running the wakeup sequence 256 times in a row, the way that the boot/reset code does. Perhaps there's a counter in the ASIC ... or perhaps I just got lucky and that was enough data reads/writes to finish off the data that I was reading and terminate the read/write normally. That should be pretty easy to test. The thing that we've not got any explanation for, yet, is why the EyeDol code sends three '0' bits after reading all of the data in a read command. It doesn't do that after a write command. There must be something significant about that, because that's obviously what the reset code is doing, now that we know that it is just sending a command to read one bit. I can see in your comments on Mooz's github that you've also wondered about those three '0' bits. In my testing, I've not sent those bits, and have absolutely no trouble doing multiple different reads, one after the other, as long as I send the wakeup sequence between reads. One interesting thing about that wakeup sequence is that the joypad value that it is looking for is nibble-reversed in the EyeDol code. I thought that it was looking for $04, i.e. all 4 direction bit pressed, but it is actually looking for $40, i.e. all 4 buttons pressed plus Down on the d-pad. My current guess is that what it's really looking for is to distinguish the MB128 from a mouse, because $40 is what I've believed the maximum possible mouse delta value is in a single read.
|
|
|
Post by dshadoff on Apr 28, 2019 23:43:27 GMT
The thing that we've not got any explanation for, yet, is why the EyeDol code sends three '0' bits after reading all of the data in a read command. It doesn't do that after a write command. There must be something significant about that, because that's obviously what the reset code is doing, now that we know that it is just sending a command to read one bit. I can see in your comments on Mooz's github that you've also wondered about those three '0' bits. In my testing, I've not sent those bits, and have absolutely no trouble doing multiple different reads, one after the other, as long as I send the wakeup sequence between reads. The three trailing bits are there on all of the commands... 'boot', 'read' do this, and 'write' has the two bits which are read (which should return a '1' followed by '0'), followed by these same three trailer bits. The '0xA8' synchronization sequence is a defined pattern which should be recognized when it passes through the recognition window, and the sender will send a trailing 3 bits in the event that it isn't - this is intended to adjust the skew/offset in case of misalignment, but also magically compensates for your missing three trailing bits. I haven't seen any sign that it's trying to do anything with those trailing bits - they just seem to be stop bits of some sort. One interesting thing about that wakeup sequence is that the joypad value that it is looking for is nibble-reversed in the EyeDol code. I thought that it was looking for $04, i.e. all 4 direction bit pressed, but it is actually looking for $40, i.e. all 4 buttons pressed plus Down on the d-pad. The MB128 only has 2 bits for output - the 'I'/'UP', which is the 'data' bit, and the 'Select'/'Down' bit which is only used for identification as far as I can tell. After sending the 0xA8 code, it reads a 'bit' (and check the whole port return value - because this is the only time 'Select'/'Down' is read); then it reads another bit and reads the port again to ensure that the value has toggled. Don't misunderstand what is happening here, though - it is not strobing the joypad for a "high" versus "low" value - it outputs a full cycle to the reset/clk line, returning the port to the same state as when it read the port the first time. The key is that whatever value is being presented on D3 has transitioned cleanly from '0' to '1' in those 3-4 microseconds. My current guess is that what it's really looking for is to distinguish the MB128 from a mouse, because $40 is what I've believed the maximum possible mouse delta value is in a single read. Oh, don't worry... the PCE Mouse is next on my radar after the MB128. How about a "PCE trackpad" controlled by a touchscreen on a microcontroller (how about the same microcontroller, reset to a different mode) ? Lots of possibilities... Dave
|
|
|
Post by elmer on Apr 29, 2019 1:46:21 GMT
The three trailing bits are there on all of the commands... 'boot', 'read' do this, and 'write' has the two bits which are read (which should return a '1' followed by '0'), followed by these same three trailer bits. Could you take a look at the Private EyeDol source that I posted, and please show me where these two bits are being read at the end of a write command, or where the three '0' bits are sent after that? I can't find them and am worried that I'm missing something. All that I see is a "write" command sending out 512-bytes being immediately followed by "read" command checking that the data was written correctly ... with none of the extra bits that you describe being read or written at the end of either of those commands, nor at the end of the entire save_file function. Now, the three '0' bits are definitely being sent at the end of the load_file, load_directory and mb128_reset functions ... but they certainly don't seem to be needed between individual read and write commands to the MB128. Perhaps, if I understand what you're saying correctly, the bits are sent in those functions that do send them, in order to help prime the recognition window for future "wakeup" calls. That could definitely make some sense. I've added to three '0' bits to the end of my test reads, and they certainly don't break anything ... so that's good. Perhaps I'll get a better handle on what you're describing when I try some test writes. Don't misunderstand what is happening here, though - it is not strobing the joypad for a "high" versus "low" value - it outputs a full cycle to the reset/clk line, returning the port to the same state as when it read the port the first time. The key is that whatever value is being presented on D3 has transitioned cleanly from '0' to '1' in those 3-4 microseconds. I'm sorry, but I can't agree with that. The code definitely checks for a specific high-bits/low-bits value, and not for just a change in the JOY_D bit.
Sure, I understand that the MB128 only actively drives D3 and D0 on the joypad port, but you've got to ask yourself why D3 was chosen, and what state are all of the other bits in?
In the wakeup function, the nibbles of data themselves are read when the CLR line is low, and so normal joypads are able to respond. That value corresponds to a normal joypad value of $40 ... i.e. JOY_L and JOY_R both pressed (one of those "impossible" combinations in normal joypads), plus JOY_U, RUN, SEL, I & II all pressed. It's a combination which differentiates the MB128 from all other devices, especially the mouse which, if you remember, was being designed at about the same time.
|
|
|
Post by dshadoff on Apr 29, 2019 2:28:14 GMT
The three trailing bits are there on all of the commands... 'boot', 'read' do this, and 'write' has the two bits which are read (which should return a '1' followed by '0'), followed by these same three trailer bits. Could you take a look at the Private EyeDol source that I posted, and please show me where these two bits are being read at the end of a write command, or where the three '0' bits are sent after that? I can't find them and am worried that I'm missing something. All that I see is a "write" command sending out 512-bytes being immediately followed by "read" command checking that the data was written correctly ... with none of the extra bits that you describe being read or written at the end of either of those commands, nor at the end of the entire save_file function. You're right - but looks like a bug to me, as it relies on the retries of the wakeup to re-synchronize. It's not like those extra bits are particularly meaningful, but it's a bit sloppy to forget that they're part of the protocol. The other write() code reads 2 bits, and checks that the second bit is a '0' - the real device will always return a {1, 0} sequence (assuming everything is going alright). The three trailing bits are just there as part of the protocol. Perhaps they reset something in the ASIC, but without them, the wakeup needs to retry in order to resync. Don't misunderstand what is happening here, though - it is not strobing the joypad for a "high" versus "low" value - it outputs a full cycle to the reset/clk line, returning the port to the same state as when it read the port the first time. The key is that whatever value is being presented on D3 has transitioned cleanly from '0' to '1' in those 3-4 microseconds. I'm sorry, but I can't agree with that. The code definitely checks for a specific high-bits/low-bits value, and not for just a change in the JOY_D bit. Now I see what you mean... Until now, I thought it was sequential rather than based on the value of the strobe/data line. I think I need to go back to my code and fix that. Sure, I understand that the MB128 only actively drives D3 and D0 on the joypad port, but you've got to ask yourself why D3 was chosen, and what state are all of the other bits in? ... It's a combination which differentiates the MB128 from all other devices, especially the mouse which, if you remember, was being designed at about the same time. What you're saying makes sense. Of course there had to be some thought going into it, but I suppose I wasn't really thinking about that (I guess you are thinking about it - perhaps related to the "universal device detector" code discussion from earlier this year).
|
|
|
Post by elmer on Apr 30, 2019 1:07:44 GMT
You're right - but looks like a bug to me, as it relies on the retries of the wakeup to re-synchronize. It's not like those extra bits are particularly meaningful, but it's a bit sloppy to forget that they're part of the protocol. Yep, you're absolutely right, I've confirmed that those three '0' bits are needed (for whatever reason). If I send them, the MB128 will wakeup for the next command on the first try. If I don't send them, then it takes two tries to wake it up. Interesting! Of course there had to be some thought going into it, but I suppose I wasn't really thinking about that (I guess you are thinking about it - perhaps related to the "universal device detector" code discussion from earlier this year). I'm definitely trying to keep that in mind. Especially after the thread on the old forum pointed out that some games had known problems with both a mouse and an MB128, or an MB128 and a multitap.
|
|