Since you can use the timers without interrupts I'd imagine that they count independent of whether or not interrupts are enabled or disabled. However, if the timer hit 0 without your acknowledging and then you later EI, it looks like it'll immediately trigger an interrupt.
Specifically, I was reading about the timers' loop control ports, but I'm not experienced with the timers yet, so I may have misinterpreted it.
You read it right. I just didn't pay enough attention to that when I was making it. So disabling interrupts only prevents them from occurring. When interrupts are off, they will pile up like when the ISR is too long.
I am using the crystal timers for very precise timekeeping and I want to know if I can disable and enable interrupts for certain small routines without that throwing off the timer.
What does using ei and di to enable and disable interrupts do to the interrupts 'timer'? Does it pause it so that if an interrupt would occur in 1000 t-states before interrupts were disabled, it would actually happen 1000 t-states after they were enabled again or does it happen 1000 - (amount of t-states that interrupts were disabled for) t-states? Does using the crystal timers vs normal interrupts make any difference?
Those are pretty neat especially the last one! I wish I had an excuse to use them. Why don't you include a faster version of the flash to ram bcall while you are at it? It should be pretty easy since all you have to do is swap the flash bank into $4000-$4FFF and ldir it to ram and swap the page when needed.
I did some research and experimentation and I found out how to use the built in Auto Power Down (APD) feature in an assembly program. I couldn't really find any kind of relevant documentation on WikiTi so I just looked at the memory areas that looked related and tried some things until I got something that works. Since I found this all out by experimentation, there is a chance that I could be totally wrong and that the calc doesn't go into low power mode or something but I'm pretty sure that I am correct. I guess the only way to tell for sure is for me to stick fresh batteries in a calc and run it in an assembly program until it dies and then to do the same thing for my APD but that could take weeks to a month.
The routiene in Axe (but it is very easy to translate to assembly if you want):
:GOff();If you are using graylib or any custom interrupt, turn it off here. If not, skip this step :*save 0x8000*;The APD destroys 256 bytes starting at 0x8000 so if you use that area for storage, you will need to back it up. If not, you don't have to do anything. :0x180C->{0x89F8}r;Set some flags so that it works :0x0101->(0x8448)r;Set the APD timer to right about to shut off :Asm(FF);Call the OS interrupt (This is 'rst 38h' in assembly) :FnOn;Interrupts should be on at this point because of the last line but it doesn't hurt to be very sure. (This is 'ei' in assembly) :Stop;Wait until the OS interrupt fires. It is at this point that the calc actually turns off (This is 'halt' in assembly) :0x7469->{0x8448}r;Set the APD timer to what it normally is so the calc doesn't instantly APD when you quit the program :0x0804->{0x89F8}r;Restore some flags :*restore 0x8000*;Restore the values you saved. If you didn't save anything you of course don't need to restore it :GOn();If you are using graylib or any custom interrupt, turn it back on here
This routiene turns the calc off as soon as you call it which means if you want your program to turn off after no keys have been pressed for a while, you will have to do that yourself. It works fine if the On key is being held when it starts (which means if you have the user press On to turn the calc off you don't have to wait for them to release On to call this) It doesn't wait for the On key to be released when it is finished so I would put a loop at the end of it to wait until the On key is released.
In my experiments with this it worked fine with all sorts of memory screwed up so as long as you save 0x8000 then you shouldn't have to do any other kind of setup. I don't know exactly what flags I am messing with (since I am too lazy to look up what they are - something like iy + onflags I think) in the two flags steps but I know they are nessicary and that there doesn't seem to be any kind of ill effect from setting them in that way.
Here is my thoughts on it just by reading the documentation. I haven't tried it out since I don't have a link cable on hand.
The documentation itself: In some commands for the documentation, you give examples of their use and on others you don't. That is fine mostly since you give examples of the ones that need to be explained and not for the simple ones but why does 10 have an example? For the display character command, what happens if I put in value that isn't in 0-255? You give the user the ability to display any character they want but you never give them a chart to tell them what character goes with what number. On commands 1 and 9, I'm not exactly sure what you mean by screen and I consider myself pretty experienced in calc-programming. By screen do you mean just the home screen and the graph screen? If so just say homescreen in 9 and not 'currently-displayed screen'. If there is more, list them. I'd detail how that works in a little more thoroughly as well.
The program: How do you sanitize your input? What does it do if a number that doesn't correspond to a command is entered like 11? How does it deal with decimals? Negative numbers? How about 65537? (2^16 + 1 as it could wrap around and appear to be 1 to your program) How about having a matrix or a list or a string in Ans? An imaginary number? You need to be sure those don't crash or do weird things. Also make sure you sanitize your input variables like x and y. Those can contain imaginary numbers. I don't get the point of the link port command. Can you name a case where it would be useful to someone programming in basic? I wouldn't give access to the link port to a basic program since the whole point of it (besides doing math) is that you can't screw up your calculator no matter what you do. Ive sent garbage to some of the ports before and you can get nasty stuff like the blue lines of death which can damage the screen or flip the screen upsides down (and that isn't fixed by a ram clear) or swap out the ram page the program is currently running on which will probably crash the calc. For the move cursor command, you say that the user shouldn't let the cursor go off the edge of the screen. You shouldn't make that the user's task. Remember that your users have no clue how your code works and they can and will feed all kinds of garbage data into your program. I would also offset the cursor's position for the user so it is the same as the basic one. It is so easy to add a 'dec hl' or whatever register you are using and it saves confusion. Why are some commands toggle and some have a separate on and off? 3 and 4 are an on-off pair but 6 and 9 are just toggle. Sleep mode seems a little odd. How exactly do you turn the calc off? I know the basic programs can auto-power-off when waiting for input and they don't throw an error when turning on. I imagine that you are handling the sleep inside your program and then when the on button is pressed then it turns back on, returns to the basic program which then errors. If so, there is a way around it. IIRC there is a flag that is set whenever the on button is pressed. Even if you read the keypad to clear the most recently pressed key, that won't clear the flag. If you clear it, then the basic program shouldn't error. Or it could be a port and not a flag. I'm pretty sure it is a flag though.
These are just some thoughts. Seems like a nice program though. You probably learned a lot from making it
I threw together a quick Axe program and I didn't have any issue with it. I can set finance vars just fine inside a hook. Here is my code:
:.TestApp :LHook //Loads the address of the hook into HL :Asm(DB06) //In a,(6) - This gets the page we are currently on and loads it into A :Asm(EFAB4F) //B_CALL EnableHomescreenHook :Return : :Lbl Hook :Asm(83) //Make it a valid hook :Asm(3d3d) //dec a, dec a - Decrements A twice so that A is zero if we are in mode 2 :Asm(6F67) //ld l,a , ld h,a - Load A into H and L :!If //If A is zero then HL will be zero and the stuff inside the if statement will run :Asm(F5C5D5E5) //Push AF, BC, DE, HL :37->float{E9055} //Convert my favorite number into a float and set 0x9055 to its value :Disp "Test" //Display some text to verify that the hook actually ran :Asm(E1D1C1F1) //Pop HL, DE, BC, AF :End :Asm(AF) //xor a - Set the Z flag before I return :Return
It worked perfectly well. To run it, you just have to compile it as an app, and run the app once. After that, every time you hit enter on the homescreen the weird 'N' finance var (the one that is kind of bolded) is set to 37. In fact, you can set 'N' to whatever you want, type it in on the homescreen, and it will tell you that 'N' is 37 so it does set the value before the program evaluates the finance var.
I actually wrote a whole response thinking that finance vars worked like the basic letter vars and that they weren't created until used. Since they use a fixed memory area and aren't created dynamically, that answer won't help you but Ill include it here in case some future person finds it useful.
Spoiler For Answer for a different problem:
Let me take a guess: The hook that you are trying to edit it in is the homescreen hook or some other hook that is run while the user is still typing things in. Your problem is that when the user is typing things on the homescreen, the OS opens an edit buffer. That edit buffer takes all of the free ram left so you can't create any new variable since there is no ram to create them in. I had this problem at one point as well. To check if I'm correct, you can use B_CALL MemChk from wherever you are having your problem. It returns the amount of free ram available. If it returns 0, then that's your issue.
Spoiler For (Optional) How edit buffers work:
This is what I've figured out from of trial and error and careful reading of the documentation. I'm pretty sure it is correct but I can't promise it is. The OS uses edit buffers for a lot of different things. From what I can tell, they are used pretty much any time you type something into a field that has no size limits. So this includes everything you type on the homescreen, when you edit programs, and more. If you aren't familiar with how exactly edit buffers work, from what I understand, they basically expand to take all the free memory so that it doesn't need to resize and create delays while it is running. The memory moves around based on where your cursor is. Its structured so that the at the beginning of the edit buffer is all the data from the start of the edit buffer up to wherever your cursor is. It then has a giant blank gap where there is no data. At the bottom of the buffer is all of the data after the cursor. When you insert things into the buffer, it just inserts that data into the blank space after the cursor and moves it forward, no shifting data around. That also means when you move the cursor, it is moving data to and from the 'behind the cursor' area and the 'after the cursor' area to keep them accurate. (I created my own program editor a while back and this isn't really a good excuse. Inserting at the top of a giant program and having to shift down all of the data each time a character is added isn't noticeably slower than inserting at the bottom )
How to fix it (assuming that I guessed your problem correctly) You can't create any new variables while the homescreen edit buffer is open. I don't think there is any way around that without doing some serious hacks that would be far too much work. What you want to do instead, is just insert your finance variable using whatever trick you are doing normally. Then on your homescreen hook, use mode 2. That is the mode that is called right before it evaluates what is typed in on the homescreen. At that point the edit buffer will be closed. You don't need to take advantage of any of the features of this mode, just create your finance variable, set it to your value and return Z.
Holy heck that is clever! So all you'd need a token hook, RawKeyHook, and parser hook.
I can't tell if you are being sarcastic. Given how much trouble I always have when trying to use more than one hook at a time, I suspect you are laughing at me.
Why a parser hook? Isn't that for modifying functions? I don't see why you would need one unless you are trying to disable all functions that would modify the hacked stat var's value. Since Sue Doenim has found a way using some hook or other to insert the token, it should be simple to change the stat var to tau's value then to be sure it is the correct value when it runs.
If you are ok with cheating a bit, there is a somewhat easier way to accomplish it. At a glance, the statistics variables all have their own dedicated ram area. A wild guess, but they are probably in statVars. If you can find the ram area for one of these stat vars, every time your hook runs, you can set the value of that stat var to the value of tau and instead of replacing the pi with a tau, replace it with that stat var. You could install a token hook to change whatever that stat var was to the tau character. It would look just like the tau token and work like it in all cases too. The only problem is that it would mess with the value stored in that variable unless you can find a way to save and restore it.
bcall(_RclAns) bcall(_ConvOP1) push af ; Load the name into OP1 ld hl,$09AA ; internally, Str0 is represented as 0xAA09 ld (OP1+1),hl
; Check if it exists and delete if necessary rst rFindSym jr c,make_str0 bcall(_DelvarArc) make_str0:
; Now create Str0 with size 1. Put the name in OP1 first ld hl,$09AA ld (OP1+1),hl
; Size is 1 byte ld hl,1 bcall(_CreateStrng)
;Pointer to size bytes is in DE. Switch to HL ex de,hl
; Don't need the size, so skip those two bytes and get to the start of the data inc hl Inc hl
; Now write the token pop af ; if using ti83plus.inc. same as $41 or in this specific case, 'A' ld (hl),a
;Done! retBut it didn't store anything into Str0, infact it did nothing, I feel ripped off, could you send me the code itself instead of telling to "put instructions in certain locations"? Also, I don't mean to be rude.
Since you seem to be trying to do something for a basic program, here is a solution in basic.
First you got to go through ti83plus.txt and go to the tokens section. Pull up an ascii chart and start hunting. It will take a lot of work to go through every ascii character and find the token equivalent to it.Then you take all of them in order and include them as data in an asm program. Many of the tokens will be 2 bytes long, but remember that the ones that aren't take up only one byte and don't need to be headed by a 0. Then have your program copy all of that into a new basic program. There you go. You have all 255 ascii characters in a basic program. It is a simple task to put some quotes around that do 'sub(' directly on that with Ans being your index. It might be easier to just put all the tokens in one program and then sort and order them from there. Alternately if you can't be bothered to do a bit of work, there is some basic program out there on ticalc that has all the ascii characters in order. If you can find it you can skip right to the 'sub(' part. I, for one, can't be bothered to hunt for it but I know it is out there.
Maybe if you told why you want to do this it would be easier to help you.
I know that I'm 2 weeks late to the party (and several months if you count it from the original post) but I actually did something pretty similar to what you are trying to do a while ago. If you want to mess around with the homescreen input, you should use a homescreen hook. (http://wikiti.brandonw.net/index.php?title=83Plus:Hooks:9B8C) Since you mentioned hooks already, I assume that you already know how to use them. If you use the mode when A=2, then you don't have to worry about edit buffers and you can just open prgm! and edit it like anything else without worrying about edit buffers and such. If you want to change what a key sends on a double press by using the mode where A=1, you are in for something much trickier. It is simple to change B to the keypress that produces the token that you want. If I recall correctly, you should change keyExtend to the second byte if it is a two byte keypress. The problem is with removing the previous token. There is an edit buffer command to shift the cursor one token to the left (BufLeft) so that might work, and then you could call BufReplace to replace that token that was previously typed in with the one you want to change it to and then return nz to ignore the keypress since you handled it manually. I don't know how this would work when the user is in insert mode.
Ooh that would be cool. Are you allowed to post modified roms? I have a couple of my own that I could add in the extremely low chance anyone does anything about it.
I suggest you make a good physics engine first. Don't even bother to make sprites. It can be easy to spend all your time making sprites and realize when you are done that you can't make the game. Black rectangles will do at first. Even if the graphics are perfect, the physics needs to feel at least somewhat realistic. I might even go so far as to get some video of Smash for analysis. (Any youtube video will work). How high do the characters jump? 2x their height? Having a video to base it off of helps. There is a version of Smash for the ti-83+ written in Axe.
Hey, I'm still working on this game for some reason.
It has been a while and I haven't had much time to work on Driller kNight since I have been away at college but here is an update anyway.
I am planning to release updates to the game on the first of every month to help boost the site and to give myself a deadline to work toward. Since I have a limited time to test, there is a chance I missed some bug. I would be very suprised if the game crashes but you shouldn't leave important things in RAM anyway.
Some unrelated things about the size of the game: To recompile the whole game takes over 6 minutes. The game is broken up into 8 seperate files and each takes anywhere from 90 seconds (the App) to 15 seconds (the file that creates the saves) The file dedicated to holding constants and variable locations is over 6k
Spoiler For Changelog::
New Features: The game can now be saved in the middle of a level. Be warned that the save file will be >10k and archived. The player can now view some stats such as kills and loot collected Added 1 new unit
Changes: The godmode and random level add-ons are no longer optional Removed the intro scroll when the game first starts The invert screen option no longer does anything although the user's preference is still saved The game now requires 20k of free RAM to run (Was 16k before)
Improvements: Opening / closing menus is now twice as fast Rewrote the Refiner Ai to not be so over powered / RNG based Rewrote the Clearer Ai not to get stuck if there was no rubble nearby Units no longer sit still and wait to die if they have low health and are being attacked Upgrade menu is easier to use and upgrade costs are now clearer The framerate no longer drops by 10% for each repair node built The game now runs ~15% faster in general Fixed the game crashing when revealing very large caverns Roads no longer appear unpowered for a second when a building or road is removed As a result of the previous fix the game now crashes when more than 60 power plants are built. (I could fix this but I thought it was funny) Various parts of the game have been moved around to begin working toward 83+ support Large amounts of the game's internals have been gutted and reworked to make expansion much easier
Outstandng bugs: I beleive that the game will crash if the user doesn't have the 10k-13k needed to create the save file but I haven't tested it. If the game reveals a cavern over 2/3 the size of the largest map it will still crash (Up from crashing on caverns over 1/8 the size previously) The user can save the game right before they finish a level, gain the stats from winning, load the save, finish it to gain the stats again, load the save... On one of the last levels the game states that the user needs to build a Hover Refiner to win even thought the pre-level story clearly states that a Doom Platform is the object.
I would post some screenshots but very few of the visuals have changed.
Not a bad transition. It seems kinda slow though. I would speed it up by a factor of 2. It might get pretty annoying if there is a lot of walking involved. Of course having the screen center on the character would be best but if your engine isn't set up to handle that it then it could be really hard to implement.
I have a bit of an obscure question. I have been looking into ways of creating multi-page apps in Axe. I know it can be done by swapping pages at 0x4000 and using a jump table, but that requires that the program use multiple apps which looks ugly. Looking at the app header I know that there is 1 byte that determines the number of pages an app is. I was wondering what would happen if I changed that byte. I know that even if I unlocked flash, I can only write a 0 onto a 1 so I would need to save the app's data and clear the flash page. So... theoretically speaking, if I looked through the archive to find X pages free in a row, copied the app to that page changing the number of pages byte to X then I could paste other 1 page Axe apps in the other pages and use a jump table in them. Would that work? Would the OS ignore the apps pasted into the second page even though it had a legal header? (I guess I could just change the header to all 0's)
Another idea: Is there a way to mark a 16k segment of flash as taken without it showing up anywhere? If I could do that, I could create the standard jump table at the start of the app with the page number as the offset of the app to the block of flash and simply call the Bcall for multi-page apps.
I suppose this is a lot of work for not much gain... just a prettier app screen. Maybe there is a way to hide apps in the menu by naming them something illegal.