No, now you've just broken it even more.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.
Pseudorandom generation
Moderator: BigEvilCorporation
-
- Interested
- Posts: 24
- Joined: Sun Dec 17, 2006 8:28 pm
- Location: Osaka, Japan
Can you be a little bit more specific? What problems are you having?Gigasoft wrote:No, now you've just broken it even more.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.
-
- Very interested
- Posts: 3131
- Joined: Thu Nov 30, 2006 9:46 pm
- Location: France - Sevres
- Contact:
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.
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.
-
- Interested
- Posts: 24
- Joined: Sun Dec 17, 2006 8:28 pm
- Location: Osaka, Japan
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.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.
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).
-
- Very interested
- Posts: 3131
- Joined: Thu Nov 30, 2006 9:46 pm
- Location: France - Sevres
- Contact:
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.
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.
-
- Interested
- Posts: 24
- Joined: Sun Dec 17, 2006 8:28 pm
- Location: Osaka, Japan
Then we can't say that Kega Fusion simply randomizes initial HV count.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.
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.
-
- Very interested
- Posts: 3131
- Joined: Thu Nov 30, 2006 9:46 pm
- Location: France - Sevres
- Contact:
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
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
-
- Very interested
- Posts: 710
- Joined: Sat Feb 18, 2012 2:44 am
-
- Very interested
- Posts: 3131
- Joined: Thu Nov 30, 2006 9:46 pm
- Location: France - Sevres
- Contact:
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...djcouchycouch wrote:Unless that player is a robot. You never know.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.
-
- Very interested
- Posts: 2984
- Joined: Fri Aug 17, 2007 9:33 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.
-
- Interested
- Posts: 24
- Joined: Sun Dec 17, 2006 8:28 pm
- Location: Osaka, Japan
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?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
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
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.
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.
-
- Very interested
- Posts: 3131
- Joined: Thu Nov 30, 2006 9:46 pm
- Location: France - Sevres
- Contact:
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...
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...