Pseudorandom generation

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Gigasoft
Very interested
Posts: 95
Joined: Fri Jan 01, 2010 2:24 am

Post by Gigasoft » Mon Apr 09, 2012 8:09 am

Which would amount to adding a random offset to H and V counters. Thanks! It indeed fixed the problem. I've patched Gens/GS accordingly. I'm surprised this hasn't been fixed so far.
No, now you've just broken it even more.

fdarkangel
Interested
Posts: 24
Joined: Sun Dec 17, 2006 8:28 pm
Location: Osaka, Japan

Post by fdarkangel » Mon Apr 09, 2012 9:17 am

Gigasoft wrote:
Which would amount to adding a random offset to H and V counters. Thanks! It indeed fixed the problem. I've patched Gens/GS accordingly. I'm surprised this hasn't been fixed so far.
No, now you've just broken it even more.
Can you be a little bit more specific? What problems are you having?

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Apr 09, 2012 9:20 am

Indeed, you cannot just add a random offset to H and V counter...
You actually really need to start randomly in the frame and this is not that easy to emulate...
I am not sure that Kega Fusion does implement that feature, Hard Reset in Eternal Champion always give the same intro so i do not think that is the case.

fdarkangel
Interested
Posts: 24
Joined: Sun Dec 17, 2006 8:28 pm
Location: Osaka, Japan

Post by fdarkangel » Mon Apr 09, 2012 10:15 am

Stef wrote:Indeed, you cannot just add a random offset to H and V counter...
You actually really need to start randomly in the frame and this is not that easy to emulate...
I am not sure that Kega Fusion does implement that feature, Hard Reset in Eternal Champion always give the same intro so i do not think that is the case.
Hmmm, does this mean there is a piece of code that implicitly depends on the fact that H(0) == 0? Let me check when I have time.

Here's my reasoning: Gens/GS calculates the HV count by counting the cycles since the beginning of the frame. The odometer is reset at the beginning of each frame, which fixes the HCount at a particular cycle since the beginning of the frame. Thus HCount at a given time, H(t), is a linear function; C[Odometer(t % T)-Odometer(0)] + H(0) where C and H(0) are constants, and T is the time it takes to draw a frame. H(0) is fixed to 0 is the current upstream, and hopefully, no code in the emulators relies on this assumption (I haven't been thorough).
Randomizing H(0), the initial HCount at the startup, would amount to adding a time-independent offset to H(t).

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Apr 09, 2012 11:47 am

Of course some games rely on the absolute H or V counter value (and not only relative).
Actually you can test games with raster effects on your Gens GS build, you may experience problems.
You can test Mickey Mania for example, just let the demo run until the deer run... i guess it won't work correctly depending initialization on your build.

fdarkangel
Interested
Posts: 24
Joined: Sun Dec 17, 2006 8:28 pm
Location: Osaka, Japan

Post by fdarkangel » Mon Apr 09, 2012 3:54 pm

Stef wrote:Of course some games rely on the absolute H or V counter value (and not only relative).
Actually you can test games with raster effects on your Gens GS build, you may experience problems.
You can test Mickey Mania for example, just let the demo run until the deer run... i guess it won't work correctly depending initialization on your build.
Then we can't say that Kega Fusion simply randomizes initial HV count.
I tried Mickey Mania but haven't seen any problems. However the title screen of Thunder Force III is glitchy. Let me see if there's a way to "gauge away" that random offset later on.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Apr 09, 2012 5:07 pm

As i said you actually need to start from random part in the frame as the real hardware does and not fake it by adding random offset the HV counter.
You can actually emulate it by using random cycle number at starting instead of 0 and also choosing random current scanline number but it's easier to say than implement :)

slobu
Very interested
Posts: 85
Joined: Tue Apr 03, 2012 6:02 pm

Post by slobu » Mon Apr 09, 2012 6:18 pm

Wouldn't setting a counter that stops incrementing at the first user input work as a seed for both emulators and real hardware? The most random thing involved is the player, methinks.

djcouchycouch
Very interested
Posts: 710
Joined: Sat Feb 18, 2012 2:44 am

Post by djcouchycouch » Mon Apr 09, 2012 6:53 pm

slobu wrote:Wouldn't setting a counter that stops incrementing at the first user input work as a seed for both emulators and real hardware? The most random thing involved is the player, methinks.
Unless that player is a robot. You never know.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Apr 09, 2012 8:46 pm

djcouchycouch wrote:
slobu wrote:Wouldn't setting a counter that stops incrementing at the first user input work as a seed for both emulators and real hardware? The most random thing involved is the player, methinks.
Unless that player is a robot. You never know.
For real hardware HV counter at initialization time is actually really random as it exactly relies on user input (i.e. when user actually turned ON the system)... If emulator reproduces that "feature" then we could use HV counter for randomizer init. The problem is that you have to check for HV counter at reset time, as soon you call a routine waiting for V blank then you lost the random input...

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Mon Apr 09, 2012 10:48 pm

As far as an emulator goes, perhaps the best way to handle this is to hold the cpu in reset while allowing the rest of the emulated system to run; hold the processor under reset for a number of cycles related to the current system time - unless you start the emulator at the same time every day, it should then be sufficiently random when the cpu starts with respect to the vdp as to produce the desired behavior.

fdarkangel
Interested
Posts: 24
Joined: Sun Dec 17, 2006 8:28 pm
Location: Osaka, Japan

Post by fdarkangel » Tue Apr 10, 2012 12:48 am

Stef wrote:As i said you actually need to start from random part in the frame as the real hardware does and not fake it by adding random offset the HV counter.
You can actually emulate it by using random cycle number at starting instead of 0 and also choosing random current scanline number but it's easier to say than implement :)
What you suggest is basically adding a time-shift such that V(t) = D [Odometer([t-t0]%T) - Odometer(0)], which is what I wanted to do in the first place. And it is doable for VCount. But can you think of randomizing HCount without being too intrusive in T_gens_do_MD_frame?
I wanted to avoid playing around with the frame-loop for such a "trivial"-fix (which don't really affect the game), I sorted to an alternative fix. And it is supposed to work, unless there is a piece of code in the emulator that assumes H(0) == 0 and V(0) == 0.

And it looks like there is:

Code: Select all

for (hc = 0; hc < 512; hc++)
{
	hc_val = ((hc * 170) / 488) - 0x18;
	H_Counter_Table[hc][0] = (unsigned char)hc_val;
	
	hc_val = ((hc * 205) / 488) - 0x1C;
	H_Counter_Table[hc][1] = (unsigned char)hc_val;
}

Code: Select all

; uint8_t Read_VDP_H_Counter(void)
global SYM(Read_VDP_H_Counter)
SYM(Read_VDP_H_Counter):
	
	push ebx
	
	call	SYM(main68k_readOdometer)
	mov	ebx, [SYM(Cycles_M68K)]
	sub	ebx, [SYM(CPL_M68K)]
	sub	eax, ebx			; Nb cycles effectués sur cette ligne.
	xor	ebx, ebx
	and	eax, 0x1FF
	test	byte [SYM(VDP_Reg.Set_4)], 0x81	; 40 cell mode ?
	setnz	bl
	mov	al, [SYM(H_Counter_Table) + eax * 2 + ebx]
	xor	ah, ah
	add	al, byte [SYM(H_Counter_Zero)]
	
	pop ebx
	ret

Code: Select all

; uint8_t Read_VDP_V_Counter(void)
global SYM(Read_VDP_V_Counter)
SYM(Read_VDP_V_Counter):
	
	push ebx
	
	call	SYM(main68k_readOdometer)
	mov	ebx, [SYM(Cycles_M68K)]
	sub	ebx, [SYM(CPL_M68K)]
	sub	eax, ebx			; Nb cycles effectués sur cette ligne.
	xor	ebx, ebx
	and	eax, 0x1FF
	test	byte [SYM(VDP_Reg.Set_4)], 0x81	; 40 cell mode ?
	jz	short .mode_32
	
.mode_40:
	mov	al, [SYM(H_Counter_Table) + eax * 2 + 1]
	mov	bl, 0xA4
	jmp	short .ok
	
align 16
	
	.mode_32:
	mov	al, [SYM(H_Counter_Table) + eax * 2 + 0]
	mov	bl, 0x84
	
	.ok:
	cmp	al, 0xE0
	setbe	bh
	cmp	al, bl
	setae	bl
	and	bl, bh
	
	test	byte [SYM(VDP_Status)], 1		; PAL ?
	jnz	short .PAL
	
.NTSC:
	mov	eax, [SYM(VDP_Current_Line)]
	shr	bl, 1
	adc	eax, 0
	cmp	eax, 0xEB
	jb	short .No_Over_Line_XX
	
	sub	eax, 6
	jmp	short .No_Over_Line_XX
	
.PAL:
	mov	eax, [SYM(VDP_Current_Line)]
	shr	bl, 1
	adc	eax, byte 0
	cmp	eax, 0x103
	jb	short .No_Over_Line_XX

	sub	eax, byte 56

.No_Over_Line_XX:
	test	byte [SYM(VDP_Reg.Set_4)], 2
	jz	short .No_Interlace
	
	rol	al, 1
	
.No_Interlace:
	xor	ah, ah
	pop	ebx
	add	al, byte [SYM(V_Counter_Zero)]
	ret

Gigasoft
Very interested
Posts: 95
Joined: Fri Jan 01, 2010 2:24 am

Post by Gigasoft » Tue Apr 10, 2012 2:43 pm

Try not to make the H and V counters behave in an unexpected way. The H and V counters need to be synchronized with each other and with H and V interrupts, and with screen drawing. If you need to be intrusive, then that's what you need to be.

And don't forget about movies - they must contain all information that is needed to play back correctly every time, so you'll need to store the initial H and V count, and preferably allow the user to specify them manually when recording a new movie.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Tue Apr 10, 2012 8:16 pm

Yeah some part of the code rely on the H(0) == 0 and V(0) == 0 stuff..
But a simple way of randomizing the initial Cycles_M68K value.
Cycles_M68K contains the number of executed cycles on current scanline, it varies between 0 and 488. Just start with a random current_scanline value and a random Cycles_M68K and that's done.
You could use a specific frame emulation code for the first frame only where current_scanline and Cycles_M68K are initialized with random value instead of 0, then you do the rest of the frame...

Post Reply