I made a new App for the Multiface 3

Show us what you're working on, (preferably with screenshots).
User avatar
djnzx48
Manic Miner
Posts: 730
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: I made a new App for the Multiface 3

Post by djnzx48 »

Nice! I typed it in and it worked fine. If you want a few minor comments about your code:

You don't need to use CALLs so often. In particular, the CALL after the attribute check could be changed to a JR NZ that skips over the LD (HL), $F3 instruction. The other CALL at $2266 could also be inlined. Subroutines are great for organizing your program, but they are slower than simple jumps, so it can be better to avoid them whenever practical, especially in tight loops like this one.

Also, you can try to limit the number of redundant memory accesses. When checking the colours, the attribute value is read twice for example. Here's another version which is very slightly quicker.
Spoiler
ld a, (hl)
and $3f
ld b, a
rra
rra
rra
xor b
and 7
Keep going on these programs. I like seeing the Multiface used to extend functionality like this.
User avatar
druellan
Dynamite Dan
Posts: 1470
Joined: Tue Apr 03, 2018 7:19 pm

Re: I made a new App for the Multiface 3

Post by druellan »

Nice x2. I didn't type it, but copy&paste the code in ZX-Editor (yep, I'm lazy).
If you don't mind I'm probably going to stream my findings at some point, using you tool live :)
User avatar
djnzx48
Manic Miner
Posts: 730
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: I made a new App for the Multiface 3

Post by djnzx48 »

Is there a way to batch download .scr loading screens from somewhere? I'd like to try searching for hidden elements on a larger range of screens.
User avatar
druellan
Dynamite Dan
Posts: 1470
Joined: Tue Apr 03, 2018 7:19 pm

Re: I made a new App for the Multiface 3

Post by druellan »

djnzx48 wrote: Mon May 06, 2019 6:55 am Is there a way to batch download .scr loading screens from somewhere? I'd like to try searching for hidden elements on a larger range of screens.
If you're still looking for this I can try and extract all the .scr from a WOS mirror, many files have the .scr inside the ZIP.
User avatar
druellan
Dynamite Dan
Posts: 1470
Joined: Tue Apr 03, 2018 7:19 pm

Re: I made a new App for the Multiface 3

Post by druellan »

I was playing with this the weekend, and works pretty well, but for some reason was a pain to make it work on ZXSpin/FUSE, I ended using EightyOne.

Image

Image

[mention]Hobes128[/mention] one small improvement, if you're still working on this, could be to pause or halt the execution of the code, since many games just plain reset, and you need to quick-pause the emulator to have the chance to reed something.
User avatar
djnzx48
Manic Miner
Posts: 730
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: I made a new App for the Multiface 3

Post by djnzx48 »

druellan wrote: Mon May 13, 2019 1:45 pm
djnzx48 wrote: Mon May 06, 2019 6:55 am Is there a way to batch download .scr loading screens from somewhere? I'd like to try searching for hidden elements on a larger range of screens.
If you're still looking for this I can try and extract all the .scr from a WOS mirror, many files have the .scr inside the ZIP.
Thanks, that would be helpful. I did think about trying that mirror but it was too large to download the whole thing.
Hobes128
Drutt
Posts: 11
Joined: Sun Apr 14, 2019 6:13 pm

Re: I made a new App for the Multiface 3

Post by Hobes128 »

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!

Guesser - 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.


djnzx - 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.


druellan - 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.
Hobes128
Drutt
Posts: 11
Joined: Sun Apr 14, 2019 6:13 pm

Re: I made a new App for the Multiface 3

Post by Hobes128 »

Hmmm, could you please help me understand your code djnzx...

ld a, (hl) ; this loads the attribute data i want to check - straight forward.

Spectrum attributes are in the format...
Bit 8 = flash on/off
Bit 7 = Bright on / off
Bits 6, 5, 4 = Ink Colour
Bits 3, 2, 1 = Paper Color
So let's imagine this specific attribute square is set to have blue paper and blue ink with no flash and no bright, so it's value will be...
FB INK PAP
00 001 001

and $3f ; 3F in hex is 00 111 111 in binary, so and'ing with this mask strips off the bright and flash data, leaving just ink and paper in the A register
ld b, a ; Store that result in the B register, so b now contains 00 001 001
rra
rra
rra ; rotating A right three times means that the paper colour is lost, leaving just the ink colour in bits 3,2,1 with all other bits are zero so now a = 00 000 001
xor b ; this is the bit i'm struggling to get my head around...

This command will xor B with A and store the result in A, so...
A = 00 000 001
B = 00 001 001
Result = 00 001 000 = A
is that right?

