In the last tutorial we pointed out that you can not create permanent self modifying code. So, how do you save important data? The answer is in AppVars. They are a special kind of variable that can only be edited in assembly, and serve as a "permanent" saving point for app data (note that they can be deleted from the memory menu).
To create AppVars, we will use the _CreateAppVar ROM call. It's inputs are appvar name in op1 and size in HL. Note that when created it will be in RAM.
;omit header ld hl,AppVarName rst rMOV9TOOP1 ld hl,32 bcall(_CreateAppVar) AppVarName: .db AppVarObj,"AVDATA",0
The data in AppVars goes like this: the first two bytes are for size, and then everything else is defined by the program accessing the AppVar.
Generally, it is a very good idea to create an identifier for your AppVar. It can be anything you want and any length you want, so long as your program can identify it later. It is good practice to put it right after the size bytes, but you don't have to if you don't want to.
Creating an identifier is as simple as ldir-ing into the AppVar.
;load our identifier inc de ;get over size bytes inc de ld hl,identifier ld bc,9 ldir identifier: .db "Identify",0
First it must be located. See External Levels and Files for more info.
Detection is as simple as checking for any variants between the identifier and the data in the AppVar.
;check for valid AppVar ;assuming de is pointing to start of AppVar Data inc de ;get over size bytes inc de ld hl,identifier ex de, hl iloop: ld a,(de) cp (hl) jr nz,invalid or a jr z,valid inc de inc hl jr iloop invalid: ;... in case identifiers don't match vald: ;... everything matches! identifier: .db "identify",0
Changing AppVar Size
It's usually a good idea to create AppVars of the correct size to begin with. However, sometimes this isn't possible. So, to do so we just need to insert memory into the appvar and update the size bytes.
;assuming that DE points to size byte and that we have enough memory push de push de ;copy de into hl pop hl ld a,(de) ;ld de,(de) ld b,a inc de ld a,(de) ld d,a ld e,b add hl,de ex de,hl ;end of program now in de ld hl,20 ;insert 20 bytes to the end bcall(_insertMem) pop de add hl,de ;update size ld a,l ld (de),a inc de ld a,h ld (de),a
Note that this process is the exact same process you go through to insert memory into program variables, too.
AppVars are really useful tools for saving data between application uses. It is interesting to note that regular assembly programs can also access AppVars, and use them in the exact same way that flash applications use them.