Norman Sword Posted April 8, 2021 Report Share Posted April 8, 2021 You can speed up the Copy routines by 25% by changing to inline LDI - But that necessitates knowing z80 and the writing the code. You can also delete #89ad (3 bytes) animate willy along the bottom(graphics) #89ef (3 bytes) animate conveyors(graphics) #8a3a (3 bytes) print the time(text) #8a46 (3 bytes) print items(text) #944e (3bytes) animates graphic item/object #8e20 (2bytes) and #8e23(2bytes) remove the jumping/falling sfx Plus make sure the tune is turned off. When doing the most basic operation a few million times needlessly, It all starts to add up to hours. IRF, crem and jetsetdanny 2 1 Quote Link to comment Share on other sites More sharing options...
crem Posted April 9, 2021 Author Report Share Posted April 9, 2021 19 hours ago, Norman Sword said: It all starts to add up to hours. Thanks a lot, that helped a lot! Without changes I could generate 2450 frames per second. With 3 LDIRs replaced with NOPS, 3950 fps. With your changes (and LDIRs replaced) -- whopping 5130 fps! With LDIR being so slow, I'm thinking of changing the emulator to just run memset() for LDIR instead of emulating it "properly" (with fetching instruction on every iteration, incrementing all the registers and updating t-state count as it runs). Maybe then it would get even higher. For now I'm not sure if that's worth the time to implement it, so any other micro-optimizations like that would be appreciated. IRF and jetsetdanny 2 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted April 9, 2021 Report Share Posted April 9, 2021 (edited) The LDIR instruction was written to enable interrupts to occur whilst the instruction takes place. Because the Z80 system uses interrupts for a host of external devices as well as synchronisation and housekeeping tasks. Enabling interrupts while an LDIR is taking place was important and that is why the LDIR is so slow. After every move of one byte the program counter moves back and reloads the LDIR instruction and repeats the one byte move. JSW does not use the interrupts and therefore any external block move sequence that can be used in place of LDIR will have absolutely no impact on what the game does. So if you externally move the block in place of the LDIR doing it. The game will take no notice and just carry on. I don't think it even cares about T-states - used mainly for the refresh register and again not used. Edited April 9, 2021 by Norman Sword jetsetdanny, andrewbroad and crem 2 1 Quote Link to comment Share on other sites More sharing options...
crem Posted April 9, 2021 Author Report Share Posted April 9, 2021 5 minutes ago, Norman Sword said: The LDIR instruction was written to enable interrupts to occur whilst the instruction takes place. Because the Z80 system uses interrupts for a host of external devices as well as synchronisation and housekeeping tasks. Enabling interrupts while an LDIR is taking place was important and that is why the LDIR is so slow. After every move of one byte the program counter moves back and reloads the LDIR instruction and repeats the one byte move. JSW does not use the interrupts and therefore any external block move sequence that can be used in place of LDIR will have absolutely no impact on what the game does. So if you externally move the block in place of the LDIR doing it. The game will not care less. One more case where it could matter is if LDIR overwrites the memory of the instruction itself. Hopefully that doesn't happen in JSW though. Also I'm a bit afraid that after my replacement it with a simple memcpy, I'll leave cpu in wrong state (e.g. forget to set flags which would be needed afterwards... But I think JSW doesn't rely on register/flag values after LDIR instructions). I'll give it a try anyway. Do you think something like that would be good enough (e.g. ignoring all flags altogether)? uint16_t hl = GET_HL(); uint16_t de = GET_DE(); uint16_t bc = GET_BC(); memmove(&memory[de], &memory[hl], bc); // Can overflow if goes over 0xffff but should not happen in JSW SET_HL(hl + bc); SET_DE(de + bc); SET_BC(0); The current emulation code also does some magic with Y, X and V flags, and I never even heard about those Z80 flags. 🙂 Hopefully it's ok not to touch them. Although maybe it makes sense to reset S/Z/C. Quote Link to comment Share on other sites More sharing options...
crem Posted April 14, 2021 Author Report Share Posted April 14, 2021 Totally offtopic for this thread, but I'm just curious. Usually when talking about memory addresses written in hexadecimal form, I can see 3 prefixes are used: #, $ and & (#DA78, $DA78 and &DA78) (Also there's 0xDA78 and DA78h but those I know where they come from). I wonder which of those prefixes is more common and where they all come from? I know that in Pascal $ is a prefix for hex numbers, but weren't there a Z80 assembler which used that? jetsetdanny 1 Quote Link to comment Share on other sites More sharing options...
jetsetdanny Posted April 14, 2021 Report Share Posted April 14, 2021 I couldn't tell you. I got accustomed to using the # prefix, because I saw it used by some people on the JSW scene (probably by Dr. Andrew Broad who would have been back then and continues to be an authority for me on this kind of subjects) and just followed suit 🙂. andrewbroad 1 Quote Link to comment Share on other sites More sharing options...
Norman Sword Posted April 14, 2021 Report Share Posted April 14, 2021 Been writing z80 since 1982 and I have witnessed many changes. Originally nearly all hex was 01234h, but the format used would be forced upon you by whatever assembler you used. The assemblers did not all use the same syntax. At present I use whatever comes to hand, and yes I will use every notation 1235h,#1234,$1234,0x1234 and my present assembler is happy with all of them After writing a lot of code it becomes easier to use #123a for no other reason than it becomes tedious when editing a lot of hex data to remember to make sure that any hex data is preceded by a non hex digit. eg whilst 1fffh is valid d000h is not and needs changing to 0d000h. When a lot of data is being manually edited and the assembler keeps throwing out the data. It becomes easier to use a format that always complies with the syntax so changing #8000 to #c000 will always assemble whilst the edit of 8000h to c000h is a syntax error. IRF and jetsetdanny 2 Quote Link to comment Share on other sites More sharing options...
Spider Posted April 14, 2021 Report Share Posted April 14, 2021 I was used to seeing the # prefix and sometimes a 'h' suffix. Starting on the Spectrum platform in 84, there was not really any built in hex facility. Those who perhaps started coding on the Acorn machines may be more used to & however. For instance typing PRINT &C9 will return you with an answer of 201 , which is correct as #C9 is 201 in decimal. This is also accepted for the Amstrad CPC range too. Can't recall which but one emulator in the "insert pokes" section seems to prefer a $ prefix for hex values too, just to add to the mix! Personal preference is simply #xx as its quite easy to distinguish between: LD A , #80 JP #7530 Decimal of the above: LD A , 128 JP 30000 I do realise I'm slightly contradicting myself as today I did provide some 'pokes' using a different prefix however the prefix suited the platform they were intended for! , but in general if I was writing a post or such I'd rather just use #value, its easy to type and does not or should not lead to any confusion. jetsetdanny and andrewbroad 2 Quote Link to comment Share on other sites More sharing options...
crem Posted April 27, 2021 Author Report Share Posted April 27, 2021 Quick question. I have a breakpoint at address #8C01, and generate various playthroughs in JSW, and it sometimes happens that number of lives decreases (and guardian cycles seemingly reset) without hitting that breakpoint. I'm fairly sure it's bug in my code, but just checking, maybe I missed something in JSW code... Could you think of some ways of this happening in JSW? (number of lives decreases without hitting breakpoint at #8C01). That happens in the very first room, "The bathroom". Thanks! jetsetdanny 1 Quote Link to comment Share on other sites More sharing options...
IRF Posted April 27, 2021 Report Share Posted April 27, 2021 I can't think of a way in which #8C01 is bypassed when losing a life. When you've observed it happen, does the program bypass the 'fade to black' screen effect? If so, maybe a bug in your code means that you have an entry point into the routine at #8C33? crem, jetsetdanny and andrewbroad 2 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.