and 7 ; 7 = 00 000 111 so this and mask will set all but the last 3 bits to zero, so now A = 00 000 000

So now if i do CP B, i'm comparing A = 00 000 000 with B = 00 001 001. Because they don't match one another, the zero flag won't be set, so my JR NZ, wont trigger.
I'm sure I'm showing up my poor coding skills here, but I must be misunderstanding something - please help.
User avatar
djnzx48
Manic Miner
Posts: 730
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: I made a new App for the Multiface 3

Post by djnzx48 »

If you want to assemble your code at a different address from where it's run from, most assemblers support something like this. For example, it's .PHASE in Pasmo. I can't remember if the ZX Spin assembler has this feature though.

For the return instructions, there are three different opcodes (not counting conditional returns) - RET, RETI and RETN. They basically all work in the same way, but the specific one you use can affect hardware peripherals attached to the bus. A common example is the AMX mouse - it uses maskable interrupts to send mouse movements and button clicks, and if you use a regular RET to return from your mouse routine then mouse input will stop working!

RETI means 'return from maskable interrupt' and it's what should be used for IM2 routines (the ones you set up with a 257-byte jump table). In your case, you may need to use RETN (return from non-maskable interrupt) as it may be an NMI that triggers the Multiface? I suppose it depends on where your code returns to - the Multiface routine or somewhere else.

RST 0 is probably OK to exit your routine, but it depends on how the stack is balanced.
Hobes128 wrote: Fri May 17, 2019 12:15 am Hmmm, could you please help me understand your code djnzx...

ld a, (hl) ; this loads the attribute data i want to check - straight forward.

Spectrum attributes are in the format...
Bit 8 = flash on/off
Bit 7 = Bright on / off
Bits 6, 5, 4 = Ink Colour
Bits 3, 2, 1 = Paper Color
Just a note - it's more common to refer to these bits as zero-indexed. FLASH is usually denoted as bit 7, BRIGHT is bit 6, PAPER is bits 5-3 and INK is bits 2-0. (I think you've got INK and PAPER mixed around in your example.) This mirrors their use in the Z80 BIT/SET/RES instructions for operating on bits.

I didn't actually test the code I posted, so it may be wrong ;) Your explanation seems mostly correct. However, the CP B should be omitted in this version and the JR placed straight after the AND 7. This is because AND sets the flags based on the result of the computation, and when the INK and PAPER match, the result will be zero, and the zero flag set. Then the jump should work correctly.

Also, with RRA the bits that fall off the end aren't completely lost - they go into the carry flag which is then shifted into the topmost bit during the next RRA instruction. (You can think of RRA as a 9-bit rotate, with the 9th bit being the carry flag.) So in your example, after the RRAs the A register should equal 00100001. In this case it doesn't matter as the extra bits will be masked off anyway.
Hobes128
Drutt
Posts: 11
Joined: Sun Apr 14, 2019 6:13 pm

Re: I made a new App for the Multiface 3

Post by Hobes128 »

Thanks for the very detailed reply djnzx.

The multiface is indeed triggered via a non-mascable interuprt, but the last page of the manual states...
"to return from your program, to the program you stopped, use RST 0" so i just did what the manual said ;-)
http://www.worldofspectrum.org/pub/sinc ... Manual.pdf

Anyway, it's bed time for me now, but i'll come back to your post soon, and try and fully digest it.
Thanks again for the help!
User avatar
druellan
Dynamite Dan
Posts: 1470
Joined: Tue Apr 03, 2018 7:19 pm

Re: I made a new App for the Multiface 3

Post by druellan »

Hobes128 wrote: Thu May 16, 2019 11:22 pm druellan - 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 :-)
Done! And we found a little collection of hidden messages and secretly signed screens, pretty amazing considering I was trying to pick random titles (Spanish)

https://www.youtube.com/watch?v=xd06lBR4Yo0

The stream was so-so because of EightyOne: it has some issues with the autoload I was not aware of.
Hobes128 wrote: Thu May 16, 2019 11:22 pm 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).
The problem arises when you are loading a game that uses a custom loader, in that case, two things might happen:
- After the NMI, the custom loader just triggers a reset
- After the NMI, the custom loader keeps going, in that case, if there are no hidden attributes, you have no indication the NMI worked.

But those are small details, really, the code works pretty well!
Alcoholics Anonymous
Microbot
Posts: 194
Joined: Mon Oct 08, 2018 3:36 am

Re: I made a new App for the Multiface 3

Post by Alcoholics Anonymous »

