Previous Thread
Next Thread
Print Thread
Page 1 of 5 1 2 3 4 5
#112363 - 01/26/18 10:11 AM FireFly on the ZX Spectrum - Missing graphics  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Hi There!

I can't seem to get FireFly on the ZX spectrum to work correctly. The section where you select a square on the map, there is no fly to move. In fact, the fly is 'there' (You can move it and select a square from the map) but you just can't see it. Then once the game begins, you can fire, and you can hear your bullets, but you can't see your bullets.

Its very strange. I decided to try and work out what is going on. I thought the game might be doing something similar to Sidewize (Reading a strange/ula input port, waiting for the raster to be in a certain position before drawing the fly/bullets) so I traced all the opcodes during the "select a square on the map" section but the only input ports read are that are used for keyboard input.

Just wondered if anyone knows why this could be happening? What I might be able to do to investigate this further?

Many thanks!

#112368 - 01/26/18 01:10 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
problems are expected in the spectrum drivers because MAME in it's current form is incapable of emulating the waitstates correctly, at least not without extensive ugly hacks to the z80 core.

I'm sure once MAME is capable of that then the driver will get a massive overhaul as it's actually a relatively simple system otherwise

As a result tho, you're unlikely to find anybody wanting to dedicate too much time to this, because a lot of things will come down to the same source, bad timings, incorrect open bus behavior (that won't really be correct without proper timings) etc.

#112369 - 01/26/18 01:49 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Hi Haze and thanks for the response! I totally appreciate what you are saying about MAME's speccy timing flaws.

Bit of a long shot I know, but if it were timing/waitstate related, wouldn't it be more likely that you'd see the fly/bullets flicker, rather than not see them at all? My reasoning for saying this is that I've run lots of speecy games on mame, even the ones that seem to be effected by timing (A few that come to mind are 'Zynaps', 'Marauder' and 'Stormlord') are all still very playable, you just have to put up with that player's ship/hero flickering a bit.

#112370 - 01/26/18 01:52 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Dec 2015
Posts: 70
AJR Online content
Member
AJR  Online Content
Member

Joined: Dec 2015
Posts: 70
If the schematics are not totally incorrect, the ZX Spectrum hardware actually has no built-in wait states, and leaves /WAIT (along with /BUSREQ and /NMI) to be driven only through the external connector. I don't know exactly what's going on here, but this probably means that the ZX Spectrum ULA, like that of its Acorn Electron counterpart, conditionally stretches the CPU clock which it does output.

#112371 - 01/26/18 01:59 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
the way the waits work on the spectrum is extensively documented, but yeah, it's the ULA grabbing the bus, it can happen mid-opcode fetch or whenever else, stalling the z80 mid operation until it's done if the Z80 attempts to access any kind of contended memory be it for opcode fetch cycle or reading / writing.

the exact patterns of access are well documented for both the original spectrum and a number of clones and there's software that depends on them being near perfect (there's even software that only runs on certain machines due to the tiniest drifts in timing which can differ from machine to machine)

the Russian clone machines don't have any waits at all, so their compatibility is basically the same as MAME.

there is some (probably outdated at this point) information about it here
https://www.worldofspectrum.org/faq/reference/48kreference.htm

I've seen better references tho, although I can't find them right now. you can also find test software people have written that at least a few years ago could even detect an emulator / real machine most of the time. (with a few false positives due to some machines being more out of spec than others)


#112380 - 01/28/18 06:47 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Hi there and thanks again for the responses! As there is a small chance this isn't a timing issue (and for my own interest), I decided to to try and work out some of Firefly's machine code. I discovered that during the game's 'move your fly to a square on the map' section, the machine code repeatedly calls a number of big subroutines. Using Emuzwin and its poke feature, I put a return (C9H) opcode at the beginning of each subroutine to see what effect it had on the game.

For example, I found that one of the big subroutines being called in the main execution loop was located at address B23AH, which when I run the game with C9H at that address, I discovered everything looked fine, but I just wasn't able to move my fly (So I assume this subroutine is checking for key presses).

Here are my complete results:-

B029 CALL AE94H Fly flashes on and off. Fly image slightly distorted
B02C CALL B484H All looks fine but background does not refresh when fly is moved (I.e. fly leaves a trail of itself).
B02F CALL B41DH All looks fine but no fly shown
B032 CALL B1C8H All looks fine but no fly shown
B035 CALL B4B4H All looks fine but background does not refresh when fly is moved (similar to B484H)
B038 CALL B3C2H All looks fine but no moving stars are drawn
B03B CALL B23AH All looks fine but not able to move fly (no response to keyboard).
B03E CALL AD26H Game freezes in between menu and planet screen

I would now like to do the same with mame (See what effect, if any, putting C9H at locations AE94H, then at B4B4H etc..) has. Is there any way I can do this without building a hacked version of mame? Using its debugger perhaps (I've looked though the help but had no joy. Thought that the 'cheatinit' command sounded promising but I don't think that is quite what I'm looking for)??

Thanks for your help!

#112381 - 01/28/18 06:53 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Jun 2001
Posts: 382
Olivier Galibert Offline
Senior Member
Olivier Galibert  Offline
Senior Member

Joined: Jun 2001
Posts: 382
somewhere else entirely
Start with the debugger, press F12 and load the game, press ` when you want to get back control, open a memory view (menu or ctrl-m), go to the address you want to change, change it, F12 to make the game continue (F5 if you want to debugger windows to stay open).

OG.

#112391 - 01/29/18 09:34 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
That's just what I'm looking for, thanks OG!

#112409 - 01/31/18 01:17 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Hi there! I think I’ve found what the problem is and maybe a way to fix it….


Here is my over simplistic summary of what I think is happening during the game:-

Step 1. AE94H is called – This is a simple loop that exits only when the Vertical Blank Interrupt occurs (I.e. When the raster returns to the top of the display).
Step 2. B41DH is called – Draws a fly on to the existing background.
Step 3. B1C8H is called – This is a simple loop that exits after a certain amount of iterations (Its purpose is to wait for raster to pass over the fly that we have just drawn)
Step 4. Remove the fly off the background
Step 5. Check keyboard input and draw stars.
Step 6. Go back to ‘1’.

So the problem is that the game draws stuff before the raster, and clears it after the raster has gone. On a real spectrum, it appears that the fly is always floating nicely on the background image. As Mame does not have a raster, it updates the display ‘in one go’ with whatever z80 display memory (6144 bytes starting at address &4000) exists at the time of the interrupt (At Step 1).. Unfortunately, at the time of the interrupt, the display memory has always had its fly removed thus the player never gets to see it.


I think it might be possible to fix it (And make other games that do a similar ‘trick’ look a lot better) like this….

Currently in mame, there is an ‘m_icount’ variable that keeps track of how many cycles (TStates) have passed since the Interrupt occurred (Note. The spectrum runs 69888 TStates per frame). Once the interrupt occurs m_icount is set to 69888, it is then decremented by a certain amount based on each Z80 opcode processed. When m_icount reaches zero, it triggers the interrupt, the screen is redrawn and m_icount is set back to 69888 and off we go again.

Based on the m_icount, we can predict where raster position would be on a real spectrum. There are 312 lines per frame, thus each time m_icount is decremented by 224 (Which is 69888/312), we’ll know the raster will have finished displaying a line. Mame could keep a history of the display memory at these intervals (Stored in, say, an "display_history[312]" array). Then when the interrupt is triggered, update_screen_spectrum() rather that displaying what is currently in the z80 display memory, would instead go though the display_history[312] array and line by line piece together a more accurate render of the display.

This fix might even get the timing based colour effects working (Like the ones seen during the 128k ‘Amaurote’ intro for example).

Very interested to hear what the opinions are on this? I haven’t tested/hacked this yet, wanted to hear if it sounds like a good idea or not.

Many thanks!

#112410 - 01/31/18 01:29 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
I actually thought somebody had already added partial update support to the MAME Spectrum driver family as some of the Russian demos, which don't care about timing, use it.

I could be wrong tho, maybe those use a different piece of code entirely. I think it was MetalliC who did it for the Russian ones at least.

It won't fix the colour effects in lots of spectrum demos even if it was added tho, because they're all based on cycle counting which depends on exact timing. They'll end up different, but not correct.

#112431 - 02/01/18 10:48 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Mar 2013
Posts: 234
ICEknight Offline
Senior Member
ICEknight  Offline
Senior Member

Joined: Mar 2013
Posts: 234
César Hernández, the author of ZEsarUX (which I think is the most compatible Spectrum emulator out there) just told me that, even though he's really busy with his emulator and can't work directly on improving MAME's driver, he'd gladly help you guys with any answers you may need regarding the contended memory.

Any interested parties, just PM me for the email address if you don't have it already.


LCD artwork cleanups: https://mega.nz/#F!uFYSzK7S!U-lJon9jsqyoCX_3y7_KLA
#112432 - 02/01/18 12:40 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
As I understand it the problem isn't understanding the contended memory so much as needing a cycle-by-cycle Z80 core.

#112433 - 02/01/18 01:12 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: R. Belmont]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
Originally Posted by R. Belmont
As I understand it the problem isn't understanding the contended memory so much as needing a cycle-by-cycle Z80 core.


Well more to the point, you can't *accurately* emulate the contented memory without a cycle-by-cycle z80 core that can be interrupted / paused during any stage, either either fetching opcodes / oprands or executing them.

MAME doesn't have such a Z80 core, and considering how widely the Z80 is used and the potential for breakage, it would be a tremendous undertaking, it's potentially one of the biggest challenges in MAME.

Until *any* byte access the Z80 makes can be checked if it's a contented address, if it's a contended address, check if the ULA is accessing it, and if it is, stop the z80 in it's tracks before it even reads/writes that address, only resuming when the ULA is not accessing it, the Spectrum can't be accurate.

Since MAME doesn't allow that level of interruption (you'd basically need a speculative 'is the bus at this address available?' read before every regular z80read/write) then we can't do much. (In that sense it's probably even messier than just cycle-by-cycle, because the Z80 doesn't pause until the Z80 actually attempts to access contended memory, if you're running from non-contended addresses and not touching any contended ram / port, you get full speed)

The spectrum is a VERY simple system, but in the architecture MAME has this is a very big issue since it was never considered nearly 20 years ago when MAME started and now good support for it has to be worked in without breaking everything else.

#112434 - 02/01/18 01:28 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
It wouldn't need to be that complicated, just have the first-level address handler be (0000, ffff) (spectrum_r, spectrum_w) and it can check for ULA interference and then dispatch through a bankdev object for the I/O and stuff.

#112435 - 02/01/18 01:35 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: R. Belmont]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
Originally Posted by R. Belmont
It wouldn't need to be that complicated, just have the first-level address handler be (0000, ffff) (spectrum_r, spectrum_w) and it can check for ULA interference and then dispatch through a bankdev object for the I/O and stuff.


Right, but you'd still need the speculative read or some kind of 'I'm going to read/write' callback, because you need to stop the actual read from happening until the rest of the hardware is ready.

Even the cycle-by-cycle cores in MAME right now don't give you that afaik, there's no "I'm asserting these address lines" stage before the "I'm reading/writing data using these address lines" and I believe it's in that gap where the Z80 would pause.

At least that's my understanding of it.

#112436 - 02/01/18 02:07 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 842
Duke Offline
Senior Member
Duke  Offline
Senior Member

Joined: May 2004
Posts: 842
Germany
We do have (limited) support for that, see SETOFFSET_MEMBER. It's only used by some TI stuff so far.

#112437 - 02/01/18 02:13 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
You don't need to do the TI thing (which performance-penalizes even un-contended accesses), you can just make the Z80 so if HALT gets pulled by a read or write handler it backs up that cycle and halts.

#112438 - 02/01/18 02:17 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: R. Belmont]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
Originally Posted by R. Belmont
You don't need to do the TI thing (which performance-penalizes even un-contended accesses), you can just make the Z80 so if HALT gets pulled by a read or write handler it backs up that cycle and halts.


but then a write that wouldn't happen has already happened.
or a read that wouldn't happen has already happened.

you can rewind time to before they happened, but they still happened, that's why it needs to be speculative, not the actual operation, the actual operation can't be allowed to happen if the Z80 is frozen.

it might 'work' for most cases, but it's still a hack, and could still have side-effects. I suspect those hacks exist for this reason, because MAME can't handle it properly for the cores where it gets used.

since you're working with screens and raster timings here those things would directly affect how demos run. If you allow a write to happen, then have the CPU pause, that data, used for a screen effect, is going to be in VRAM not next time the ULA frees it, but before/during, which if you're doing accurate ULA timings, means the ULA might pull the incorrect data and the effect will appear a few pixels too early as RAM has already changed.

the fundamental problem, or at least the way I see it, is that the asserting of the address lines, and the actual read/write operation are two separate actions.

it's a similar theory those fast ARM cartridges for old systems work on, they can see the address lines being asserted as a separate operation before the data is read / written, and in those cases the ARM is fast enough to execute an entire block of code to get the data before it needs to be pushed out without slowing down the CPU.

MAME doesn't differentiate between the two stages of the operation. For things like this to work, without hacks, MAME needs to.

So yeah, the SETOFFSET_MEMBER type thing, prior to any access, be it readmem/writemem/readport/writeport/opcode fetch, as a separate instruction stage, including performance hit, absolutely *is* needed. This needs to be in conjunction with another callback to tell the CPU that the address it just tried to access is now free so that it can try again (due to timings, I guess it would need to check again if it was free incase something else stole it in the meantime)

I guess this is also really why you need code generators generating the CPU .cpp code too, because ideally you'd be able to generate fast/slow paths in the Z80 core, because I don't really think you want this level of accuracy for the one embedded in the Dreamcast for instance ;-) You'd want to be able to generate a version with all the checks / callbacks, and one without and pick which codepath to use depending on if the driver attempts to install callback handlers for address accesses.

I suppose you'd call this 'signal accurate' rather than 'cycle accurate' ?


#112443 - 02/01/18 09:19 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Feb 2018
Posts: 4
Cesar Hernandez Offline
Member
Cesar Hernandez  Offline
Member

Joined: Feb 2018
Posts: 4
You don’t need an accurate cycle z80 emulation
On my ZEsarUX emulator I don’t have it and a emulate contended memory and hi res color effects
You only need to have a table with contended memory delays and lookup on it every time you do a memory access. It’s really simple
However, there are some opcodes, like ldir, that makes more than 1 lookup in the same opcode, if you emulate them, you will have a perfect emulation. If not, you will have a nearly perfect emulation, which is enough to see the majority of these games without flickering

#112444 - 02/01/18 09:26 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
I guess it depends how correct you want to do it.

If you want to do it how the hardware works, in a way where there's no way for the emulated software to detect it, I think you would have to do it as I said.

Either way, surely an opcode fetch is a 'memory access' so you'd still need to be able to pause on every opcode fetch if you were running code from contended memory, that alone is an issue for MAME. Unless you're just adding up the cycles for each memory access then pausing for that long at the next given opporunity (which would be after a complete opcode has executed) however I don't see how that would actually be accurate unless it's coincidentally designed that the delays never fall mid-opcode?

If somebody has a solution for MAME which will work for all cases and be undetectable by software running on the Speccy I'd love to see it, maybe I've just over thought the problem and assumed all the worst cases that in reality don't happen. I know the MSX drivers in MAME have a similar 'delay table' approach (machine/msx.cpp actually it just looks like a gross table of custom opcode timings that have added waitstates) but I believe there is demo software that breaks those with ease.

Other drivers like the Sega System 1 driver seem to have to run the Z80 with a multiplied clock in order to do some kind of custom delay thing too, that I don't quite understand (Wonderboy really doesn't have a 20Mhz Z80)


Last edited by Haze; 02/01/18 09:35 PM.
#112445 - 02/01/18 09:30 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: Haze]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
Originally Posted by Haze
but then a write that wouldn't happen has already happened.
or a read that wouldn't happen has already happened.


No, they wouldn't. The read/write handler would simply not commit the actual read or write, set HALT, and bail. When the Z80 resumes it will redo the read/write and it'll actually go through at the right time.

#112449 - 02/01/18 11:16 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: R. Belmont]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
Originally Posted by R. Belmont
Originally Posted by Haze
but then a write that wouldn't happen has already happened.
or a read that wouldn't happen has already happened.


No, they wouldn't. The read/write handler would simply not commit the actual read or write, set HALT, and bail. When the Z80 resumes it will redo the read/write and it'll actually go through at the right time.


I'm not following at all.

As soon as the Z80 core is at the stage of knowing which address it's going to fetch / write to, that fetch / write happens, there's no way to halt in the middle of it. By the time you know, it's too late unless you're suggesting returning a dummy value, or noping the write in the handler, then rewinding.. but then we really are into hacks on hacks...

That would also get messy during opcode fetches / decodes.

Maybe I really just am overthinking it and letting the underlying grossness of it all bother me, but returning dummy values and expecting cpu cores to travel back in time sounds like a stack of plates I don't want to be around..


#112450 - 02/01/18 11:33 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: Haze]  
Joined: Feb 2018
Posts: 4
Cesar Hernandez Offline
Member
Cesar Hernandez  Offline
Member

Joined: Feb 2018
Posts: 4
Originally Posted by Haze
I guess it depends how correct you want to do it.

If you want to do it how the hardware works, in a way where there's no way for the emulated software to detect it, I think you would have to do it as I said.

Either way, surely an opcode fetch is a 'memory access' so you'd still need to be able to pause on every opcode fetch if you were running code from contended memory, that alone is an issue for MAME. Unless you're just adding up the cycles for each memory access then pausing for that long at the next given opporunity (which would be after a complete opcode has executed) however I don't see how that would actually be accurate unless it's coincidentally designed that the delays never fall mid-opcode?






Well I don't know the mame internal code, but I will explain on a simple way what I do on ZEsarUX: I have a t-states counter, every frame (1/50s) of the spectrum means 69888 frames (48k model) and every memory access or opcode fetch sums t-states. For example a NOP operation counts 4 t-states. When I read a memory address which has contention, I sum the value of the contention (values are from 0 to 7 if I remember well). So for example if I that NOP opcode is in contended memory, it could last 4+7 t-states(I'm inventing the 7 value). So that NOP will last 11 t-states instead of the uncontended and normal 4 t-states. Just as simple as that, I'm not adding "pauses" here, just making opcodes last longer (exactly what the z80 on the speccy does)

Cheers

#112451 - 02/01/18 11:49 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
right, you're making the opcode last longer

but in that opcode there are multiple stages, does the pattern never mean that the read part of an opcode is contended, but the write never is?

are you executing the opcode actions before or after decreasing the states value? if you're executing the actions of the opcode, then acting as if it took longer than it did, rather than causing a delay in the exection of the opcode due to it not being allowed to access the ram doesn't that mean you're going to be putting a value in ram, or reading a value from ram too early?

maybe the suggested workarounds for the spectrum are already taking all this into account by shifting when the waits happen or something...

I mean I can understand the theory of just adding the extra t-states as a workaround, but in my head at least it's going to cause some slight imperfections in when the actual memory changes compared to the real system.

I believe t-states are what MAME calls icounts anyway, but icount deductions happen after the opcode has been executed which would surely result in premature reads/writes if you consider the whole system. Doing it the way you suggest would actually be really easy in MAME, because we can just burn a few cycles if an access is contended, I'm just not convinced it would be 100% accurate especially not as time wouldn't be advancing as the cycles were burned so any opcode (including fetch) would either be fully contended, or not contended at all with a fully contented one doing a full read/write cycle obviously burning more than a nop that doesn't have any read/write beyond the opcode fetch. It would have no way of working where a read/write opcode fell across the boundary of a contended period.

I'd love to see the Spectrum driver in MAME run all the software and demos more than practically anybody else here, I've just never felt comfortable in adding it because of all these "what if" scenarios in my head for ways in which any code I write might break, however if I have completely misunderstood something, and it can be done without any issues at all I'd absolutely love to see somebody get it right. In part, that's because I'd actually love to try and develop some Speccy stuff of my own, but MAME is the environment in which I'm most comfortable working.

#112452 - 02/02/18 12:36 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: Haze]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
Originally Posted by Haze
I'm not following at all.

As soon as the Z80 core is at the stage of knowing which address it's going to fetch / write to, that fetch / write happens, there's no way to halt in the middle of it. By the time you know, it's too late unless you're suggesting returning a dummy value, or noping the write in the handler, then rewinding.. but then we really are into hacks on hacks..


You're running the Z80 cycle-per-cycle. It executes a load. Time gets to the exact cycle when the load or store happens. The read/write handler calls m_maincpu->HALT() and returns a dummy value on reads / doesn't write the value on writes. The Z80 immediately exits back to the scheduler and backs the current sub-cycle up 1, and when the ULA is finished you restart the Z80 minus however many cycles the ULA took (I assume the ULA is doing standard DMA where its cycles count against the CPU). It executes the read/write again, and this time they actually happen. For an opcode fetch it's even simpler, although you'd need to track if what got halted was a fetch or not.

#112453 - 02/02/18 12:38 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
And if what Cesar says works, we can just m_maincpu->adjust_icount(ula_cycles) and get much better compatibility for cheap.

#112455 - 02/02/18 05:39 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Feb 2018
Posts: 4
Cesar Hernandez Offline
Member
Cesar Hernandez  Offline
Member

Joined: Feb 2018
Posts: 4
Of course it works wink
I’m proposing a easy way to have a nearly 95% same spectrum cpu behaviour. I think you need to focus on achieve this 95% as I say on a easy way instead on trying to have a 100% super perfect cpu cycle by cycle

#112456 - 02/02/18 07:39 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: R. Belmont]  
Joined: Jun 2001
Posts: 382
Olivier Galibert Offline
Senior Member
Olivier Galibert  Offline
Senior Member

Joined: Jun 2001
Posts: 382
somewhere else entirely
Originally Posted by R. Belmont
Originally Posted by Haze
I'm not following at all.

As soon as the Z80 core is at the stage of knowing which address it's going to fetch / write to, that fetch / write happens, there's no way to halt in the middle of it. By the time you know, it's too late unless you're suggesting returning a dummy value, or noping the write in the handler, then rewinding.. but then we really are into hacks on hacks..


You're running the Z80 cycle-per-cycle. It executes a load. Time gets to the exact cycle when the load or store happens. The read/write handler calls m_maincpu->HALT() and returns a dummy value on reads / doesn't write the value on writes. The Z80 immediately exits back to the scheduler and backs the current sub-cycle up 1, and when the ULA is finished you restart the Z80 minus however many cycles the ULA took (I assume the ULA is doing standard DMA where its cycles count against the CPU). It executes the read/write again, and this time they actually happen. For an opcode fetch it's even simpler, although you'd need to track if what got halted was a fetch or not.


And that's essentially what I'm working on making possible sanely with the memory system stuff. With additional "don't return to the scheduler if your icount is big enough" goodness for decent performance.

#112461 - 02/02/18 02:34 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Thanks for all the responses, fascinating stuff regarding contented memory!

So do you think there is any point in me testing out my original suggestion (as it sounds like the source code I will be building on will soon be dramatically changing towards a cycle exact approach)??

Just to recap, my original suggestion was:-
Originally Posted by geecab

Currently in mame, there is an ‘m_icount’ variable that keeps track of how many cycles (TStates) have passed since the Interrupt occurred (Note. The spectrum runs 69888 TStates per frame). Once the interrupt occurs m_icount is set to 69888, it is then decremented by a certain amount based on each Z80 opcode processed. When m_icount reaches zero, it triggers the interrupt, the screen is redrawn and m_icount is set back to 69888 and off we go again.

Based on the m_icount, we can predict where raster position would be on a real spectrum. There are 312 lines per frame, thus each time m_icount is decremented by 224 (Which is 69888/312), we’ll know the raster will have finished displaying a line. Mame could keep a history of the display memory at these intervals (Stored in, say, an "display_history[312]" array). Then when the interrupt is triggered, update_screen_spectrum() rather that displaying what is currently in the z80 display memory, would instead go though the display_history[312] array and line by line piece together a more accurate render of the display.


With how Mame currently works, the above seems like quite a 'low impact' change with quite a bit of benefit. I'd imagine this would improve flicking on many games, and make Firefly playable. It wouldn't fix nifty colour effects seen in a few demos that really push the envelope, and it wouldn't fix nifty colour effects seen in a couple of games (To name a few - 'Dark Star' (The pattern drawn in the top border when viewing the hi-score table), 'Uridium' (The title 'Uridium' on the menu screen)) and 'Amaurote' (During the 128K intro sequence)). Actually, does anyone know just how many spectrum titles perform nifty colour effects, it might only be the ones I've mentioned?? :p

Many thanks!

#112462 - 02/02/18 02:38 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
a lot of the new Spectrum software does colour effects as it uses some game maker engine that was created and allows for 'multicolour' 'sprites' etc. (basically changing the attributes on each line using raster timing)

there are limits on what people can do with it, but it does look impressive.

there's are some older games doing similar too, but the modern development on the system really pushes the limits, proper smooth 50fps games etc.


Last edited by Haze; 02/02/18 02:40 PM.
#112463 - 02/02/18 06:02 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Feb 2018
Posts: 4
Cesar Hernandez Offline
Member
Cesar Hernandez  Offline
Member

Joined: Feb 2018
Posts: 4
Of course you will also need to add per-scanline drawing. If you only add contended memory, you will only notice a normal slowdown on some games, but the flicker on games will be almost the same. To fix flickering, you will need that per-scanline drawing

#112464 - 02/02/18 06:07 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
per-scanline drawing isn't difficult (in fact the code might already support finer grained than that, as I said, some stuff was added for the russian clone demos to work where there are no contended memory issues at least)

#112472 - 02/03/18 10:45 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: Haze]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Thanks Haze & Cesar!

Originally Posted by Haze
per-scanline drawing isn't difficult (in fact the code might already support finer grained than that, as I said, some stuff was added for the russian clone demos to work where there are no contended memory issues at least)


Any chance you could let me know the Russian clone that does the partial screen update (Or even point me to the code). I've had a look but I couldn't find it (But am most probably looking in the wrong place / looking for the wrong thing!). Basically, I trying to come up with a nice way that the src/devices/cpu/z80.z80.cpp can call a routine in the src/mame/video/spectrum.cpp to build up screen display line by line, and I'm hoping the code written for the Russian clone will help.

Many thanks!

#112473 - 02/03/18 11:02 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Jun 2001
Posts: 42
Osso Offline
Member
Osso  Offline
Member

Joined: Jun 2001
Posts: 42
Italy
I believe it's the Pentagon.
Here's the commit that added partial screen updates: https://git.redump.net/mame/commit/?id=128ba6317b7cb4cbdaea584be650b9ac29d289b9

#112476 - 02/03/18 02:18 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
That's excellent, thanks Osso!

#112603 - 02/13/18 10:46 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Hi there!

I decided to hack something in try out my suggestion. Basically, execute_run() (In src/devices/cpu/z80/z80.cpp) directly calls spectrum_plot_screen (A function I wrote in src/mame/video/spectrum.cpp) each time an opcode is processed. spectrum_plot_screen() keeps a running total of the tstates gone by since the vblank interrupt occurred, and with that draws a certain about of pixels up to the imagined position of the raster. After I did this, I then realised machine->first_screen()->vpos() and hpos() could give me the precise pixel position of the imagined raster position, so me working out the x and y based on tstate all felt a little pointless :p

Anyway, despite the ugliness of my hack, the results were pretty spectacular (OMG see what I did there!). Flicker gone completely on Stormlord and Marauder. Firefly now fully playable. Amaurote 'Traal Welcomes You' colour effect looks spot on.

Here is an image containing screenshots showing the aforementioned games with and without my hack so you can spot the difference (Top row of screen shots are without the hack, bottom row screen shots are with the hack)...
zx game screenshots before and after hack

Here is a diff of my hack...
my diff

So my thoughts are now, can the spectrum driver have a timed callback for every machine cycle (Similar to, say, the device_timer() function that is there already), and that each time it is triggered, the function calls the existing spectrum_UpdateScreenBitmap() function? I think that would achieve the same result as what I have done with much less ugliness?

Thanks for reading!

#112605 - 02/13/18 03:08 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Now implemented using a timed callback for every CPU cycle. A lot less code changes for the same benefit. I don't fully understand how the emu_timers work, so might have broken something in the process, but all the games I tried previous work & look as good as they did with my original hack.

Code
diff --git a/src/mame/drivers/spectrum.cpp b/src/mame/drivers/spectrum.cpp
index 39c7974919..9a26903325 100644
--- a/src/mame/drivers/spectrum.cpp
+++ b/src/mame/drivers/spectrum.cpp
@@ -285,7 +285,6 @@ SamRam
 #include "screen.h"
 #include "softlist.h"
 #include "speaker.h"
-
 #include "formats/tzx_cas.h"
 
 
@@ -445,6 +444,7 @@ static ADDRESS_MAP_START (spectrum_io, AS_IO, 8, spectrum_state )
 	AM_RANGE(0x01, 0x01) AM_READ(spectrum_port_ula_r) AM_MIRROR(0xfffe)
 ADDRESS_MAP_END
 
+
 /* Input ports */
 
 /****************************************************************************************************/
@@ -643,13 +643,25 @@ GFXDECODE_END
 
 void spectrum_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
 {
-	m_maincpu->set_input_line(0, CLEAR_LINE);
+	switch (id)
+	{
+	case TIMER_IRQ_OFF:
+		m_maincpu->set_input_line(0, CLEAR_LINE);
+		break;
+	case TIMER_CPU_CYCLE:
+		timer_set(m_maincpu->cycles_to_attotime(1), TIMER_CPU_CYCLE);
+		spectrum_UpdateScreenBitmap();
+		break;
+	default:
+		printf("Unknown device_timer id=%d\n", id);
+		exit(0);
+	}
 }
 
 INTERRUPT_GEN_MEMBER(spectrum_state::spec_interrupt)
 {
 	m_maincpu->set_input_line(0, HOLD_LINE);
-	timer_set(attotime::from_ticks(32, m_maincpu->clock()), 0, 0);
+	timer_set(attotime::from_ticks(32, m_maincpu->clock()), TIMER_IRQ_OFF, 0);
 }
 
 MACHINE_CONFIG_START(spectrum_state::spectrum_common)
diff --git a/src/mame/includes/spectrum.h b/src/mame/includes/spectrum.h
index d227e10e58..ad654c14d2 100644
--- a/src/mame/includes/spectrum.h
+++ b/src/mame/includes/spectrum.h
@@ -63,6 +63,12 @@ struct EVENT_LIST_ITEM
 class spectrum_state : public driver_device
 {
 public:
+        enum
+        {
+                TIMER_IRQ_ON,
+                TIMER_IRQ_OFF,
+                TIMER_CPU_CYCLE
+        };
 	spectrum_state(const machine_config &mconfig, device_type type, const char *tag)
 		: driver_device(mconfig, type, tag),
 		m_video_ram(*this, "video_ram"),
@@ -110,6 +116,8 @@ public:
 
 	int m_ROMSelection;
 
+	emu_timer *m_cpu_cycle_timer;
+
 
 	EVENT_LIST_ITEM *m_pCurrentItem;
 	int m_NumEvents;
diff --git a/src/mame/video/spectrum.cpp b/src/mame/video/spectrum.cpp
index 2a26f0f209..9ccab4428d 100644
--- a/src/mame/video/spectrum.cpp
+++ b/src/mame/video/spectrum.cpp
@@ -37,6 +37,9 @@ VIDEO_START_MEMBER(spectrum_state,spectrum)
 	machine().first_screen()->register_screen_bitmap(m_screen_bitmap);
 
 	m_screen_location = m_video_ram;
+
+	m_cpu_cycle_timer = timer_alloc(TIMER_CPU_CYCLE);
+	timer_set(m_maincpu->cycles_to_attotime(1), TIMER_CPU_CYCLE);
 }
 
 VIDEO_START_MEMBER(spectrum_state,spectrum_128)
@@ -53,6 +56,9 @@ VIDEO_START_MEMBER(spectrum_state,spectrum_128)
 	machine().first_screen()->register_screen_bitmap(m_screen_bitmap);
 
 	m_screen_location = m_ram->pointer() + (5 << 14);
+
+	m_cpu_cycle_timer = timer_alloc(TIMER_CPU_CYCLE);
+	timer_set(m_maincpu->cycles_to_attotime(1), TIMER_CPU_CYCLE);
 }
 
 
@@ -73,7 +79,7 @@ WRITE_LINE_MEMBER(spectrum_state::screen_vblank_spectrum)
 	if (state)
 	{
 		spectrum_UpdateBorderBitmap();
-		spectrum_UpdateScreenBitmap(true);
+		//spectrum_UpdateScreenBitmap(true);
 
 		m_frame_number++;
 
@@ -122,7 +128,7 @@ uint32_t spectrum_state::screen_update_spectrum(screen_device &screen, bitmap_in
 	if (m_border_bitmap.valid())
 		copyscrollbitmap(bitmap, m_border_bitmap, 0, nullptr, 0, nullptr, cliprect);
 
-	spectrum_UpdateScreenBitmap();
+	//spectrum_UpdateScreenBitmap();
 	if (m_screen_bitmap.valid())
 		copyscrollbitmap(bitmap, m_screen_bitmap, 0, nullptr, 0, nullptr, rect);

#112606 - 02/13/18 03:10 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
Ok, that second patch is much nicer. If it gets all the benefits, I'd be inclined to apply it. How badly does it hurt performance?

#112607 - 02/13/18 03:14 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Feb 2004
Posts: 1,906
Vas Crabb Online content
Very Senior Member
Vas Crabb  Online Content
Very Senior Member

Joined: Feb 2004
Posts: 1,906
Sydney, Australia
Timers are very inefficient if you're running them at these kinds of frequencies. Wouldn't you be better of making something that inherits `device_execute_interface` running at CPU clock and setting perfect interleave on it? Then you'll get your `execute_run` callback every time the Z80 yields, and you can just do your update and finish your timeslice.

#112608 - 02/13/18 03:48 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Mar 2001
Posts: 15,851
R. Belmont Online content
R. Belmont  Online Content

Very Senior Member

Joined: Mar 2001
Posts: 15,851
USA
I agree, but this is a very low-performance system already so I'd like to see numbers before trying to force someone off-list into doing something even Haze is terrified of.

#112609 - 02/13/18 05:54 PM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Thanks for the responses!

According to top, when running Firefly my CPU performance jumps from 12% without my hack, to 57% with my hack. Ouch!

Thinking about it, the timer really doesn't need to be triggered every cycle. Just been increasing the timeout (number of cycles) value to see how it effects CPU:-
1 cycle = 57% CPU
8 cycles = 19% CPU
16 cycles = 15% CPU
32 cycles = 13% CPU
224 cycles = 12% CPU

Might as well go with 224, at least it is clear that the screen is being put together line-by-line. Just tried the games out and they all look/play just as good.

I don't think my changes can be applied as-is though as I think I may have broken a few Russian clones. See the diff above, in the mame/video/spectrum.cpp file I commented out calls to spectrum_UpdateScreenBitmap() from the screen_vblank_spectrum() and screen_update_spectrum() functions. I reckon/guess a few of the clones rely on these calls. I will try and get my head around which ones will need attention.

#112681 - 02/18/18 10:42 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: Apr 2013
Posts: 41
geecab Offline
Member
geecab  Offline
Member

Joined: Apr 2013
Posts: 41
Originally Posted by Haze
per-scanline drawing isn't difficult (in fact the code might already support finer grained than that, as I said, some stuff was added for the russian clone demos to work where there are no contended memory issues at least)


Hi Haze! Any ideas of the names of these demos that work on the Pentagon? The existing (Partial screen update) fixes to the Pentagon driver basically result in calling spectrum_UpdateScreenBitmap() (In the pentagon_scr_w and pentagon_scr2_w memory write handler functions) more often than the Spectrum driver does. I think doing this somehow 'gets by' making these Russian demos work but doesn't fix the 'Firefly' issue or the flickering in certain games. I don't think the Pentagon driver's extra calls to spectrum_UpdateScreenBitmap() would be necessary if I implement my fix (Repeatedly triggering a call to spectrum_UpdateScreenBitmap() after x amount of CPU cycles). Just want to try these Pentagon demos out for myself in case there is something I haven't understood.

#112682 - 02/18/18 11:56 AM Re: FireFly on the ZX Spectrum - Missing graphics [Re: geecab]  
Joined: May 2004
Posts: 1,484
Haze Offline
Very Senior Member
Haze  Offline
Very Senior Member

Joined: May 2004
Posts: 1,484
_Metallic_ would know better about the Russian demos than I do as he enabled the partial update support for them in the first place.

Maybe if you were lucky some of them were added to a software list, but I don't think they were (they probably should be tho as they provide useful test cases)

Last edited by Haze; 02/18/18 11:57 AM.
Page 1 of 5 1 2 3 4 5

Who's Online Now
5 registered members (EoceneMiacid, Dorando, Edstrom, robcfg, 1 invisible), 28 guests, and 0 spiders.
Key: Admin, Global Mod, Mod
Shout Box
Forum Statistics
Forums9
Topics8,496
Posts110,806
Members4,781
Most Online225
May 26th, 2014
Powered by UBB.threads™ PHP Forum Software 7.6.0
Page Time: 0.086s Queries: 14 (0.031s) Memory: 5.3635 MB (Peak: 5.8250 MB) Zlib enabled. Server Time: 2018-02-22 16:23:22 UTC