So, as suggested, a thread to condense my z80 questions to one place for future reference.

So here we are:

Q1) I am writing a graphics library (as several of you know and advise against) anyhow, I have some functions which I would like the user to call before using anything else. So, my initial idea was to the pre-processor and (#define/ifdef/ifndef). But I don't think that work to limit it like that. So my other idea was just to check if they have a certain byte equal to a certain value in safe ram and only allow functions to run if it's there. (I would set it in the first library set up function). But this could be a problem if the user edits the byte themselves. So are there any other solutions?

Pseduocode here:

Code:

Setup function to call.

; The next three functions should ONLY be able to be called if setup has been run.
Func 1
Func 2
Func 3
That's not how #defines work. #define and similar preprocessor directives are processed at assembling time, not at runtime, which means that they can't react to anything related to running the program. To do something like what you're describing in ASM, I'd do the following:
Code:
;...standard headers here...
    .org progstart -2
    .db $BB,$6D ; or whatever

    ld a,(setup_completed)
    or a
    jr nz,Post_Setup
    call Setup
    ; Do any setup things here
    ld a,1
    ld (setup_completed),a
Post_Setup:
    call Func1
    call Func2
    call Func3
    ret

setup_completed:
    .db 0    ;This requires a shell like Doors CS that performs writeback
Though you can force a player to define routines they're going to use at the start of the program. It might make for a slightly awkward header, but:

routines.inc

Code:
#ifdef ROUTINE1
    call setupRoutine1
#endif
#ifdef ROUTINE2
    call setupRoutine2
#endif
#ifdef ROUTINE3
    call setupRoutine3
#endif
;etc.

main.asm

Code:
;normal header
.org $9D93
.db $BB,$6D
start:
#include "routines.inc"
#DEFINE ROUTINE1
#DEFINE ROUTINE3
;rest of code
That would just put the calls at the start of the program. Using a byte in saferam would be fine, too, you just need to tell the programmer not to change that byte. Is it just one setup routine? Or do different routines require a different setup? And is your library a file to be included or part of a shell?

If it's an include file that's going to insert code into the program (not just equates), you could prefix the routines that require setting up with a 'ret'. The setup routine would overwrite the ret's with a nop ($00). The routines will just exit if you haven't run the setup routine. That's got the same issue as Kerm's solution, though, in that it'll only work the first time you run the program if you're using a shell with writeback. The next time it'll have written the nops into the program and will run them even if you haven't run setup.

EDIT: You could also do some wacky stack stuff, so that when setup is called you do something like:

Code:
setup:
     pop af ;the address to return to after setup rets
     ld hl,resetSetup
     push hl ;put this address on the stack so that the program jumps to it before quitting
     push af ;put the address to return to back on the stack
;setup whatever you need to
     ret

resetSetup:
;reset the values you changed (for example, changing the nops to rets ($C9) again
     ret ;now it will exit the program completely
chickendude wrote:
That would just put the calls at the start of the program. Using a byte in saferam would be fine, too, you just need to tell the programmer not to change that byte. Is it just one setup routine? Or do different routines require a different setup? And is your library a file to be included or part of a shell?
I understood the question differently. I think the first time the program runs, he wants to run the setup routine, and only then the remaining three routines can run. On subsequent runs, he wants just the three routines to run, because the setup routine has already been run the first time the program was executed. My solution therefore does that.
KermMartian wrote:
chickendude wrote:
That would just put the calls at the start of the program. Using a byte in saferam would be fine, too, you just need to tell the programmer not to change that byte. Is it just one setup routine? Or do different routines require a different setup? And is your library a file to be included or part of a shell?
I understood the question differently. I think the first time the program runs, he wants to run the setup routine, and only then the remaining three routines can run. On subsequent runs, he wants just the three routines to run, because the setup routine has already been run the first time the program was executed. My solution therefore does that.

Perhaps I should've cleared it up a bit more, the setup routine should be run every-time the program is run, so everytime you would run the game, it would have to be run to set up the frequencies or what not. The setup would only have to be run once per run of the game/program, after that they can run the other routines.
Will the routines be in RAM? My idea with the stack would work if they're in RAM and you can use SMC, it also doesn't use any saferam. But how you do it would change depending on how the routines are stored. Is it an include file with all the routines in it? Or is it like a shell where the routines will be stored outside of the program (and not subject to program writeback)?

Another option if the routines are in RAM would be just to add a .db 0 to the end of the setup routine and use that as your variable.

EDIT: I just wanted to say that if you're really concerned about speed, prefixing routines you don't want to run before setup is called with a 'ret' then overwriting that byte with a 'nop' will be faster than checking a certain value in saferam. nop is 4 t-states, loading a value into a from an address (indirection) is 13 t-states and the comparison, depending on the value (whether it's an 'or a/inc a/dec a' or 'cp ##') will be 4 or 7, and then skipping the ret nz/z/c/whatever another 5. The difference is pretty negligible, but in deeply nested routines it can start to make a difference.
It's worthwhile to note that the overarching flow of most of my programs and games in z80 assembly (and in most languages, I guess, if you translate the syntax) looks like this:
Code:
; --- headers ---
StartOfProgram:
    ; initialize variables that should only be initialized once per program run
MainMenu:
    ; Initialize main menu and display it
MainMenuInner:
    ; Handle key movement, redrawing, whatever.
    ; If not done with the main menu...
    jr nz,MainMenuInner
MainGame:
    ; Set up per-game-instance variables.
    ; For example, for tic-tac-toe, set up board and who goes first
MainGameLoop:
    ; Sort of an outer loop. For example, in tic-tac-toe, reloop here
    ; whenever a new turn starts.
    ; Code to set up a move start here
MainGameLoopInner:
    ; Something like keys or AI and redrawing
    ; if not done...
    jp nz, MainGameLoopInner
    ; Post-turn/move state changes
    ; Check win/loss/quit condition
    jp nz, MainGameLoop ; game continues
    ; Do final cleanup, win/lose display, high scores, etc
    jp MainMenu
;---------Helper routines go here
;---------Static data goes here
;---------SMC/writeback data goes here
Of course, you could easily reinterpret this basic structure for many different types of programs. A graphing program, for example, would use the main menu to select which mode to go into (equation entry, window variable editing, displaying the graph), then you might have several "MainGameLoop"-esque sections with redisplay and key entry. Just food for thought.
chickendude wrote:
Will the routines be in RAM? My idea with the stack would work if they're in RAM and you can use SMC, it also doesn't use any saferam. But how you do it would change depending on how the routines are stored. Is it an include file with all the routines in it? Or is it like a shell where the routines will be stored outside of the program (and not subject to program writeback)?

Another option if the routines are in RAM would be just to add a .db 0 to the end of the setup routine and use that as your variable.

EDIT: I just wanted to say that if you're really concerned about speed, prefixing routines you don't want to run before setup is called with a 'ret' then overwriting that byte with a 'nop' will be faster than checking a certain value in saferam. nop is 4 t-states, loading a value into a from an address (indirection) is 13 t-states and the comparison, depending on the value (whether it's an 'or a/inc a/dec a' or 'cp ##') will be 4 or 7, and then skipping the ret nz/z/c/whatever another 5. The difference is pretty negligible, but in deeply nested routines it can start to make a difference.


I would assume they would be in RAM, or wherever the game is being run from? Since the routines would just be in an include file that you would include in the program. And since these are graphics routines, I'm fairly certain speed is important, hence I can do the ret thing. Though I feel as I should have a routine in the end to include to change the nop's back to ret's? Or would that not be needed?

KermMartian wrote:
It's worthwhile to note that the overarching flow of most of my programs and games in z80 assembly (and in most languages, I guess, if you translate the syntax) looks like this:
Code:
; --- headers ---
StartOfProgram:
    ; initialize variables that should only be initialized once per program run
MainMenu:
    ; Initialize main menu and display it
MainMenuInner:
    ; Handle key movement, redrawing, whatever.
    ; If not done with the main menu...
    jr nz,MainMenuInner
MainGame:
    ; Set up per-game-instance variables.
    ; For example, for tic-tac-toe, set up board and who goes first
MainGameLoop:
    ; Sort of an outer loop. For example, in tic-tac-toe, reloop here
    ; whenever a new turn starts.
    ; Code to set up a move start here
MainGameLoopInner:
    ; Something like keys or AI and redrawing
    ; if not done...
    jp nz, MainGameLoopInner
    ; Post-turn/move state changes
    ; Check win/loss/quit condition
    jp nz, MainGameLoop ; game continues
    ; Do final cleanup, win/lose display, high scores, etc
    jp MainMenu
;---------Helper routines go here
;---------Static data goes here
;---------SMC/writeback data goes here
Of course, you could easily reinterpret this basic structure for many different types of programs. A graphing program, for example, would use the main menu to select which mode to go into (equation entry, window variable editing, displaying the graph), then you might have several "MainGameLoop"-esque sections with redisplay and key entry. Just food for thought.


That's a pretty nifty writeout that's completely accurate for pretty much any program I've seen! Thank you for it!
That's what the stack work is for, so that when your program exits it jumps to "resetSetup". When you "pop af" you get the address you're supposed to return to in af (just be careful not to do anything that messes with flags before you push it back, or use another register). Then you push "resetSetup" onto the stack, and then the return address onto the stack. You essentially insert an extra address to the stack before the program exits. At resetSetup you would conver the nops to rets again.

EDIT: Though really, i don't know if all that effort is necessary since either way the program isn't going to work. If the routines you're calling are just quitting, the program won't function like the author wants it to and won't release the game/program in that state. Doing what i said will just make the program larger than it needs to be. I say a note in the readme should be fine.
chickendude wrote:
That's what the stack work is for, so that when your program exits it jumps to "resetSetup". When you "pop af" you get the address you're supposed to return to in af (just be careful not to do anything that messes with flags before you push it back, or use another register). Then you push "resetSetup" onto the stack, and then the return address onto the stack. You essentially insert an extra address to the stack before the program exits. At resetSetup you would conver the nops to rets again.

EDIT: Though really, i don't know if all that effort is necessary since either way the program isn't going to work. If the routines you're calling are just quitting, the program won't function like the author wants it to and won't release the game/program in that state. Doing what i said will just make the program larger than it needs to be. I say a note in the readme should be fine.


Hmmm, I suppose you are right, since they should read the readme file anyways and the pertinent information there should be enough to alert them on what to do, perhaps also a small comment in the include file as well; those together should be more than enough for any developer.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement