Due to unusually high levels of website traffic you will be presenting with regular Cloudflare checks for the time being.

Game development trick? Or something else?

Struggling with Fuse or trying to find an emulator with a specific feature. Ask your questions here.
Post Reply
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Game development trick? Or something else?

Post by beginner »

Hi everybody,

I'm back with yet another question :) .

After successfully emulating the Z80 cpu,
over the past weekend I thought that maybe I should take it to the next level and also implement a basic ZX Spectrum 48K emulator.

A good couple of hours later I was ready to take it for a spin.
With fingers crossed, I loaded a snapshot and ... it worked. And I was hooked :D.

It was time to load more games :D .

Most of them worked without any problems.
However, there were some which would only display a black screen with a white border and hang.
I kind of expected this, since I'm only doing the most basic emulation and far from perfect timing.

My emulation loop basically looks something like this:

Code: Select all

while(true) {
	cpu_step_for_69888_cycles();
	cpu_compensate_if_overstepping();
	decode_screen_file();
	update_screen();
	.
	.
	wait_for_20ms_to_pass();
	signal_cpu_interrupt();
}
Later on, I started poking (pun intended :P) around the source code, doing some cleanup and I noticed that I forgot to mark the lower 16K of memory as read only, which basically allowed writes to the ROM area :o .
After fixing that and by total accident I re-loaded one of the non-working games. Except that now it worked perfectly! :o :D. And so did all the others.

I did a bit more digging and debugging and I noticed that these games were actually trying to POKE the ROM area - and before I fixed that part, they succeeded.
For example, the 8BitTRIS game would try to constantly POKE the ROM during the menu display.

And now finally, my question :P :
is this "POKE the ROM" practice some kind of game development trick on the ZX Spectrum? Or is it something else, more general? What exactly is it testing?
scoppack
Dizzy
Posts: 65
Joined: Mon Jun 22, 2020 9:33 am

Re: Game development trick? Or something else?

Post by scoppack »

Hiya, i wrote 8bitTris, and i have no idea!!
The title loop is just badly playing music with its stock player. Theres definately no special secrets in my code. I just try to work around redraws to hide tearing.
User avatar
Turtle_Quality
Manic Miner
Posts: 508
Joined: Fri Dec 07, 2018 10:19 pm

Re: Game development trick? Or something else?

Post by Turtle_Quality »

Sounds like you're making good progress.

Yes poking rom has no actual effect on real hardware. But I have used it to make screen printing faster and simpler ;

If you use a lookup table for the address of each screen row, and say you want your 16 x 16 pixel sprite routine to be able to partially print at the top and bottom of screen, then you can have the first 15 address and the last 15 address point to any location in ROM. That way the code does not need to check with every row if it's off screen, so the code is a little simpler, runs a little faster (compared to lookup table and check "am I offscreen") and takes a consistent number of T states

My only game published here (so far) doesn't use that technique but I'm probably not the only who thought of coding that way
Definition of loop : see loop
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

scoppack wrote: Mon Jul 04, 2022 9:53 am Hiya, i wrote 8bitTris, and i have no idea!!
The title loop is just badly playing music with its stock player. Theres definately no special secrets in my code. I just try to work around redraws to hide tearing.
Hi @scoppack ,
I was hoping there was some magic going on there :D , especially since it seems that multiple games exhibit this behavior. I still hope, actually :D

My logs showed that 8bitTris and Anteater tried to write at address 0x00 the value 0xf9. Other games tried to write to other ROM addresses different data. However, Pacman - The Curse of the Slimers did not made any ROM write attempt.

Another thing that I noticed is that without the ROM-write protection - a.k.a when the game hangs - the written data value would increase until it reaches 0xff.

Code: Select all

ROM write attempted at: 0x0  , data: 0xf9  
ROM write attempted at: 0x0  , data: 0xfc  
ROM write attempted at: 0x0  , data: 0xfe  
ROM write attempted at: 0x0  , data: 0xff  
ROM write attempted at: 0x0  , data: 0xff  
ROM write attempted at: 0x0  , data: 0xff
...
ROM write attempted at: 0x0  , data: 0xff
Btw: I love your games ;) . I spent quite some time over the weekend playing them :D .
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

