Feature: Using Writeback To Save Program Data
Posted by Nick on 28 March 2000, 05:54 GMT
Jonah Cohen has written a feature on using a technique called "writeback" to save data for things such as high scores. Note that all references here are for TI-86 assembly, but the concept is very similar on other z80 calculators. Writeback, for those of you unfamiliar with the concept, is a method of saving data within a program so that it remains there after the program exits. On the TI-86, when asm programs are executed, they are copied to _asm_exec_ram ($D748) before being run. However, once they exit, they are not copied back to their original location. Thus any changes to the data in the program are not saved. So what can you do about this? Well, there are a number of methods of saving information: - Save the data in a string or other external data file.
- Save the data in a RAM location that is reasonably safe.
- Using writeback to save the data to the original program.
The first two options are not very useful (the first has no advantages over the third and the second is not very safe). Thus, I will only go into depth describing the third method--using rom calls to copy data from the executed code in _asm_exec_ram back to the original program file. Here is an example writeback routine: 1. ld hl,_asapvar 2. rst 20h 3. rst 10h 4. xor a 5. ld hl,data_start-_asm_exec_ram+4 6. add hl,de 7. adc a,b 8. call _SET_ABS_DEST_ADDR 9. xor a 10. ld hl,data_start 11. call _SET_ABS_SRC_ADDR 12. ld hl,data_end-data_start 13. call _SET_MM_NUM_BYTES 14. call _MM_LDIR A line by line explanation of the routine: - Point hl to _asapvar, the name of the currently executing program in variable name format.
- Copy the variable name from _asapvar to _OP1.
- Shortcut to _findsym, which looks up the variable name in _OP1 and returns the absolute pointer (24-bit) in bde.
- Register a=0
- Point hl to the offset into the program that the data starts. Notice that we subtract _asm_exec_ram so it's only an offset, not a full address. The extra 4 bytes we're adding are because every asm program has a 4 byte header--a size word and a signature word.
- Since bde contains the pointer to the original program, we can add the offset in that program by doing add hl,de.
- Remember: the addressing is 24-bit. Thus, if the offset into the original program is greater than 16 bits can represent, we need to add the carry flag (adc=add with carry) to the original pointer. After executing this line, ahl points to the first byte in the original program where we want to copy the data to.
- Use the ROM call to set ahl to be the absolute source address.
- Register a=0
- Now point hl to the data again. Since _asm_exec_ram is in $c000-$ffff, this time we use normal 16-bit addressing (hence why a=0).
- Now set this as the source address. See how this works? We copy from the current program data in _asm_exec_ram back to the original program data, which we got the address to by using _findsym.
- Put the size of the data to be copied in hl.
- Set that as the number of bytes.
- The ROM call _MM_LDIR (_mm_ldir in some include files) simulates the z80 opcode ldir using 24-bit addressing. It copies _MM_NUM_BYTES bytes from _ABS_SRC_ADDR to _ABS_DEST_ADDR. This is the command that does the bulk of the work. It uses the addresses we generated earlier to copy all of the data between data_start and data_end back to the original program.
So what good does this do, you may ask? Well, a lot! By defining data inside the program, we can then modify it to store high scores, names, speed preferences, and other things, all of which can be saved the next time the user runs the program. Here's an example: exit_program: ld de,(score) ld hl,(highscore) call _cphlde jr nc,no_highscore ;user got a high score ld (highscore),de ld hl,_asapvar rst 20h rst 10h xor a ld hl,data_start-_asm_exec_ram+4 add hl,de adc a,b call _SET_ABS_DEST_ADDR xor a ld hl,data_start call _SET_ABS_SRC_ADDR ld hl,data_end-data_start call _SET_MM_NUM_BYTES call _MM_LDIR no_highscore: jp _clrScrn ;quit to homescreen data_start: highscore: .dw 0 data_end: You can use this method to store any type of data you want, and even modified code (though that's much less useful). Now go out and write a game with high scores, initials, saved games, and the works!
|
|
|
The comments below are written by ticalc.org visitors. Their views are not necessarily those of ticalc.org, and ticalc.org takes no responsibility for their content.
|
|
Re: Feature: Using Writeback To Save Program Data
|
Patrick H
(Web Page)
|
Great job Jonah!
|
|
28 March 2000, 06:01 GMT
|
|
Re: Feature: Using Writeback To Save Program Data
|
EV9D93
(Web Page)
|
Cool, I never knew exactly what write-back was.
A question... Why do you think my calc sometimes just stops saving high scores untill I reset it?
|
|
28 March 2000, 07:29 GMT
|
|
Re: Feature: Using Writeback To Save Program Data
|
nova
|
An 89 with AMS 2.03 has problems keeping high scores.
Has anyone else noticed it?
|
|
28 March 2000, 09:00 GMT
|
|
Re: Feature: Using Writeback To Save Program Data
|
rabidcow
(Web Page)
|
replace the last two calls with this one:
call _MM_LDIR_SET_SIZE
it will perform both operations in one call.
_MM_LDIR_SET_SIZE equ 524Dh
|
|
28 March 2000, 09:14 GMT
|
|
Re: Feature: Using Writeback To Save Program Data
|
Kerey Roper
(Web Page)
|
Using external files to save does have some advantages over program writeback, although it is larger and more difficult to use. It allows people to trade saved games, even to different types of calculators, such as 83 to 83+, send the game to someone else without sending save files, and back up a saved game without having to save all of them.
Program writeback is the best choice for high scores though.
|
|
28 March 2000, 23:10 GMT
|
|
Re: Feature: Using Writeback To Save Program Data
|
natefanaro
(Web Page)
|
Will this method work on an 82? or only on the 86?
|
|
29 March 2000, 06:09 GMT
|
|
Re: Feature: Using Writeback To Save Program Data
|
Huub Heerink
(Web Page)
|
That's a great job, I never could have done this. Thanks!
|
|
31 March 2000, 21:03 GMT
|
|
|