HBlank Timings
Moderators: BigEvilCorporation, Mask of Destiny
Snake -> That's exactely what i've done.
Each components are in their own class.
I have a class Genesis wich contains a class for 68k, a class for Z80, VDP, PSG ...
The class Genesis doesn't car how each component work.
Each component are implemented an class interface called "Component".
The only thing a component call do is executing events.
Each components are communicating with his controller, and can ask to him to add event.
So for the VDP we have the class VDP and the Class VDPController.
The Genesis implements all the controller VDPController, PSGController, 68KController ....
At start of each frame, The VDP ask his controller (Class Genesis) to add an event in 3416 cycles (Vdp Clock) called VDP_EVENT_HBLANK. The class Genesis convert the number of cycle into system cycle (also 3416 because clock not divided) and add to his queue.
When processor have executed 3416 system cycles, the class Genesis take the event and send it to the owner component (VDP in that case).
My main loop is unique
So the only thing the Genesis do is take event, send to the component at the good moment and executing processors.
With this solution the code is very clear and we can have very good timings (instruction by instruction).
My emulator isn't as fast as other but code is easy to read and with a solid object model.
All the data are typped in a header and all memory access (READ_WORD, READ_BYTE ...) too.
All Genesis emulation is in a kernel wich is system independant.
All you have to do to use the kernel in a system is redefine some macros in the system.h header file and that's all you can use class Genesis in your software.
that's was for presentation of my work.
PS : Sorry for my bad english
Each components are in their own class.
I have a class Genesis wich contains a class for 68k, a class for Z80, VDP, PSG ...
The class Genesis doesn't car how each component work.
Each component are implemented an class interface called "Component".
The only thing a component call do is executing events.
Each components are communicating with his controller, and can ask to him to add event.
So for the VDP we have the class VDP and the Class VDPController.
The Genesis implements all the controller VDPController, PSGController, 68KController ....
At start of each frame, The VDP ask his controller (Class Genesis) to add an event in 3416 cycles (Vdp Clock) called VDP_EVENT_HBLANK. The class Genesis convert the number of cycle into system cycle (also 3416 because clock not divided) and add to his queue.
When processor have executed 3416 system cycles, the class Genesis take the event and send it to the owner component (VDP in that case).
My main loop is unique
So the only thing the Genesis do is take event, send to the component at the good moment and executing processors.
With this solution the code is very clear and we can have very good timings (instruction by instruction).
My emulator isn't as fast as other but code is easy to read and with a solid object model.
All the data are typped in a header and all memory access (READ_WORD, READ_BYTE ...) too.
All Genesis emulation is in a kernel wich is system independant.
All you have to do to use the kernel in a system is redefine some macros in the system.h header file and that's all you can use class Genesis in your software.
that's was for presentation of my work.
PS : Sorry for my bad english
So, if i understand, the VDP trigger Hint at the same time that HBlank start but the processor need 44 cycles to start processing?Eke wrote:no, I made Hblank, Vcounter jump and Hint starts at the same time, even if it's probably not *exactly* what happen on the real thing but it's easier and does not seem to break anythingDo delay between Hint and Hblank start is also 36 cycles?
more precisely, there is two things to handle with HBLANK: the HBLANK flag which is polled by some games and some register writes during HBLANK period which can affect the current line (which has already been drawn by the emulator)
correct, Hcounter table starts at 0x85 in H32 mode and 0xA5 in H40 modeDoes your HCounter table in genesis plus start at Hint?
again, not sure if this is completely accurate but it works
it's because Hint processing takes some time (at least 44 cycles to start the processing) so the cycles executed during Hint routine should be executed AFTER the line rendering, because at that time, the VDP has already latched those values and the CRAM/VSRAM/whatever changes will only occur on the next lineIn the emulator i actually write, if i execute 36 cycles of 68k between Hint and Line rendering, I have glitch (Lotus -> write values to CRAM in start of H-Int function and landstalker -> one line is clipping)
at least, this is what happen with Lotus games, not sure about Landtstalker, I never had any problems with this one, I just know that it requires proper DMA operation somewhere
so, I do NOT execute 36 cycles between Hint triggering and line rendering but instead, I ADJUST the events timing regarding of Hint occurences, do you see the difference ?
So :
- The line rendering (ideally) is made at HBlankStart +36 cycles
- The first instruction of HInt processus is made at HBlankStart + 44 cycles, when the line has already been rendered?
Does a 68k processor already need 44 cycles (44*7 = 308 system cycles) to start an interrupt processus or the reason is something else?
yes, it's exactly what I didSo, if i understand, the VDP trigger Hint at the same time that HBlank start but the processor need 44 cycles to start processing?
So :
- The line rendering (ideally) is made at HBlankStart +36 cycles
- The first instruction of HInt processus is made at HBlankStart + 44 cycles, when the line has already been rendered?
but as I said, I can not say for sure this is perfectly correct
this is more probably something like:
HSYNC<-->start of Hblank <-->VDP fetches infos for the line <-->HINT start processing-->VDP starts rendering the line (end of HBLANK)
with some unknown delays between those events
you have to take border (left & right) periods in consideration also
maybe one of our two former genesis programmer here could tell us what timings they were told to use to do fast display modifications during HBLANK
it's specified like that in the 68k programmer manual, I guess it includes the time necessary to update 68k registers, fetch the interrupt vector address, update the PC, jump to new PC, etc... all 68k internal operations are tied to the clock.Does a 68k processor already need 44 cycles (44*7 = 308 system cycles) to start an interrupt processus or the reason is something else?
Yes, VDP render line at end of HBLank but in my emulator I must execute my rendering function at HBlankStart + 36 cycles (ideally)?
So I will have that config :
HBlankStart : Trigger HInt
HBlankStart + 36 cycles : render line
Between this event, i can execute 36 cycles of 68k.
IF first instruction of interrupt processus is executed during this 36 cycles, this is a 68k core bug that i must correct because between the moment the H-Int is take by 68k core and the moment of the first interrupt instruction, there must be this delay ...
Then
HBlankStart + 44 cycles : 68 execute first interrupt opcode
In that way I would have no gltch in Lotus for example.
Do you understand?
So I will have that config :
HBlankStart : Trigger HInt
HBlankStart + 36 cycles : render line
Between this event, i can execute 36 cycles of 68k.
IF first instruction of interrupt processus is executed during this 36 cycles, this is a 68k core bug that i must correct because between the moment the H-Int is take by 68k core and the moment of the first interrupt instruction, there must be this delay ...
Then
HBlankStart + 44 cycles : 68 execute first interrupt opcode
In that way I would have no gltch in Lotus for example.
Do you understand?
The first tests i made are ok.
I have a glitch on road rash (the first line at the top of the road).
I searched on the forum and the reason is that border is modified during the line, wich take effect immediately.
the VDP fetch datas on start of the line but I notice 2 access wich take effect on the current line :
- Display ON/OFF
- Border color modify (needs to remap colors but not redraw line !!!)
Are there other access in that case?
If the display is turned off during active scan, the start off the line is drawn and the end is blanking?
I have a glitch on road rash (the first line at the top of the road).
I searched on the forum and the reason is that border is modified during the line, wich take effect immediately.
the VDP fetch datas on start of the line but I notice 2 access wich take effect on the current line :
- Display ON/OFF
- Border color modify (needs to remap colors but not redraw line !!!)
Are there other access in that case?
If the display is turned off during active scan, the start off the line is drawn and the end is blanking?
some improved event system and better way to handle interrupt latency, I realised that I've already quite modified the original musashi core interface so there is no reason not to continueWhat kind of idea my approach gave you?
not sure about that, but it's possible (see how Kega emulates Sonic 2 vs-mode, especially the end of the separation bar... the display is sometime enabled later in the line... I do not remember the original game doing this however, only some white CRAM dots on the last line)Are there other access in that case?
If the display is turned off during active scan, the start off the line is drawn and the end is blanking?
in genesis plus, I made this possible only during hblank period (including borders)
again, this would require real testing
-
- Very interested
- Posts: 2440
- Joined: Tue Dec 05, 2006 1:37 pm
- Location: Estonia, Rapla City
- Contact:
There's quite a bit of flicker on real HW, but on last line of the separation bar. I don't recall flickering on 1st line... I need to pay more attention.
Mida sa loed ? Nagunii aru ei saa
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen
on my PAL mega drive 2, I didn't get any blue bar flickering as far as I remember (I used this game quite intensively for aspect ratio comparison with the emulator); only some white dots flickeringmickagame wrote:I notice that in Kega the start of the first line sepration bar is flickering.
Does it happen on real hardware? What's the reason? Display Off some cycle after active line?
what the game does is shutoff the display for a few lines to increase DMA capacity. The CPU is frozen during DMA so the display will be reenabled once it is finish, this is how you get this blue separation bar.
I think that I remember the game was reading the HBLANK flag in the Hint routine to wait before re-enabling display after DMA is finish.
same goes for the start of the DMA which is triggered once the game has disabled the display, on the required line
all of this was handled (display OFF -> DMA -> display ON) is handled in the Hint routine
So this game requires very accurate DMA and Hint/Hblank timings to be displayed exactly like real hardware but, theorically, the DMA operation should be constant in time and the display enabled/disabled in constant intervals...
EDIT:
here's the disassembled Hint :
Code: Select all
loc_F6E: ; CODE XREF: HInt+24j
ROM:00000F6E move.w (VDP_Control).l,d0
ROM:00000F74 andi.w #4,d0
ROM:00000F78 beq.s loc_F6E
ROM:00000F7A move.w ($FFFFF60C).w,d0
ROM:00000F7E andi.b #$BF,d0
ROM:00000F82 move.w d0,(VDP_Control).l
ROM:00000F88 move.w #$8228,(VDP_Control).l
ROM:00000F90 move.l #$40000010,(VDP_Control).l
ROM:00000F9A move.l ($FFFFEEEC).w,(VDP_Data).l
ROM:00000FA2 move.w #$100,(Z80BusReq).l ; D8 ( W) 0: BUSREQ CANCEL
ROM:00000FA2 ; 1: BUSREQ REQUEST
ROM:00000FA2 ; ( R) 0: CPU FUNCTION STOP ACCESSIBLE
ROM:00000FA2 ; 1: FUNCTIONING
ROM:00000FAA
ROM:00000FAA loc_FAA: ; CODE XREF: HInt+5Ej
ROM:00000FAA btst #0,(Z80BusReq).l ; D8 ( W) 0: BUSREQ CANCEL
ROM:00000FAA ; 1: BUSREQ REQUEST
ROM:00000FAA ; ( R) 0: CPU FUNCTION STOP ACCESSIBLE
ROM:00000FAA ; 1: FUNCTIONING
ROM:00000FB2 bne.s loc_FAA
ROM:00000FB4 lea (VDP_Control).l,a5
ROM:00000FBA move.l #$94019340,(a5)
ROM:00000FC0 move.l #$96EE9580,(a5)
ROM:00000FC6 move.w #$977F,(a5)
ROM:00000FCA move.w #$7800,(a5)
ROM:00000FCE move.w #$83,($FFFFF640).w ; 'â'
ROM:00000FD4 move.w ($FFFFF640).w,(a5)
ROM:00000FD8 move.w #0,(Z80BusReq).l ; D8 ( W) 0: BUSREQ CANCEL
ROM:00000FD8 ; 1: BUSREQ REQUEST
ROM:00000FD8 ; ( R) 0: CPU FUNCTION STOP ACCESSIBLE
ROM:00000FD8 ; 1: FUNCTIONING
ROM:00000FE0
ROM:00000FE0 loc_FE0: ; CODE XREF: HInt+96j
ROM:00000FE0 move.w (VDP_Control).l,d0
ROM:00000FE6 andi.w #4,d0
ROM:00000FEA beq.s loc_FE0
ROM:00000FEC move.w ($FFFFF60C).w,d0
ROM:00000FF0 ori.b #$40,d0 ; '@'
ROM:00000FF4 move.w d0,(VDP_Control).l
ROM:00000FFA move.l (sp)+,d0
ROM:00000FFC movea.l (sp)+,a5
ROM:00000FFE
ROM:00000FFE locret_FFE: ; CODE XREF: HInt+4j
ROM:00000FFE rte
then it programs and triggers a DMA operation
once CPU is released,it wait for the HBlank flag to be set then enable the display again