Hi @Turtle_Quality
Turtle_Quality wrote: Mon Jul 04, 2022 10:34 am Sounds like you're making good progress.
I have to admit, I never thought that working on a emulator would be such a great experience. But now, I'm hooked :D
Edit: Ups, I just realized your note might have been for scoppack. My bad :D
Turtle_Quality wrote: Mon Jul 04, 2022 10:34 am Yes poking rom has no actual effect on real hardware. But I have used it to make screen printing faster and simpler ;

If you use a lookup table for the address of each screen row, and say you want your 16 x 16 pixel sprite routine to be able to partially print at the top and bottom of screen, then you can have the first 15 address and the last 15 address point to any location in ROM. That way the code does not need to check with every row if it's off screen, so the code is a little simpler, runs a little faster (compared to lookup table and check "am I offscreen") and takes a consistent number of T states

My only game published here (so far) doesn't use that technique but I'm probably not the only who thought of coding that way
So there is some magic after all :D . Nice! :D

Btw: which one is your game? I couldn't find it on a quick look around.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2643
Joined: Mon Nov 13, 2017 3:16 pm

Re: Game development trick? Or something else?

Post by Ast A. Moore »

Indeed, writing to ROM is sometimes used for screen address calculations (primarily, when an object goes off the top of the screen area). This greatly simplifies things and speeds up calculations. I think I used that technique in one of the earlier versions of Yankee for the missiles (the code may still be there, I haven’t looked at it recently).

P.S. If you want to perfect your emulator, then my Yankee is something you might want to consider for testing. It’s not meant for beginner-level emulators, though, since it uses the floating bus, but for future development goals, I think you’ll find it ideal. ;)
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

Hi @Ast A. Moore
Ast A. Moore wrote: Mon Jul 04, 2022 12:00 pm Indeed, writing to ROM is sometimes used for screen address calculations (primarily, when an object goes off the top of the screen area). This greatly simplifies things and speeds up calculations. I think I used that technique in one of the earlier versions of Yankee for the missiles (the code may still be there, I haven’t looked at it recently).
Awesome! I love this kind of little tricks :D .
Ast A. Moore wrote: Mon Jul 04, 2022 12:00 pm P.S. If you want to perfect your emulator, then my Yankee is something you might want to consider for testing. It’s not meant for beginner-level emulators, though, since it uses the floating bus, but for future development goals, I think you’ll find it ideal. ;)
I took your advice and gave Yankee a shot. I tried out the this Yankee version. As expected, since I currently do not have a floating bus implementation and even though I was able to start the game, it froze as soon as the helicopter showed up on the screen :).

And then, I thought, how about if I try a little hack? What if I update my I/O port read logic to return random numbers between 0x00 and 0xff when a read is attempted from an unassigned/non-existing I/O port number?
One line of code later the helicopter started purring like a kitten. Much to my surprise, it started working perfectly ;).

I still need to properly read up on and implement floating bus support in the future, but I was just way to curious not to try out Yankee right now :D.

All I need now is to start perfecting my piloting skills :P.
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2643
Joined: Mon Nov 13, 2017 3:16 pm

Re: Game development trick? Or something else?

Post by Ast A. Moore »

the.beginner wrote: Mon Jul 04, 2022 3:12 pm And then, I thought, how about if I try a little hack? What if I update my I/O port read logic to return random numbers between 0x00 and 0xff when a read is attempted from an unassigned/non-existing I/O port number?
One line of code later the helicopter started purring like a kitten. Much to my surprise, it started working perfectly ;).
Ha, that’s a dirty trick! :lol:
the.beginner wrote: Mon Jul 04, 2022 3:12 pmI still need to properly read up on and implement floating bus support in the future, but I was just way to curious not to try out Yankee right now :D.
I have a basic write-up on my website (link in my signature). It’s mostly geared toward game developers, rather than emulator authors, but hopefully you can find some useful information there. I also have a special test designed for cycle-accurate testing of the floating bus on the +2A/+3 (which is different from the 48K/128K), in case you’re ever going to emulate those machines.
the.beginner wrote: Mon Jul 04, 2022 3:12 pm All I need now is to start perfecting my piloting skills :P.
That might take a while. It was at the request (complaints, actually, heh) of many people on this forum that I added the difficulty selection to the game in v1.3.1 ;)
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

