BS-X Satellaview Datapak's

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Revenant
Posts: 462
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: BS-X Satellaview Datapak's

Post by Revenant »

Okay, after another quick test, pin 31 is EXLED after all - grounding it turns the access LED off whenever it's enabled by $2194.
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: BS-X Satellaview Datapak's

Post by nocash »

Cool, then pin31 is confirmed. For the corresponding bits:
From what I know, access led is switched on via 2194h.bit2. But I don't know if it's 0=On or 1=On.
And bios does set both 2194h.bit2 and 2194h.bit3 to the same value, don't know if bit3 is also having some effect on the LED state (or on the EXLED behaviour).
Revenant wrote:$2197: FF
BS-X does manually set $2197 to #$80 on startup, though.
Yeah, I was wondering if the "initial" value of 80h was meant to be "after reset" or "after bios init", too. However, the bios does never set it to 80h (it's accessing the register only via "read-modifyBit7-write" code). So value 80h could occur only in emulators (if they use zero as initial value), or maybe if hardware boots up with a random value (unaffected by /reset signal).

The two serial ports with "$2198: 80 and $2199: 01"... Different DATA in bit7 may be explained by the external chips, but different CLK state in bit0 is odd. Maybe it's uninitialized/random, or maybe it's initentionally done so for different external chips (but then different chip select level would have made more sense).

The unknown/unused register "$219A: 00"... the last thing I had heard was that it's always 10h, or well, maybe that depends on state of other registers.

For some registers it would be interesting to see their values when reading more than once, eg. bits 2193 might be cleared after reading (so you might see 9F,00,00,00...), on the other hand, reading 2191 might load new nonzero bits into 2193.
User avatar
LuigiBlood
Posts: 62
Joined: Thu Jul 29, 2010 2:24 pm

Re: BS-X Satellaview Datapak's

Post by LuigiBlood »

nocash wrote:For some registers it would be interesting to see their values when reading more than once, eg. bits 2193 might be cleared after reading (so you might see 9F,00,00,00...), on the other hand, reading 2191 might load new nonzero bits into 2193.
I may have done a terrible job for other registers, but I can 100% already confirm that behavior. However, $2193 will NOT reset as long as $2194.bit0 is not set. Reading $2191 will set $2193 no matter what. Same for Stream 1 regs. I have also heard that setting $2194.bit0 actually makes a small static sound in my case.
Revenant
Posts: 462
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: BS-X Satellaview Datapak's

Post by Revenant »

nocash wrote:Cool, then pin31 is confirmed. For the corresponding bits:
From what I know, access led is switched on via 2194h.bit2. But I don't know if it's 0=On or 1=On.
And bios does set both 2194h.bit2 and 2194h.bit3 to the same value, don't know if bit3 is also having some effect on the LED state (or on the EXLED behaviour).
Bit 2 is 1=on - sort of. I tested both bits 2 and 3 and they actually both control the LED activation behavior:

Code: Select all

00 = LED always off
01 = LED on when EXLED is high (or disconnected)
10 = LED on when EXLED is low
11 = LED always on
The BIOS setting both at once is probably just to make sure that the "download in progress" LED indicator isn't affected by whatever an EXT port device might also be doing.
nocash wrote:Yeah, I was wondering if the "initial" value of 80h was meant to be "after reset" or "after bios init", too. However, the bios does never set it to 80h (it's accessing the register only via "read-modifyBit7-write" code). So value 80h could occur only in emulators (if they use zero as initial value), or maybe if hardware boots up with a random value (unaffected by /reset signal).
Yeah, you're right, I was going off of (faulty) memory there. I can confirm that it is actually initialized to 0xFF on reset, though, so the two output pins on EXT defaulting to high does make sense.

I think the only registers that don't seem to be consistent after a reset are the stream prefix/data registers, but I don't know how those are exactly supposed to behave on first power-on, since I'm currently running on my Super UFO that has its own memory mapping registers overlapping with some of the ones controlling the data streams (but the UFO doesn't touch $2194, and that's initialized to 0x00, so the prefix/data ports might just be essentially returning garbage).
nocash wrote: The two serial ports with "$2198: 80 and $2199: 01"... Different DATA in bit7 may be explained by the external chips, but different CLK state in bit0 is odd. Maybe it's uninitialized/random, or maybe it's initentionally done so for different external chips (but then different chip select level would have made more sense).

The unknown/unused register "$219A: 00"... the last thing I had heard was that it's always 10h, or well, maybe that depends on state of other registers.

For some registers it would be interesting to see their values when reading more than once, eg. bits 2193 might be cleared after reading (so you might see 9F,00,00,00...), on the other hand, reading 2191 might load new nonzero bits into 2193.
I think what LuigiBlood says about the prefix/status registers is correct - the only different thing I've noticed so far is that if a stream fails (i.e. error bits in $218B/2191), the "first packet" flag in bit 4 might not be cleared when reading the prefix bytes. But it's probably unpredictable if an invalid stream will even cause that bit to be set in the first place; sometimes when booting via the Super UFO or sd2snes then I get constant prefix/data bytes of 0x9F and 0x00 for stream 1 but 0x8F and 0x80 for stream 2, or things like that, and the values stay the same even when repeatedly resetting the console.

I'm going to do some more different tests with the other registers soon (esp. $2199-$219F), though I don't really have a way to tap any of the pins on the DCD-BSA chip which probably limits what else I'll be able to figure out for now.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BS-X Satellaview Datapak's

Post by Near »

<copy paste from my own forum: https://board.byuu.org/viewtopic.php?f= ... 166#p57166>

I rewrote my BS Memory flash emulation to use type 1 cartridges instead of type 2 cartridges, since only type 1 cartridges actually exist. I may or may not bother with type 2. Kind of annoying to emulate something that's impossible to test.

I ran my own hardware tests to clarify some things, and discovered some new information.

First, the MCC has two types of write-enable for the BS memory carts.
$0c5000.d7 enables the query interface
$0d5000.d7 enables the write command (the one that clears bits)

If you don't set $0c5000.d7 and commit the change (by writing $0e5000.d7), then all writes to the BS memory cart will fail, and all reads will be the ROM data. It will act exactly like a ROM cartridge. If you do set it, then you can write values to it to query status registers, vendor information, erase data, and write bytes.

If you don't *also* set $0d5000.d7, then all writes (type 1 flash commands $10 and $40) will fail. However, *erases still work!* even if you don't set $0d5000.d7. Both the 64K page erase, and the entire-chip erase work regardless of $0d5000.d7.

Obviously, if $0c5000.d7 is clear, there's no way to trigger a write, so for write commands to work, you must have both $0c5000.d7 and $0d5000.d7 set.

Next, $0f5000.d7 is truly bizarre. If I write $0f5000.d7=1, then I can read any one $0x5000 status register. The second time I try and read one, the entire SNES deadlocks until I reset it. If I write $0f500.d7 before every read, then I read back the same exact values I normally get from $0x5000.

This does not appear to be an extra page of extended bits, at least not on my system.

I still don't emulate $01500.d7 IRQs. Unsure how exactly those work.

Okay, now for the flash carts themselves ... there are no two-byte commands as with bsnes-plus.

Writes act on the current mode, and then change the mode, but only when the low 16-bits of the address are all zeroes. So $c00000 and $cf0000 will work for writing $75 to get vendor information, but $c08000 will not. I'm guessing in LoROM configuration that it's the decoded low 16-bits? But I didn't verify that.

So with this setup, if you write $10 to write a byte, or $20 to erase a page, or even $a7 to erase the entire chip (which ostensibly doesn't need another byte of data), nothing will happen until the next write, which doesn't care about the address (other than $20 using the upper eight bits instead of the data bus bits to determine which page to clear.)

nocash mentioned $97 being some kind of alternate full-chip erase mode ... it does nothing here, whereas $a7 does.

Revenant had $40 as an alternate write command, and I can confirm that does indeed work. Weird.

$10, $20, $40, $a7 writes seem to kick the mode to $70 automatically. Games seem to do it anyway, but it doesn't appear necessary to do so.

Reading from mode $70 always returns a single status byte, no matter what the address is.

Reading from $71 always returns zeroes, except in three cases that I can see:
(address&$ffff) == 2
(address&$ffff) == 4
(address&$ffff) == 6
The last one is usually zero, but if perform an erase command, the value changes around. I've seen $70 and $8f from it.

I'm going to guess that (address&$ffff) == 0 is something too, but so far it only returns zeroes for me.

Reading from mode $75 returns vendor information. In this case, it looks at the low 8-bits of the address.
(address&$ff) == 0 ? return 'M'
(address&$ff) == 2 ? return 'P'
(address&$ff) == 4 ? return 4 (unknown purpose)
(address&$ff) == 6 ? return type << 4 | log2(size >> 10);
All other addresses return ... noise. I tried four different BS memory packs, and all four had different values in every single byte, and the values never changed. The values are not ROM values, and they're not open bus.

Here, see if you can make any sense out of it:

Code: Select all

[Cartridge 1] => 4d 50 04 1a 00 00 20 31 22 99
c0ff00  4d 1c 50 16 04 ef 1a 7d 00 bf 00 6e 20 eb 31 05 
c0ff10  22 73 99 52 f6 cb 4a d3 64 fb 7e 78 1a d8 20 27 
c0ff20  55 cd 4c e4 f7 58 2f df 27 d7 75 a8 e6 3a b0 28 
c0ff30  f4 9b 2e 21 fe fa c8 3c 99 af a6 9f f0 ff 13 a2 
c0ff40  50 b6 fa e4 af ad 0f 30 2c 9d b3 7d 73 96 ee 85 
c0ff50  00 34 14 a2 77 63 70 79 23 33 f5 64 d7 e1 8a e8 
c0ff60  e9 94 68 30 b8 6d ce 71 ba ff e7 64 93 82 9e 7b 
c0ff70  12 29 5a 8c 6a cf e5 bc 6a 98 bb 4d 8f a0 9d 61 
c0ff80  8e e9 36 a6 f0 28 7b 8a 4b df d9 6b 49 06 12 82 
c0ff90  68 0e 15 a4 db 9d ab 5d 6c 35 b3 37 75 0e 46 60 
c0ffa0  11 e7 19 1b 2e 7d 99 ac bf 0e 9a 8f 3a e2 98 07 
c0ffb0  94 ec 4a e3 e2 fb f2 7e 16 1e 7b fd 11 2a 03 f6 
c0ffc0  d5 00 20 89 9e 32 0d bd 75 69 ed fa 2f dc 06 01 
c0ffd0  78 2b df 4b 3f 3f 1e d4 de 7a 93 5a 1e 43 51 ae 
c0ffe0  fc d2 20 21 54 f3 0b e7 ff ef 8b dd 93 52 d6 c5 
c0fff0  32 66 30 b8 6c 5f 0a f3 83 e5 7f f8 0f f3 2e 64 

[Cartridge 2] => 4d 50 04 1a 00 00 20 41 12 33
c0ff00  4d e7 50 d5 04 ef 1a df 00 6f 00 ff 20 59 41 94 
c0ff10  12 2c 33 b3 47 6d 73 ed 6c d6 ff fd 48 00 13 03 
c0ff20  03 a8 a3 63 ed 69 bf de ef fd fe ff de ce a5 12 
c0ff30  b2 33 a0 a9 e7 ef 9f f1 4b 7d de 7f fc 40 20 51 
c0ff40  b1 64 03 82 a9 7f df da ca e7 ba f7 34 5a c0 44 
c0ff50  a0 26 1f 2e b7 0b 3b a5 bb bb 35 be b0 d6 41 48 
c0ff60  1a 47 16 4c 97 c3 53 fa fa 7e df ff b0 1e a6 60 
c0ff70  f6 84 a4 0f 1f ad ed 3f ef ff af e9 1c 80 34 80 
c0ff80  87 98 8a 14 fb 7d f6 fa 2e 3d ef fc c1 d3 93 65 
c0ff90  55 05 ed 47 bd e3 17 1b 3b fb 7d 75 39 64 4d 61 
c0ffa0  02 c6 28 50 e6 df a9 7e fe 7f e3 fd 2b 43 af 04 
c0ffb0  1c 3c 67 92 69 ab 7a bd 7f af a5 f7 03 cb 80 de 
c0ffc0  4a 58 21 48 fe 73 87 bf 7d 6e ff fd 08 84 5a 30 
c0ffd0  18 07 92 69 9f fd ff 75 7a cf ef 8e 48 d2 e5 5a 
c0ffe0  1a 83 60 74 4f de 72 b7 bf f3 fb fb 09 81 a3 69 
c0fff0  38 64 57 94 ed 7a f1 fd bf ff e3 fb 82 15 e2 94 

[Cartridge 3] => 4d 50 04 1a 00 01 40 41 70 59
c0ff00  4d ab 50 7a 04 0b 1a fe 00 34 01 fc 40 f6 41 02 
c0ff10  70 89 59 89 fe 97 bd bd 9f 54 df 7a bc 8a c6 bf 
c0ff20  03 94 f9 88 3d d3 f7 fd 36 7e e7 fe cf 6f ed 19 
c0ff30  93 94 1e 6a ac 0f fb d9 53 72 c7 fe f7 92 db 0e 
c0ff40  0e 2a 1b 23 5b d4 9b fd be fb 67 5c 24 d1 7f 56 
c0ff50  b8 44 c6 2e 13 a5 fe ef e5 d7 ad 3a 7b 3e d7 03 
c0ff60  02 bf dc e1 f4 6b f7 d9 31 56 3a 58 21 30 9e 62 
c0ff70  bd b0 ea 59 79 7b 34 6c 77 ba 27 fd a1 1a 98 91 
c0ff80  3a 3e 9c 3b d9 ac b7 e7 76 cf 2c fd fc 3f f9 1b 
c0ff90  2e aa 32 ed 9e ce b7 1c 39 fb f3 b7 3f 58 05 46 
c0ffa0  09 93 17 80 6f e6 f6 04 ef ed 0f bf c1 26 7b 74 
c0ffb0  84 a3 36 b2 86 0a b4 fd 6b b3 85 f6 54 12 60 94 
c0ffc0  5f 91 3a 78 a4 03 d7 18 ef 89 5c 7f 1d 47 2c 20 
c0ffd0  bd 57 f2 00 da a2 1e 87 7f f0 e0 b9 2d 35 2b ab 
c0ffe0  70 6f c5 7b 9d 90 17 5d bd f7 dd fe 01 6a 3d fd 
c0fff0  1e f3 ac 8b df ba b6 dc 27 c6 ab 79 35 98 87 ac 

[Cartridge 4] => 4d 50 04 1a 00 91 90 70 31 03
c0ff00  4d 42 50 ca 04 bc 1a 7f 00 fe 91 ed 90 6a 70 28 
c0ff10  31 90 03 9c c2 ff 5f 47 dd fb 7e bd 01 00 cc 02 
c0ff20  37 22 5c 40 5a f7 e7 f5 df fe fe d7 10 00 4b 94 
c0ff30  95 8a f5 0e 65 de eb fd ba 3b fe ff b7 4c e0 28 
c0ff40  23 46 46 31 ee ff ff fb ff ff ff f9 4f 18 92 54 
c0ff50  e8 03 40 00 f7 66 7f 3d ff d7 eb 5f 00 32 12 40 
c0ff60  a2 29 95 80 97 bb fe 77 fe de 3f eb 07 60 98 c8 
c0ff70  83 a9 64 a0 fd 6e ff ed fe ff eb fb 25 36 c8 48 
c0ff80  a9 38 c2 44 5d 79 7b 7f ff 77 f7 ff 44 1b 62 9d 
c0ff90  a8 02 04 60 ff df ff f9 bf b7 de 3d 22 b2 25 02 
c0ffa0  1b c3 23 04 f7 6f 9d bf bf ff fd 9f b2 e3 eb 3a 
c0ffb0  40 0f 4b 06 fd 2f eb ec ff f7 bf f9 84 47 06 94 
c0ffc0  02 00 67 50 ff ef ce bb fb bf fb 3f 4e 38 62 04 
c0ffd0  56 60 5b 11 fe a9 bf 9f f7 ab 8f de b1 40 0c ea 
c0ffe0  26 70 15 05 ef be ee eb ff ff fd f3 08 08 5a a0 
c0fff0  60 46 81 04 f7 ff e2 3e ff 5f ff fb 80 a2 e6 61 
One pack had an RPG Tsukuru 2 save on it, and I get the exact same 256 values back even after I later erased the cartridge. If it was reading data from the BS-X Town cart ROM/SRAM/PSRAM, then it'd be the same values for all cartridges, but it isn't.

Again note it only looks at address&$ff. You can read from $c00000 or $c1fe00 and get the same data. If you try and read from $c0ff02, it starts from address 2, not 0, so it's not a counter.

More fun ... there's a ton of mirrors of the three readout modes.

$70 mirrors to $76 - $7d, and I also saw it at $6d and then stopped because what the hell >_<
$71 mirrors to $72 - $74, and probably to more areas.

I didn't try and enumerate all 256 values because some of them are write/erase commands.

I'll need to write a fancier test that tries all 256 values and maps out what they do, I guess.
Revenant
Posts: 462
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: BS-X Satellaview Datapak's

Post by Revenant »

byuu wrote:Next, $0f5000.d7 is truly bizarre. If I write $0f5000.d7=1, then I can read any one $0x5000 status register. The second time I try and read one, the entire SNES deadlocks until I reset it. If I write $0f500.d7 before every read, then I read back the same exact values I normally get from $0x5000.

This does not appear to be an extra page of extended bits, at least not on my system.
Strange. ikari's and nocash's notes already differ about what that bit does (according to nocash it's the extra page, according to ikari "strange things happen, apparently the MCC assumes A23-A19 = 0 when set"). Are you able to tell if writing it does anything to the actual memory mapping?

I can try to test this on my BS-X cart as well, now that I actually own one.

re: the flash memory packs, for reference, here's a datasheet for Sharp flash chips that pretty much everything in existing implementations is based on (largely via LuigiBlood/nocash/etc's documentation).
byuu wrote: So with this setup, if you write $10 to write a byte, or $20 to erase a page, or even $a7 to erase the entire chip (which ostensibly doesn't need another byte of data), nothing will happen until the next write, which doesn't care about the address (other than $20 using the upper eight bits instead of the data bus bits to determine which page to clear.)
$20 and $a7 (according to the sheet) supposedly requires writing $d0 once to confirm the erase, plus a second time if a suspend command was issued previously (at least that's how I'm reading it). But for $20, if you write $d0 more than once, the address only seems to matter for the first write.
byuu wrote: nocash mentioned $97 being some kind of alternate full-chip erase mode ... it does nothing here, whereas $a7 does.
$97 is called "upload status bits", which sounds like it's supposed to latch the initial state of the block status registers after powering up (and requires another $d0 write to any address to confirm), but it's not clear if you're supposed to do that every time you read the registers, or just the first time.
byuu wrote: Revenant had $40 as an alternate write command, and I can confirm that does indeed work. Weird.
$40 and $10 are listed respectively as "word/byte write" and "alternate word/byte write". No idea if there's supposed to be a difference between the two, but they're listed right next to each other in the list of commands and have identical descriptions.
byuu wrote: $10, $20, $40, $a7 writes seem to kick the mode to $70 automatically. Games seem to do it anyway, but it doesn't appear necessary to do so.
Writing $b0 ("erase suspend/resume") is also supposed to do this.
byuu wrote: Reading from mode $70 always returns a single status byte, no matter what the address is.

Reading from $71 always returns zeroes, except in three cases that I can see:
(address&$ffff) == 2
(address&$ffff) == 4
(address&$ffff) == 6
The last one is usually zero, but if perform an erase command, the value changes around. I've seen $70 and $8f from it.

I'm going to guess that (address&$ffff) == 0 is something too, but so far it only returns zeroes for me.
Reads from $70 are the "compatible status register", which has to do with the basic read/write/erase commands (the datasheet calls these the "compatible mode commands", as opposed to the other chip-specific ones).

For $71, addresses 2 and 4 are the block status register (for a specific block of addresses) and the global status register. 0 and 6 are both listed as "reserved", so I have no idea what the value read from 6 is supposed to be. Can you tell if it matters whether the erase is still in progress when reading that one?
byuu wrote: Reading from mode $75 returns vendor information. In this case, it looks at the low 8-bits of the address.
(address&$ff) == 0 ? return 'M'
(address&$ff) == 2 ? return 'P'
(address&$ff) == 4 ? return 4 (unknown purpose)
(address&$ff) == 6 ? return type << 4 | log2(size >> 10);
All other addresses return ... noise. I tried four different BS memory packs, and all four had different values in every single byte, and the values never changed. The values are not ROM values, and they're not open bus.
Writing $72 supposedly swaps between two different pages of this, though I believe/assume only page 0 is actually used by BS-X. I assume any byte that BS-X doesn't actually explicitly check is just garbage.

There are also several commands for writing to these buffers, and according to these notes writing $38+$d0 will reset their contents, but I'm not sure if that means losing the "M P " signature and size info, etc. and that command isn't even listed in the datasheet... (the info there about $08 and $38 possibly only applies to type 3/4 carts if any even exist?)
byuu wrote: More fun ... there's a ton of mirrors of the three readout modes.

$70 mirrors to $76 - $7d, and I also saw it at $6d and then stopped because what the hell >_<
$71 mirrors to $72 - $74, and probably to more areas.
This doesn't seem right... at least going by the same Sharp datasheet, $72, $74, and $77 are all separate commands.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BS-X Satellaview Datapak's

Post by Near »

Okay, going at this more tonight ...

$38 isn't documented in the data sheet, and it also doesn't complete until you write $d0 after.

It has two effects, actually: it writes the vendor info into the current page buffer, *and* it toggles the current page buffer after that. So if you do this after a reset:
$c00000 = #$38
$c00000 = #$d0
$c00000 = #$75
read($c00000..c000ff)
You will get data from the second page, but it won't have the magic markers in memory because you're reading from the wrong page. Write $c00000 = #$72 between #$d0 and #$75 to read back the current page you modified.
Detection Sequence
[C00000h]=38h, [C00000h]=D0h ;request chip info part 1
delay (push/pop A, three times each) ;delay
[C00000h]=71h ;enter status mode
repeat, X=[C00002h], until (X.bit7=1) ;wait until ready
[C00000h]=72h, [C00000h]=75h ;request chip info part 2
FOR i=0 to 9, info=BYTE[C0FF00h+i*2], NEXT ;read chip info (10 bytes)
[C00000h]=FFh ;somewhat bugged, see below ;terminate status mode


Which is exactly what the BS-X BIOS is doing here.

...

Now that I know how to write to the page buffer, I can fill it with $00, $55, $aa, $ff, and clearly see what bytes $38d0 is writing:

$00 = #$4d
$02 = #$50
$04 = #$04
$06 = #$1a
$08 = #$00
$0a = #$91
$0c = #$90
$0e = #$70
$10 = #$31
$12 = #$03

Or with a few cartridges ... good thing Matthew Callis sent me a box of them:

Code: Select all

#1 => 4d 50 04 1a 00 91 90 70 31 03
#2 => 4d 50 04 1a 00 00 20 31 22 99
#3 => 4d 50 04 1a 00 00 70 31 85 78
#4 => 4d 50 04 1a 00 00 10 50 24 43
#5 => 4d 50 04 1a 00 01 40 41 70 59
#6 => 4d 50 04 1a 00 00 20 41 12 23
#7 => 4d 50 04 1a 00 00 10 41 20 64
#8 => 4d 50 04 1a 00 02 80 31 22 83 (FLASH marking: 9517 5 OA)
#9 => 4d 50 04 1a 00 00 10 62 62 39 (FLASH marking: 9517 5 OA)
The values are static for each cart. The first four (or five) digits are always the same, and then the rest change.

Do you see it? These are unique serial numbers.

...

The page buffers themselves are really, really cool. You can fill them with bytes using:
$c00000 = #$74
$c000xx = #$data
<repeat>

And there's even a sequential write command that I need to try out.

Once you have them, you can write out all or a portion of the page buffers directly to the flash memory, and it works even where bits were zero. So it probably combines an erase with writes or something.

#1 is the odd one out, #$91 where the rest are #$00,#$01,#$02. So I doubt these are even strictly sequential.

...

The page buffers themselves are volatile, they decay to random data after a time of no power to the cartridges. It's not immediate though. If you quickly turn the system off and back on, you'll still have your old data. It decays to high entropy values (at least compared to SRAM/DRAM chips on the base SNES.)
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BS-X Satellaview Datapak's

Post by Near »

The intelligent identifier (activated by writing #$90) is another readout mode of this chip.

It returns the following data on all cartridges:

Code: Select all

c00000  b0 a8 63 20 20 20 20 20 20 20 63 20 20 20 20 20
c00010  20 20 63 20 20 20 20 20 20 20 63 20 20 20 20 20
...
cffff0  20 20 63 20 20 20 20 20 20 20 63 20 20 20 20 20
A better way to describe it:

Code: Select all

if(ReadMode == IntelligentIdentifier) {
  if((uint24)address == 0) return 0xb0;  //only appears once in the entire address space
  if((uint24)address == 1) return 0xa8;  //only appears once in the entire address space
  if( (uint3)address == 2) return 0x63;  //repeats every eight bytes: (address&7)==2
  return 0x20;  //fills in all remaining bytes
}
This is supposed to return the manufacturer and device ID#s.

According to the PDF, the LH28F016SANS-70 has:
Manufacturer ID# 0089H
Device ID# 66A0H

In 8-bit mode (which is what our BS Memory Cassettes operate in), these IDs are shortened to:
Manufacturer ID# 89H
Device ID# A0H

The device ID would obviously be different for the Sharp LH28F800SUT-ZI, but the manufacturer ID would not.

On a whim, Nintendo's manufacturer ID is 0553H (Bluetooth), 057EH (USB), 12E1H (PCI).

I found a match here: http://www.idhw.com/textual/chip/jedec_spd_man.html

Sharp has a manufacturer ID under 10110000 (B0), which begs the question why the datasheet says their manufacturer ID is 0089H.

The datasheet indicates we can only read out the low bytes of the IDs in 8-bit mode, and yet I have four unique values.

I guess the only way to be sure will be if someone can desolder the flash memory from a BS Memory Cassette, wire it up in 16-bit mode, and read out the full 16-bit IDs for us. Until then, this emulation will have to do.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BS-X Satellaview Datapak's

Post by Near »

Uh ... remind me again why we're looking at the datasheet for the LH28F016SANS-70, when the datasheet for the LH28F800SU is readily available?

https://www.dataman.com/media/datasheet ... F800SU.pdf

Manufacturer ID# 00B0H (B0H in 8-bit mode)
Device ID# 66A8H (A8H in 8-bit mode)
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BS-X Satellaview Datapak's

Post by Near »

https://pastebin.com/raw/YpNrrxYP
(note: I forgot to increment the erase counters on page writes to flash.)

Okay, with the exception of the critical emulation of commands taking time to complete, this should be a complete implementation of the Sharp LH28F800SUT-ZI in 8-bit configuration.

For a quick overview:

The block lock flags don't appear to do anything. Whether they are set or not, I can both write and erase the flash data.

On power-up, all of the block lock flags read as set. There are 16-bits of non-volatile storage inside the flash chip that hold their last written state. Executing $97d0 after a reset will load those bits in for you.

Locking a page with $77d0 will update both the readable BSR lock flag, and the non-volatile bit. Erasing a page via $20d0 or $a7d0 is the only way to clear the lock flags once they've been set.

Erase commands can execute whether $0d5000.d7 is set or not, but write commands will fail if that's not set.

No commands work if $0c5000.d7 is set. Current theiry is that $0c5000.d7 is internal to the MCC and controls whether it sends /WR to the BS Memory Cassette, and $0d5000.d7 is likely /WP to the BS Memory Cassette.

$0c is a really cool command that erases a block for you, and will then write out a 256-byte block to flash. It actually takes a 16-bit value, so you can write out 65536 bytes of data to the flash if you wanted, it'll just keep repeating. The address portion of $0c is the same for both the flash write and page read, so eg if you write to $c25037 - $c25038, it will write from the page buffer $37 to $38, not from page buffer $00 to $01.

$38d0 writes out a unique serial# per BS Memory Cassette to $80,$0a,$0c,$0e,$10,$12 of the page buffer. Along with the Nintendo-specific information at $00,$02,$04,$06. The rest of the active page buffer bytes are untouched.

$80 abort seems to set the GSR sleeping flag. I have no idea how to clear the sleeping flag for either $80 abort or $f0 sleep.

$90 gives you the low-byte of the vendor ID, then the low-byte of the product ID, then some noise. It fills the entire 256-byte page.

$96(01,02,03,04) says something about ready-busy mode in the PDF, but I don't understand it. It may not even be observable from the SNES, if it's just pulsing pins?

$99d0 is a truly fascinating command ... it writes #$06 to page address $06, and #$00 to page address $07, which is constant with all of my BS Memory Cassettes. It also writes 32-bit block erase counters, which are non-volatile, in a weird way to memory.

The block counter starts at 0x80000000, and increments by one with every block erase command. I don't have any never-erased packs, so I couldn't tell you if it starts at 0x00000000 or not.

There's sixteen of these 32-bit counters, one for each block, written into memory locations at:
(block&3)*8 + (block>>2)*0x40, eg:
00-03, 08-0b, 10, 18, 40, 48, 50, 58, 80, 88, 90, 98, c0, c8, d0, d8-dc.

I have no idea how this would change if you had a 16mbit or 32mbit flash. There's room in there for them (up to 64 blocks, so 32mbit), but if I were to try and emulate it without having one of these non-existent carts, I'd have to guess where the rest of block counters went.

$e0 is a very interesting command, the only one like it, and it screws with simplistic attempts at a command queue. You write $e0, then the low byte count, then the high byte count, then you keep writing address:data pairs to write to the page buffer. A high byte count other than $00 is pretty dumb but, it's supported if you wanted to do that ... I don't think you an abort this one?, so don't write $ffff unless you want to do a whole lot of writing, or reset your console.

$fb is a 16-bit word write command, with some funky behavior. A0 of the second write controls whether the second and third writes are data low, data high (A0=0), or data high, data low (A0=1). The target location comes from the third address write, and instead of incrementing the address, it does a ^1.

Corrections and more information would be greatly welcome.

With the unique serial#, the non-volatile lock status bits, and the flash write counters ... I've decided to store these attributes in a BML manifest alongside the flash ROMs themselves.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BS-X Satellaview Datapak's

Post by Near »

Oops, major mistake on my part ... I didn't realize the flash was already FF from a previous erase command ...

The write to flash from page buffer command is a write only, not an erase + write. Realized that when I was thinking, "but wait, it doesn't write entire blocks at once ... how could it erase the blocks first, then?" >_>

So yeah, write from page buffer stores: write(address, read(address)&data)); and doesn't increment the erase counters, of course.

Amusingly, the emulation code was already correct in that case.

---

Aha, finally! Figured it out.

Okay, $0c5000.d7 works as I explained. If you set it, /WR is disconnected from the memory pack, and so it acts exactly like a mask ROM cart would.

$0d5000.d7 controls /WP on the memory pack.

So what happens is that if you set $0d5000.d7, it's like an override that forces the memory pack to always be both writable and erasable, regardless of the lock bit.

The lock bits come into play when $0d5000.d7 is low. In this case, writes and erases fail when a block is locked, but will succeed otherwise.

Once you lock a block, the only way to unlock it (that I know of) is through erasing the block. And to erase a locked block, you have to set $0d5000.d7 first.

Locking a block requires $0d5000.d7 to be set. Even if the block is already locked. If you execute this command anyway with $0d5000.d7=0, then regardless of the current lock status bit or non-volatile lock bit, it'll set CSR.d4,5 + BSR[n].d5 + GSR.d5. And if the page was already locked, it obviously remains locked.

It's an open question how the other BS-X slotted cartridges work. My guess is that without $(0c,0d)5000.d7 available (no MCC), the write protect feature is always disabled, and it will always allow commands to be sent to flash carts.

...

Also, it seems another mistake I made earlier: the $d0 terminal byte is important. $77d1 will set the block error bit and not lock the page, whereas $77d0 will indeed lock it.
Last edited by Near on Thu Sep 13, 2018 5:24 am, edited 1 time in total.
User avatar
LuigiBlood
Posts: 62
Joined: Thu Jul 29, 2010 2:24 pm

Re: BS-X Satellaview Datapak's

Post by LuigiBlood »

Isn't 0E:5000 just a way to apply changes? Or is it that our comprehension of it was completely wrong from the start and all changes are actually instant?
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: BS-X Satellaview Datapak's

Post by Near »

Oops, sorry. Was off by one on the addresses. s/$0d5000/$0c5000, s/$0e5000/$0d5000 in the last post. Fixed it.

Also, more fun ... the theoretical LH28F032SU (32mbit flash chip) variant (well, the chip is real, the BS Memory Cart with it is not) is going to be a lot more painful to emulate properly. As was pointed out to me on Twitter, this chip is just two LH28F016SU's glued together. And of course, the LH28F016SU is *not* two LH28F800SU's glued together.

So basically what this means is that:
8mbit => $c0-cf:0000-ffff = LH28F800SU (16 x 65536 x 8-bit)
16mbit => $c0-df:0000-ffff = LH28F160SU (32 x 65536 x 8-bit)
32mbit => $c0-df:0000-ffff = LH28F160SU #1 + $e0-ff:0000-ffff = LH28F160SU #2

This changes a lot:
* a full chip erase requires $a7d0 to be sent to eg $c00000 and $e00000
* status mode changes have to be done on each chip separately
* the block erase count retrieval command will only populate 32 entries per chip
* the device ID really is going to be the same for both the 160SU and 320SU as a result
* you could technically do certain operations with one chip while the other is busy
* proper timing emulation of the flash write commands will require *two* threads instead of one

The 4mbit variant is also annoying as heck. That one's 32 x 16384 x 8-bit, so it invalidates assumptions like 64KB block sizes.

I think I'll drop support for 32mbit flash carts, and just keep 8mbit and 16mbit sizes supported.
Revenant
Posts: 462
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: BS-X Satellaview Datapak's

Post by Revenant »

Interesting stuff, thanks for looking into it more.

Assuming I do update my BS-X flash emulation based on this info, I'll probably try to keep supporting sizes other than 8 and 16 Mbit just because BS-X does; I guess I could just have two instances of a generic flash chip class (with either 16kb or 64kb block size) and let the existing BSXFlash class be an interface to both of them. I also currently support 2 Mbit flash, which could probably be treated as 16x16k(?)
Revenant
Posts: 462
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: BS-X Satellaview Datapak's

Post by Revenant »

Also, I don't think I remembered to mention this before but I did confirm that the bits in $2197 also work as (active low) inputs.
Post Reply