Jump to content

JLP save/restore

Recommended Posts

I guess asking here makes more sense.


So, tying the loose threads together - JLP saving works in LTO Flash!, and jzintv. So in theory a body could play with it right now, even without all this fancy-pants hardware. So how does one implement it?


I know it was discussed a few months ago but I don't recall a lot of detail being mentioned. I assume it's mostly a matter of just writing bytes/words to a specific address (and perhaps setting up an environment of sorts for that address in a header or something)? And yeah, I'm aware that IntyBASIC isn't going to have a nice neat command for it, although that would be damned cool. For now I'll just muddle my way through some inline ASM.


Although I do wonder if a person would be wise to also include a password-type functionality, just for backwards compatibility with the older multicarts and such. I was hoping to avoid this because I would probably have to enlist some serious math help just to manage the amount of data I need to encode in a password and make it non-trivial to guess.

Link to comment
Share on other sites

I haven't posted the JLP flash save/restore docs publicly yet, but they do exist. It's been one of those "I'll publish them with LTO Flash! and LTO Flash! will be here Real Soon NowTM" task items. And it would be if it weren't for those meddling kids my day job.


Here's the high level description. I will post lower level code later.


The JLP flash support consists of:

  • A small number of memory mapped registers to provide information to the game, and to control the flash save/load process.
  • A set of three commands triggered by register writes:
    • Copy 1 row of data from JLP flash to JLP RAM
    • Copy 1 row of data from JLP RAM to JLP flash
    • Erase 1 sector of data (8 rows) in JLP flash
  • The actual flash storage on the JLP board


Flash storage is organized in sectors. Each sector holds 768 words (1536 bytes). Sectors are further subdivided into rows, with 8 rows per sector. That gives each row 96 words (192 bytes).


JLP provides two memory locations that report the lowest and highest available row number to the program. The lowest row number varies with the size of the game programmed into JLP, while the highest number varies based on the capacity of MCU populated on the board.1 A correct program, therefore, should query these locations to determine the valid range of row numbers for saving game state. JLP will silently reject requests to operate on a row outside the valid range.


Issuing commands to JLP is fairly straightforward, with one caveat that I'll get to in a moment:

  1. Write the JLP RAM address to the address argument register. (Not needed for the 'Erase' command.)
  2. Write the JLP flash row number to the row argument register. (For 'Erase', use the first row # of the sector.)
  3. Write the 'magic number' for the desired command to the command register.

This triggers the command of interest. JLP will either copy data to flash, copy data from flash, or erase a sector of flash. Note that once you copy data to a row in flash, you can't copy new data to that row until you erase it. But, you can't erase individual rows, only groups of 8. More on that fun below.


I mentioned above there's a caveat to issuing JLP flash commands: On issuing a JLP flash command, JLP will "disappear" and cease to respond to the Intellivision for several milliseconds. There's no way to avoid this: The MCU stalls completely during flash operations and I cannot control that. That means you cannot access any program code or data in JLP's ROM or RAM while a flash command is active. Ordinarily, that would mean everything crashes when you initiate a flash command.


Don't worry, I have that covered. To successfully issue a flash command to JLP, you need to run a small bit of code in the Intellivision's system RAM, and make sure your stack pointer points to system RAM also. That way, the Intellivision doesn't actually need any resources from JLP during the flash operation. I provide reference code that does this with a small, 5 word stub in system RAM. Since JLP gives you 8K words of RAM in return for the rest of the time, this feels like a fair trade.


So how about the row / sector structure, and the fact you can't overwrite a row without erasing a sector? The strategy I've adopted is to devote the first couple words of a row to a serial number, and then write my updates to flash in a pool of rows at least 2 sectors large, but preferably larger. When loading data, I scan for the row with the highest serial number. When saving data, I write the data with a serial number that's one larger. Whenever all of the rows in a given sector are "out of date," I issue an erase command for that sector. I have reference code I'm happy to share.


One last high level detail: Sectors erase to all 0xFFFFs, so it's easy to detect them. Also, when a cartridge is factory fresh, all of flash reads as 0xFFFFs also.


I'll post a preliminary excerpt from the programming guide later. This is just meant to be a high level overview.


Some other details:

  • You can enable JLP save-game support in jzIntv with the flag --jlp-savegame=filename. JLP will use filename to store the flash 'image'. Right now, it creates an arbitrary sized image, roughly sized to the largest JLP board. My plan, by LTO Flash! release, is to have a mechanism where programs can declare how much JLP flash they require to operate correctly, and have jzIntv honor that setting.
  • LTO Flash! actually relies on programs declaring how much JLP flash space they need, to know how much space to allocate. :) LTO Flash! supports JLP flash save areas up to 1MB, even though no JLP board supports that much.
  • JLP itself will provide whatever it can; the main role of the "minimum required" flag will be to throw an error if you try to put a game on too small of a JLP board.

Hopefully this whets your whistle a little.



1JLP can actually be built in 3 capacities, although to date we've only bothered building the largest model due to economies of scale, the small price difference between largest and smallest, and the ever increasing size of games under development.

  • Like 4
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.

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.

  • Recently Browsing   0 members

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