Ast A. Moore wrote: Mon Jul 04, 2022 5:09 pm That might take a while. It was at the request (complaints, actually, heh) of many people on this forum that I added the difficulty selection to the game in v1.3.1 ;)
I'm starting to realize that :lol:
scoppack
Dizzy
Posts: 65
Joined: Mon Jun 22, 2020 9:33 am

Re: Game development trick? Or something else?

Post by scoppack »

Really glad you liked them! I've had a lot of time out lately, but trying to get motivated again and finish the 2 projects.
I've just looked quickly at the code and for 8bitTris its all in RAM. There is no lookup for screen addresses. There is a counter for kind of random counter seed in the main intro loop. It may be a spill for IM2 which is very high in memory, but nothing i can see that tries to write to it while incrementing. Seems I'm more of a mainstream coder than I thought! Nice one :) I've always been interested in how emulators are made, but thats just another distraction from my shootemup which is currently 14 months behind schedule.
I'm now intrigued what's causing it.
User avatar
Turtle_Quality
Manic Miner
Posts: 508
Joined: Fri Dec 07, 2018 10:19 pm

Re: Game development trick? Or something else?

Post by Turtle_Quality »

@the.beginner My game was Mazeball - it's an extremely simple bit of compiled basic from 1984. And it was your progress I was praising, not tried making an emulator myself but a couple of friends of mine did and I can see there's a lot of things you've got to get right before you get standard 48K games working okay.

After that there's all the finer points of timing (such as memory contention) for games that rely on exact timing, undocumented instructions, undocumented flag bits, the floating bus, then a whole list of extra features and hardware you can implement. The sky's the limit.

@scoppack does your monitor/ debugger allow pause on a write to location range ? Or perhaps @the.beginner can see what at address the curious instruction occurs
Definition of loop : see loop
scoppack
Dizzy
Posts: 65
Joined: Mon Jun 22, 2020 9:33 am

Re: Game development trick? Or something else?

Post by scoppack »

tbh, i've no idea how to use a debugger properly. I fudge it with CSpect and checking on regs and memory locations, or setting areas on screen for actions or branches. If you can provide a possible memory location of the code that is trying to write, i can look that up.
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

@Turtle_Quality
Thank you for your kind words. I still have lots to do. My current implementation is still very basic.
It does support the entire Z80 instruction set, both documented and undocumented, however as far as flags are concerned only the documented ones are handled for now. Floating bus, contention, proper timing... all these are currently still missing.

I was as surprised as excited when I saw that so many games are actually working even with such a basic emulation :D .

@scoppack , @Turtle_Quality
One of the biggest mistakes I made was to not develop a proper debugger for the project, but then again, the entire project pretty much evolved on the fly, without much planning. Basically, my rudimentary 'debugger', when enabled, just dumps the state of the registers to the console after an executed instruction.
Mazeball works too. However, behind the scenes it seems to exhibit the same 'ROM-write attempt' behavior as 8bitTris.

More and more, I'm starting to have the feeling that maybe some well hidden bug is lurking inside my emulator :lol: .
I would definitely not rule out that possibility :D .

I managed to collect some logs from 8bitTris when the 'ROM-write attempt' happened, but they seem to be kind of strange.
It seems that NOPs are executed in a loop while a counter is running (as shown by the PC and the BC reg pair). I encountered the same thing while running Mazeball too.

Maybe we should take a look at this on a well established and "trusted to work correctly" emulator :lol:

Code: Select all