Hobes128 wrote: Fri May 17, 2019 1:05 am The multiface is indeed triggered via a non-mascable interuprt, but the last page of the manual states...
"to return from your program, to the program you stopped, use RST 0" so i just did what the manual said ;-)
The multiface rom probably contains the right instructions to return to the caller at address 0. There are a few things that need to be done (write to port 0x3F to allow the nmi button to work again, read from port 0xBF to disable the multiface rom/ram mapping and that should be done just before a retn instruction in the spectrum rom). At least that's how I think it works :)

I have a question though - the multiface should be in invisible mode when it powers up which means you have to push the button and exit from the multiface at least once before enabling the multiface ram and copying your code there. Is that how it works on the real thing? I don't have one to try myself.

And the multiface manual mentions that you could write in to get more detailed programming instructions. I don't suppose anyone has seen these instructions?
User avatar
djnzx48
Manic Miner
Posts: 730
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: I made a new App for the Multiface 3

Post by djnzx48 »

djnzx48 wrote: Fri May 17, 2019 12:39 am So in your example, after the RRAs the A register should equal 00100001.
Sorry, I made a mistake here... I should have said 01000001.
Hobes128
Drutt
Posts: 11
Joined: Sun Apr 14, 2019 6:13 pm

Re: I made a new App for the Multiface 3

Post by Hobes128 »

Well, i've made a new version of my MF3 Easter Egg finder, with a pause added (as requested by druellan). After pressing the MF3 button, it now waits untill you press space before returning to the game. I incorporated some of djnzx's advice and removed all the calls, and replaced them with relative jumps too (so the code is portabel now) but i didnt incorporate the xor method as i didnt really understand it TBH. I might come back to that at some point. Anyway, here it is...

10 REM Multiface Easter Egg Finder V2 - By Hobes128 20,05,2019
20 CLEAR 32768
30 PAPER 6: INK 3: BORDER 0: BRIGHT 1: FLASH 1: CLS : PRINT "MULTIFAC 3 EASTER EGG FINDER"
40 PRINT : PRINT "SETTING UP - PLEASE WAIT"
50 FOR i=40000 TO 40027: READ a: POKE i,a: BEEP 0.01,(a/5): NEXT i
60 FOR i=40100 TO 40105: READ a: POKE i,a: BEEP 0.01,(a/5): NEXT i
70 FOR i=40200 TO 40282: READ a: POKE i,a: BEEP 0.01,(a/5): NEXT i
75 REM STOP
80 PRINT
90 PRINT "PLEASE ENSURE MULTIFACE IS ON, THEN PRESS ANY KEY"\#013100 PAUSE 0
110 RANDOMIZE USR 40000
120 PRINT : PRINT "DONE. NEXT TIME YOU PRESS THE MULTIFACE BUTTON, ANY HIDDEN MESSAGE WILL SHOW IN FLASHIN YELLOW/MAGENTA. Have Fun!"
130 DATA 219,63,33,164,156,17,0,32,1,6,0,237,176,33,8,157,17,96,34,1,84,0,237,176,0,219,191,201
140 DATA 96,34,0,82,85,78
150 DATA 245,197,213,229,33,0,88,17,0,3,126,230,7,71,126,230,56,31,31,31,184,40,56,35,27,122,179,32,237,62,6,211,254,6,140,5,32,253,62,19,211,254,6,140,5,32,253,62,6,211,254,6,80,5,32,253,62,19,211,254,6,80,5,32,253,1,254,127,237,120,254,191,40,211,225,209,193,241,199,54,243,24,196


I also experimented with some pointless border effects and sound, so while it's waiting for the space key to be pressed, it just a big of a horrible noise, and flashes the border a bit. This will probably be really annoying for anyone that actually wants to use the app, but i learned a bit more about coding, so it made me smile at least :-)
User avatar
druellan
Dynamite Dan
Posts: 1470
Joined: Tue Apr 03, 2018 7:19 pm

Re: I made a new App for the Multiface 3

Post by druellan »

Hobes128 wrote: Sun May 26, 2019 8:14 am Well, i've made a new version of my MF3 Easter Egg finder, with a pause added (as requested by druellan).
Beautiful, I need to test this ASAP. BTW, people got hooked on the small stream I did. To see the hidden messages on the actual screen instead of a text reference on an article makes a huge difference.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: I made a new App for the Multiface 3

Post by RMartins »

Just a suggestion.
You could remove the false positives, by checking if the contents have all bits set, or all bits reset.
If every bit is 1, or every bit is 0, in a specific char, there is no hidden content, it's just a color.
User avatar
druellan
Dynamite Dan
Posts: 1470
Joined: Tue Apr 03, 2018 7:19 pm

Re: I made a new App for the Multiface 3

Post by druellan »

[mention]Hobes128[/mention] I was testing the new version with some homebrew and...

Image
Post Reply