Jump to content
IGNORED

Atarimax cartridge writing question


Recommended Posts

Hi, all!

 

I want to do some experiments with atarimax flashcarts. I want to write some portions, but I don’t know how. I looked into atarimax site to fine some documentation, but without results. Does anyone know how to do this?

 

I want to erase blocks and write banks.

 

Thank you in advance!

Link to comment
Share on other sites

I have never understood why I can never find a direct "This is how you write to a bank" anywhere at all on the internet.

 

That isn't a dig at you Wrathchild as you have been helpful by pointing out the page, it is more of an overall comment.

 

I have seen a lot of comments like "You can look it up on this page at the bottom" or "It has been explained before", but never the direct statement of how to do it. When following the links, they all appear to lead you towards an answer but never quite do.

 

Interestingly enough, the provided link is still one of the best that I have ever seen, though it appears that it is not working in practice according to the comment.

 

Perhaps it is due to the original documentation being lacking. Maybe the saves are unreliable??? I don't know that for a fact though.

 

Has anyone here implemented a saving routine that can be directly copied and pasted into here with all required procedures?
 

I can imagine a lot of people taking up programming for the AtariMax if we had this information in the open.

 

Currently I am writing a game for the AtariMax but it saves to disk, it would be so much better if it saved to cartridge.

Link to comment
Share on other sites

I've attached some MaxFlash code originally written by Steve Tucker designed to be called from Quick programs.  In order to save some calls I modified it a bit, but the reading and writing still work the same.  Please keep in mind that the examples below are at a fairly high level - you can drill down into the code to see what actually makes the cartridge work.

 

To write:

  NewSetSector(Sector#) - choose the sector to act upon

  NewEraseSect(Sector#) - must be done before writing *

  NewWrite(CartPage#,RAMPage#,NumPages#)

 

To read:

  NewSetSector(Sector#) - choose the sector to act upon

  NewRead(CartPage#,RAMPage#,NumPages#)

 

Because of the nature of Quick (the cartridge memory area and Quick's variable table are both located at $B000) a few accommodations needed to be made.  Since Quick can't access the cartridge directly, it calls the MaxFlash code - which, when reading, moves the required pages from the cartridge to the specified RAM location, or when writing does the opposite.

 

* Once a sector is erased, any page on that sector can be written - once.  The only way to re-write a page, is to first erase the sector it resides on.

 

The code uses the A, X and Y registers to pass parameters.

 

Note:  With a 1mb cartridge, sectors are 64K blocks numbering between 0 and 15 

 

 

I hope this is somewhat useful!

maxflash.a65

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

21 minutes ago, jacobus said:

Note:  With a 1mb cartridge, sectors are 64K blocks numbering between 0 and 15

Best to clarify here that it means a 1 Megabyte (8 Megabit) cartridge which has two 29f040 chips, each 512 Kilobytes, with a 64 Kilobyte erasable block size. So (512 / 64) = 8 blocks per chip

 

The 128 Kilobyte (1 Megabit) cartridge has one 29f010 chip with a 16 Kilobyte erasable block size. So 128 / 16 = 8 blocks.

Link to comment
Share on other sites

41 minutes ago, Wrathchild said:

Best to clarify here that it means a 1 Megabyte (8 Megabit) cartridge which has two 29f040 chips, each 512 Kilobytes, with a 64 Kilobyte erasable block size. So (512 / 64) = 8 blocks per chip

 

The 128 Kilobyte (1 Megabit) cartridge has one 29f010 chip with a 16 Kilobyte erasable block size. So 128 / 16 = 8 blocks.

Yes absolutely!  And please let me note that my code has only ever been used on a 8mbit cartridge.  Not sure how or if it will work on the 1mb version.

Link to comment
Share on other sites

Something cool about the 8Mbit cart is that you can mix an 040 and an 010 inside and address them accordingly. You get a smaller overall size (512+128 = 640 KBytes, still about 7 single-density disk sides!) but can utilise the smaller erase block size of the 010.

 

My ideal would be to put an SST29SF010/020/040 in there instead as these have a uniform 128 Byte sector erase layout and so effectively you can treat them as sectors on a disk.

This way I had envisioned implementing Seven Cities of Gold as a cart so that the map building would be able to read/write to flash memory whilst creating the world. :)

 

The 128 Byte sector size should also permit you to use an xBios approach to read/write sectors and treat the cart memory as a file system.

Edited by Wrathchild
xBios
Link to comment
Share on other sites

3 hours ago, jacobus said:

Once a sector is erased, any page on that sector can be written - once.  The only way to re-write a page, is to first erase the sector it resides on.

This isn't true as the result of flash chip byte write can be viewed as the 'and' of the existing and new value.

Due to the erase all bits have been set 'high' and so the AND of the intended value is the intended value.

Therefore if you were to write the same values over an already written area then that will still read correctly.

So think of it as 1's can become 0's but 0's cannot become 1's.

 

The chip spec's tend to state a 10,000 writes limit though in reality it is probably higher.

So if wear is a concern then a form of write levelling could be employed to extend the life.

 

An example approach could be one that permits smaller save areas to be used across a larger block.

e.g. if your save data area was only 1K then you could cycle these over 8 save positions *.

Done by checking the first byte of the block (i.e. $A000) and if not $FF then add 1K ($400) to the address pointer and test until a $FF is found.

Then write the save data to that block, ensuring the first byte is not $FF.

If all 8 blocks are full then the block can then be erased and so the save takes place from the beginning again.

 

* - chosen for the simplicity of keeping things in the cart window, you'd actually do this over the whole erase block size.

 

This causes a little bit of trickiness in terms of identifying the 'last' save block, for example when the game is powered on it loads the high-score table.

By walking the $A000, $A400, $A800 etc addresses, when you find the $FF, or the address reaches $C000, then you read data from the preceding 1K block.

 

Link to comment
Share on other sites

You may want to also employ some method of making sure that the data finished writing properly (i.e., the power didn't go out during the write).

 

There are many ways to do this, but a couple of simple ideas would be to have a checksum or CRC that gets written at the same time, or a faster way would be to do a two-step write where you first write the data, and then write a byte saying that the full data write completed.  For example, you might write the entire block where the first byte is $FE.  Then, when the write has been verified, go back and write the first byte to $FC.  Then, you can read the first byte to see if the block is empty ($FF), block is known good ($FC), or block may be incomplete or corrupted ($FE).  You could continue to use bit pairs in the byte like this to indicate four separate blocks as being used & good.

 

Note:  You may want to check the flash specs on how many times you can write to the same byte before erasing it.  In a past life, I worked with a flash that specified that you could only write to a 32-bit word up to four times before doing an erase.

 

 

  • Like 1
Link to comment
Share on other sites

Flash is typically written in chunks, a 'flash line" at a time.  The size of the flash line can vary by device, but 32 bytes is the size of the last one I worked with.  So you write out 32 bytes to the device and then it programs them.  The details of how it does this are device dependent.  But you can imagine that not all bytes or bits are zapped to 0 at exactly the same time.  So in this case, maybe you are writing a $00 to the last byte when power gets yanked.  Perhaps you end up with a $05 in that byte?  Perhaps you get some weak bits, so that the value read back is not consistent?  If power is cut prior to the write completing, the values of those bytes can not be guaranteed.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...