ROM write attempted at: 0x0   , data: 0xf9
37918.	 OP: 0     	     NOP            	 PC: B6BA	 SP: FF23	 BC: 0008	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 3C	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37919.	 OP: 0     	     NOP            	 PC: B6BC	 SP: FF23	 BC: 0008	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 3E	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37920.	 OP: 0     	     NOP            	 PC: B6BE	 SP: FF23	 BC: 0008	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 40	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37921.	 OP: 0     	     NOP            	 PC: B6BF	 SP: FF23	 BC: 0008	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 41	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37922.	 OP: 0     	     NOP            	 PC: B6C0	 SP: FF25	 BC: 0008	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 42	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37923.	 OP: 0     	     NOP            	 PC: B6B4	 SP: FF25	 BC: FF08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 43	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37924.	 OP: 0     	     NOP            	 PC: B6B5	 SP: FF23	 BC: FF08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 44	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37925.	 OP: 0     	     NOP            	 PC: B6B8	 SP: FF23	 BC: FF08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 45	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37926.	 OP: 0     	     NOP            	 PC: B6BA	 SP: FF23	 BC: FF08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 47	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37927.	 OP: 0     	     NOP            	 PC: B6BC	 SP: FF23	 BC: FF08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 49	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37928.	 OP: 0     	     NOP            	 PC: B6BE	 SP: FF23	 BC: FF08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 4B	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37929.	 OP: 0     	     NOP            	 PC: B6BF	 SP: FF23	 BC: FF08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 4C	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37930.	 OP: 0     	     NOP            	 PC: B6C0	 SP: FF25	 BC: FF08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 4D	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37931.	 OP: 0     	     NOP            	 PC: B6B4	 SP: FF25	 BC: FE08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 4E	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37932.	 OP: 0     	     NOP            	 PC: B6B5	 SP: FF23	 BC: FE08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 4F	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37933.	 OP: 0     	     NOP            	 PC: B6B8	 SP: FF23	 BC: FE08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 50	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37934.	 OP: 0     	     NOP            	 PC: B6BA	 SP: FF23	 BC: FE08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 52	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37935.	 OP: 0     	     NOP            	 PC: B6BC	 SP: FF23	 BC: FE08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 54	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37936.	 OP: 0     	     NOP            	 PC: B6BE	 SP: FF23	 BC: FE08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 56	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37937.	 OP: 0     	     NOP            	 PC: B6BF	 SP: FF23	 BC: FE08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 57	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37938.	 OP: 0     	     NOP            	 PC: B6C0	 SP: FF25	 BC: FE08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 58	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37939.	 OP: 0     	     NOP            	 PC: B6B4	 SP: FF25	 BC: FD08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 59	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37940.	 OP: 0     	     NOP            	 PC: B6B5	 SP: FF23	 BC: FD08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 5A	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37941.	 OP: 0     	     NOP            	 PC: B6B8	 SP: FF23	 BC: FD08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 5B	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37942.	 OP: 0     	     NOP            	 PC: B6BA	 SP: FF23	 BC: FD08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 5D	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37943.	 OP: 0     	     NOP            	 PC: B6BC	 SP: FF23	 BC: FD08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 5F	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
ROM write attempted at: 0x0   , data: 0xf9  
37944.	 OP: 0     	     NOP            	 PC: B6BE	 SP: FF23	 BC: FD08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 61	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37945.	 OP: 0     	     NOP            	 PC: B6BF	 SP: FF23	 BC: FD08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 62	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37946.	 OP: 0     	     NOP            	 PC: B6C0	 SP: FF25	 BC: FD08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 63	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37947.	 OP: 0     	     NOP            	 PC: B6B4	 SP: FF25	 BC: FC08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 64	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37948.	 OP: 0     	     NOP            	 PC: B6B5	 SP: FF23	 BC: FC08	 DE: 0101	 HL: 0101	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 65	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758
37949.	 OP: 0     	     NOP            	 PC: B6B8	 SP: FF23	 BC: FC08	 DE: 0101	 HL: 0000	 IX: 013C	 IY: 5C3A	 AF: 0885	  R: 66	  F: 10000101.	AF': 0044	BC': 0000	DE': 369B	HL': 2758

...
COUNTER CONTINUED
...

On the other hand, it does seem to be a somehow "organized" loop, in the sense that it doesn't seem to be a random "code ran of the tracks" one.
I'm not yet sure what to make of this, to be honest :D. If anybody recognizes this kind of loop-pattern, let us know :)
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

I'm not yet sure if there is something else, but for starters, there is definitely something wrong on my side with my "debugger".
Even though the emulator executes that loop, at some point, somewhere, somehow the debugger fails to record the proper instruction being executed and it records NOPs instead.

