Sorry, it's been a while since i checked in here, and it seems you guys sent a load of great replies
I'm really happy that you've actually found my daft little routine interesting, and taken the time to play with it and even provide feedback, so thank you so much for that!
- Thanks for the encouragement. I think you're absolutely right really. The fact that i had a bit of fun with it, and learned quite a bit about machine code programming is what it was all about really.
- Thanks so much for the coding tips. This was the 1st machine code program I've ever attempted so your constructive criticism is very much appreciated! Your code looks much more efficient and elegant than my own! It also occured to me that avoiding calls and absolute jumps has the advantage of making the code portable (i.e. using Jump relative instead, i could load the routine into any memory address, and it would still run). This was something that caused me a bit of a saw head when i was working on it, as the code needed to run from the multiface ram which pages in over the top of the spectrum rom at something like 8100 (I don't remember the exact address right now). Because I hand compiled the code (i used a google drive spreadsheet to work out the dec values i needed in the data statements!), I had to remember that even though I was poking it into quite high memory addresses (~40000) I needed the call commands to point the the low addresses so it would actually work once i'd LDIR'ed it into the multiface RAM. I crashed the spectrum emulator lots of times before I actually got all the addresses right.
Anyway, I've given up on hand assembling code now, and moved onto using the assembler build into zxspin. This does give me a new problem though…
In the assembler, I tend to start my code with ORG 32768 (or similar) to tell the assembler where in memory I want the code to end up. When i'm writing multiface routines, I have to ask the assembler to dump the code into high memory, as it can't write it directly to the MF ram (as it isn't paged in at the time i assemble the code). But, if i use any jumps or calls (i.e. if my routine is not portable) I need some way to ask the assembler to dump the code in a high memory address, but set the absolute jump/call memory addresses based on the low memory address i'll actually be moving the code into before running it. I have no idea how i would tell the assembler that i needed to do that. Maybe it’s not even possible?
I think in the short term, the best solution is probably to just make sure all my routines are fully portable by sticking with relative jumps.
- It really made me smile to see you actually captured some hidden loading screen messages with my code - thats really cool! And yes, I would love for you to use my code in a stream so feel free to do that
Your suggestion to add a pause at the end of the routine would make sense i guess (i.e. press any key to continue running the game). After doing a bit more reading, i realised that i didn't really put much effort into making sure the game could continue running after i exit my routine. That was mostly because i was focused on loading screens, and i figured that triggering an NMI in the middle of the tape loading would almost always cause a crash (or at least an r-tape loading error). When you trigger my routine from within a running game though, there's no reason it shouldn't continue running normally afterwards (all be it with a bit of screen colour corruption). To make that a bit more reliable I should really have some code at the start to push all the registers to the stack, then disable interrupts, then at the end i should have the code wait for a key press, then recover the registers from the stack, and enable interrupts before returning to the game code.
<strike>Also I think I'm using the wrong return command at the end of my routine. I used 201 which is just RET, but i realised recently that there’s another op code for RETI (i.e. return from interrupt) so i guess i should be using that one really. (I have no idea what difference it makes though to be honest).</strike>
Actually, the ret command in my code is just returning from one of my pointless sub-routines. I'm acutally using RST 0 to exit my routine, which i think is correct?
I've been pretty busy with other stuff lately, so I've not had much time to keep tinkering on the spectrum, but your replies have definitely inspired me, so i'll try and find time sometime soon, and will try and post an improved version.