After a quick search, I downloaded InkSpector, which seems to have some great debugging capabilities, and did a side-by-side walk-through of the loop execution. At a quick glance, except for the memory refresh register R and the undocumented flags which are not handled by my code, all other values seem to be in sync. I'll have to take a closer, more detailed look at this.

But first, I really need to implement a way better debugger if I am to move forward with this project :)

This is fun :D
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

Back with some updates on this. Maybe it will be useful to somebody in the future :)

I'm still not sure what exactly the previously presented 8bitTris routine does, other than apparently acting as some sort of counter.
However, using the debugger, I managed to understand what causes the ROM write attempt in this case.

As you can see below, in the disassembly of the routine, at 0xB6B5 the HL register pair is being loaded with 0x0000.
This is followed by a SRA (HL) instruction. This instructions will attempt to do a SRA on the value stored at the memory address pointed to by (HL)
and store back the result to the same address.

However, (HL) now points to address 0x0000, which in this case is located in ROM and contains the value 0xF3 (the DI instruction).
When SRA (HL) tries to store back the result of the operation, which is 0xF9 in this case, it will in effect attempt to write the 0xF9 value to address 0x0000 in the ROM memory.

Code: Select all

; Disassembly of the file "Memory"
; 
; CPU Type: Z80
; 
; Created with dZ80 2.01
; 
b69a cp      $08
b69c dec     l
b69d jp      z,$b68e

b6a0 out     ($fe),a
b6a2 nop     
b6a3 nop     
b6a4 djnz    $b67e

b6a6 inc     c
b6a7 jp      nz,$b680

b6aa ret     

b6ab ld      a,($b6c9)
b6ae cpl     
b6af ld      c,a
b6b0 push    bc
b6b1 push    af
b6b2 ld      b,$00
b6b4 push    hl
b6b5 ld      hl,$0000
b6b8 sra     (hl)
b6ba sra     (hl)
b6bc sra     (hl)
b6be nop     
b6bf pop     hl
b6c0 djnz    $b6b4

b6c2 dec     c
b6c3 jp      nz,$b6b4

b6c6 pop     af
b6c7 pop     bc
b6c8 ret     

b6c9 rst     $30
b6ca nop     
b6cb inc     b
b6cc ret     nc


Apparently, ROM poking is also used by the "ROM calculator routine [...] to throw away a value", as mentioned by Philip Kendall in an older post on another forum. Nice :)

It turns out that there is nothing wrong with my "debugger" after all. Other than being very rudimental.
In one of those "duh moments" I realized that I just forgot to properly initialize it when I "hackishly" set up the break-point for generating the logs from the previous post :roll: .

With that in mind I decided to postpone the creation of a better debugger and instead move on to the next step and try to implement the sound emulation.
I must say, the first attempt was not a successful one. Even though I can clearly recognize the 8bitTris tune in the playback, the sound is very crackling and scratchy and just horrible.

I'll probably come back with some related questions in a new thread
User avatar
Turtle_Quality
Manic Miner
Posts: 508
Joined: Fri Dec 07, 2018 10:19 pm

Re: Game development trick? Or something else?

Post by Turtle_Quality »

Thanks for posting that, interesting.

When you said Mazeball suffered from the same issue, I was thinking "But it's just short bit of compiled basic, and the only POKE was to system variables"
But the compiler probably uses the ROM routines for calculations so that would make sense, well done for tracking that down.

I've often wondered how people manage to emulate 48K Spectrum sound accurately ... on a modern machine running 1000s of times faster but the emulator will be only one of hundreds of processes running with varying priority, it would seem to me getting each click to occur at exactly the right moment would be tougher for an emulator than emulating a soundchip or rendering graphics.
Definition of loop : see loop
scoppack
Dizzy
Posts: 65
Joined: Mon Jun 22, 2020 9:33 am

Re: Game development trick? Or something else?

Post by scoppack »

I was looking at that code and wondering WTF, I didn't recognise it at all!!
I tracked it down from the cpl command and it is from the Music Box Player Engine. It was a straight 'save as asm' from the program Beepola.
It may help, or not.
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

@scoppack
scoppack wrote: Wed Jul 06, 2022 8:35 pm I was looking at that code and wondering WTF, I didn't recognise it at all!!
I tracked it down from the cpl command and it is from the Music Box Player Engine. It was a straight 'save as asm' from the program Beepola.
It may help, or not.
Mystery solved :D.
Btw: that tune is very catchy. It got stuck in my head all day long :).

@Turtle_Quality
Turtle_Quality wrote: Wed Jul 06, 2022 7:42 pm I've often wondered how people manage to emulate 48K Spectrum sound accurately ... on a modern machine running 1000s of times faster but the emulator will be only one of hundreds of processes running with varying priority, it would seem to me getting each click to occur at exactly the right moment would be tougher for an emulator than emulating a soundchip or rendering graphics.
I too am wondering that right now, to be honest :lol:. I couldn't find much info about it. It seems to be a well guarded secret :P.

So far, I find this part to be the most difficult one to implement, but that's probably just because my knowledge about sound generation and processing is pretty limited. I need to read up on this and do some more research.

More or less, here is what I did in my first attempt: aiming for an overall 44.1 kHz sample rate, I took a reading of the EAR bit value after every 79 T-States (3.5Mhz / 44.1kHz) and push that into a buffer. After 69888 T-States are executed (after each screen frame / 20 ms) I fed that buffer to the system's audio routine which runs in another thread and produces the sound based on the data from the buffer.
And repeat.

I also tried using two buffers: while one is being played the other one is being filled with data and then they are alternatively fed to the "audio thread".
At a quick glance the results seemed to be the same on my system.

In all my attempts so far I could clearly recognize the tune playing in the background (for example the tune from 8bitTris or Arkanoid), but overall the sound was extremely crackling and scratchy and far, far, far from a faithful reproduction of the original sound.

When it comes to sound emulation, I'm pretty much walking in the dark :).
User avatar
Pegaz
Dynamite Dan
Posts: 1210
Joined: Mon Nov 13, 2017 1:44 pm

Re: Game development trick? Or something else?

Post by Pegaz »

@the.beginner

Really like this thread. :)
Please keep us updated with your emulator development.
I can't help with sound emulation, but I can tell you that almost all authors of the most accurate Spectrum emulators are members of this forum.
They may not all be active right now, but if you're looking for advice, this is probably the best place to find it.
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

Pegaz wrote: Fri Jul 08, 2022 8:18 am @the.beginner

Really like this thread. :)
Please keep us updated with your emulator development.
I can't help with sound emulation, but I can tell you that almost all authors of the most accurate Spectrum emulators are members of this forum.
They may not all be active right now, but if you're looking for advice, this is probably the best place to find it.
@Pegaz

Thanks! I'm glad to hear that :).

It is an extremely fun project to work on.
Unfortunately, the fact that it was created on the fly, without much thought and planning put into it from the beginning, is starting to show it's limitations. It was something more on the lines of : "let's see what if ..." :). But I did learned a lot by doing it, even if it is just a very basic emulation.

To be honest, on one hand, when I see how many amazing and proper emulators are around here, I am a bit embarrassed to even call mine an emulator.
But, on the other hand, I am pretty excited and kind of proud to be able to play my childhood games on it :D.

Currently, the final goal of the project is to have, as much as possible, a clear-ish sound, even if it is not a totally faithful reproduction of the original, but just enough to be able to play a game without causing my neighbor's dogs to start barking :lol: (just a figure of speech! :P ).

In the future, if time permits, I hope there will be a newer, more proper version.
I'll definitely keep you updated! :)
TheMartian
Microbot
Posts: 107
Joined: Wed Feb 03, 2021 5:18 am

Re: Game development trick? Or something else?

Post by TheMartian »

Hi!
the.beginner wrote: Thu Jul 07, 2022 9:03 pm More or less, here is what I did in my first attempt: aiming for an overall 44.1 kHz sample rate, I took a reading of the EAR bit value after every 79 T-States (3.5Mhz / 44.1kHz) and push that into a buffer. After 69888 T-States are executed (after each screen frame / 20 ms) I fed that buffer to the system's audio routine which runs in another thread and produces the sound based on the data from the buffer.
And repeat.

I also tried using two buffers: while one is being played the other one is being filled with data and then they are alternatively fed to the "audio thread".
At a quick glance the results seemed to be the same on my system.

In all my attempts so far I could clearly recognize the tune playing in the background (for example the tune from 8bitTris or Arkanoid), but overall the sound was extremely crackling and scratchy and far, far, far from a faithful reproduction of the original sound.

When it comes to sound emulation, I'm pretty much walking in the dark :).
That's pretty much what I am doing on SpecIde. With some differences:
- Instead of just getting a sample each 79 T-States, I collect one sample per cycle in a buffer.
- When it's the time for a sample at 44.1KHz, I average the samples I've collected. This implements a low-pass moving average filter, which removes the high frequency noise in the beeper. This really helps with the Arkanoid tune, for instance, as 44.1KHz looks too low a sampling frequency for what the Speccy is doing.
I also adjust the number of samples, because 7000000/44100 is not an integer. If I round up, I end up getting too many samples and there's a buffer overrun. If I round down, eventually I run out of samples and there's a click. Also this method allows me to adjust the sound rate for different Speccy models.

I don't quite know if there are better methods, I figured things out just by trial and error and by refreshing some signal theory from uni (but I've definitely forgotten most of it).

If you want, have a look at my code. You should look at the ULA.cc file, void ULA::sample() function, and also Spectrum.cc, Spectrum::run() for the counting of samples. (You can find my project at https://github.com/MartianGirl/SpecIde - I hope it's tidy and clear enough)

Cheers!
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

Hi @TheMartian,

This is exactly what I was looking for. Thank you! Your information is priceless!

If only I would have seen it sooner. It would have saved me long hours of browsing through very old forum posts :D.
I realize now just how important timing is :P.

Here's what happened:
Yesterday I told myself: "this is it! now or never" :D .
So, like a good Friday night activity, I started browsing through old forum post for clues.
After coming up empty handed here, I moved over to the WOS forum. Unfortunately their search function was down (Query failed: connection to localhost:9312 failed (errno=111, msg=Connection refused). ), so I started manually going through most of the posts from their Emulators section.
I even came across one of your old posts and I took a quick look at your code too :)

And then, finally, after a couple of hours, this post showed up: Audio Output Filtering in Emulators . When I saw the title, everything clicked :D

However, I find your post to be spot on and much clearer! :)

Cheers!
TheMartian
Microbot
Posts: 107
Joined: Wed Feb 03, 2021 5:18 am

Re: Game development trick? Or something else?

Post by TheMartian »

Hi!

I'm glad it was helpful.

Sound is tricky. You can't predict it, especially when it is generated by the CPU, so you must generate it just on time. Also, it is *very* sensitive to timing and jitter and dropped samples and so on.

In SpecIde, as I say, I'm adjusting the number of "skipped" samples all the time, and this number depends on the emulated model.
Then I had problems with the AY emulation, because it sounded detuned. Hint: If you implement hardware counters, make them count *up*. This way, when the count limit register is changed, the period change happens instantly. If you count down, the change doesn't happen until you reach zero and reload. And you can hear this.
Also, the host machine delays. I've tried different ways of implementing the frame delay. You can't just say "wait until 20ms from here" because the host CPU can be awakened a bit later than expected, and you get a click for this. I've solved this by waking up a bit early, and then making up for the extra time in an idle loop.
If you have a nice 50Hz refresh rate on your PC monitor, you can maybe sync to it, and then the delay is perfect and costs nothing, but you have to adjust a bit your timings because 50Hz is a bit slower than the refresh rate in British Speccies, and a bit faster than the Pentagon. This detunes a bit the music, but I guess you need pitch perfect hearing to notice it! Also, this works nicely on the Speccy, but on other systems that can change the refresh rate (anything with a CRTC, like the BBC or CPC) gives the feeling of the sound speed changing if such a video mode change happens.

As I said earlier, feel free to look at my code. You can get ideas from there. It's not the best code, but I tried to make it clear and tidy, so SpecIde is a bit of a "Speccy documentation" project.

:)
beginner
Drutt
Posts: 37
Joined: Sat May 21, 2022 10:23 pm

Re: Game development trick? Or something else?

Post by beginner »

This is all great info! Thanks for sharing! :)

Maybe we could have a sticky page in the Emulators section, where more experienced emulator developers could share info with newbies like myself.
Stuff like: tips and tricks, common pitfalls, different approaches, etc :).
Post Reply